欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity for IOS 加载手机相册图片以及打开相机拍照获取图片

程序员文章站 2024-03-23 09:15:16
...

Unity for IOS 加载手机相册图片以及打开相机拍照获取图片

最近想做一个使用unity for IOS获取手机图片的功能,所以就研究了一下

这里我们需要创建两个objective-c文件,最终这两个文件需要放在unity项目中的路径为:Assets\Plugins\IOS
Unity for IOS 加载手机相册图片以及打开相机拍照获取图片

一. 首先创建objective-c文件:IOSCameraController.h

//import 引用头文件 相当于Using
#import<QuartzCore/CADisplayLink.h>
//声明一个IOSCameraController类  继承自UIViewController <>里面是是协议/代理的调用声明 可以理解为c#的接口
@interface IOSCameraController : UIViewController<UIImagePickerControllerDelegate,UINavigationControllerDelegate>
@end

二. 再来创建一个objective-c文件:IOSCameraController.m

这个文件用来调用IOS设备打开相机和相册,并获取图片。这里提供接口,供unity使用。unity只需要调用接口就行。
保存之后通知unity 执行对应的回调

//UnitySendMessage 是用来给unity发消息的 有三个参数 1.挂载对应回调脚本的物体名 2.回调函数的名称 3.对应回调上的参数
UnitySendMessage(“Manager”, “Message”, “Temp.jpg”);

#import "IOSCameraController.h"
 
@implementation IOSCameraController
-(void)OpenTarget:(UIImagePickerControllerSourceType)type{
    //创建UIImagePickerController实例
    UIImagePickerController *picker;
    picker= [[UIImagePickerController alloc]init];
    //设置代理
    picker.delegate = self;
    //是否允许编辑 (默认为NO)
    picker.allowsEditing = YES;
    //设置照片的来源
    // UIImagePickerControllerSourceTypePhotoLibrary,      // 来自图库
    // UIImagePickerControllerSourceTypeCamera,            // 来自相机
    // UIImagePickerControllerSourceTypeSavedPhotosAlbum   // 来自相册
    picker.sourceType = type;
    
    //这里需要判断设备是iphone还是ipad  如果使用的是iphone并没有问题 但是如果 是在ipad上调用相册获取图片 会出现没有确定(选择)的按钮 所以这里判断
    //了一下设备,针对ipad 使用另一种方法 但是这种方法是弹出一个界面 并不是覆盖整个界面 需要改进 试过另一种方式 重写一个相册界面
    //(QQ的ipad选择头像的界面 就使用了这种方式 但是这里我们先不讲 (因为我也不太懂 但是我按照简书的一位老哥的文章写出来了 这里放一下这个简书的链接
    //https://www.tlbyxzcx.com)
    if (picker.sourceType == UIImagePickerControllerSourceTypePhotoLibrary &&[[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
        // 设置弹出的控制器的显示样式
        picker.modalPresentationStyle = UIModalPresentationPopover;
        //获取这个弹出控制器
        UIPopoverPresentationController *popover = picker.popoverPresentationController;
        //设置代理
        popover.delegate = self;
        //下面两个属性设置弹出位置
        popover.sourceRect = CGRectMake(0, 0, 0, 0);
        popover.sourceView = self.view;
        //设置箭头的位置
        popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
        //展示选取照片控制器
        [self presentViewController:picker animated:YES completion:nil];
    } else {
        //展示选取照片控制器
        [self presentViewController:picker animated:YES completion:^{}];
    }
   
}
//选择完成,点击界面中的某个图片或者选择(Choose)按钮时触发
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
    //关闭界面
    [picker dismissViewControllerAnimated:YES completion:^{}];
    //得到照片
    UIImage *image = [info objectForKey:@"UIImagePickerControllerEditedImage"];
    if (image == nil) {
        image = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
    }
    //有些时候我们拍照后经常发现导出的照片方向会有问题,要么横着,要么颠倒着,需要旋转才适合观看。但是在ios设备上是正常的
    //所以在这里处理了图片  让他旋转成我们需要的
    if (image.imageOrientation != UIImageOrientationUp) {
    //图片旋转
        image = [self fixOrientation:image];
    }
    //获取保存图片的地址
    NSString *imagePath = [self GetSavePath:@"Temp.jpg"];
    //保存图片到沙盒路径 对应unity中的Application.persistentDataPath 之后我们取图片就需要在这个路径下取  这是一个可读可写的路径
    [self SaveFileToDoc:image path:imagePath];
}
//获取保存文件的路径 如果有返回路径 没有创建一个返回
-(NSString*)GetSavePath:(NSString *)filename{
    NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docPath = [pathArray objectAtIndex:0];
    return [docPath stringByAppendingPathComponent:filename];
}
//将图片保存到沙盒路径
-(void)SaveFileToDoc:(UIImage *)image path:(NSString *)path{
    NSData *data;
    if (UIImagePNGRepresentation(image)==nil) {
        data = UIImageJPEGRepresentation(image, 1);
    }else{
        data = UIImagePNGRepresentation(image);
    }
    [data writeToFile:path atomically:YES];
    //保存之后通知unity 执行对应的回调
    //UnitySendMessage 是用来给unity发消息的  有三个参数 1.挂载对应回调脚本的物体名 2.回调函数的名称 3.对应回调上的参数
    UnitySendMessage("Manager", "Message", "Temp.jpg");
}
#pragma mark 图片处理方法
//图片旋转处理
- (UIImage *)fixOrientation:(UIImage *)aImage {
    CGAffineTransform transform = CGAffineTransformIdentity;
    
    switch (aImage.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;
            
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
            
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        default:
            break;
    }
    
    switch (aImage.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
            
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        default:
            break;
    }
    
    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
                                             CGImageGetBitsPerComponent(aImage.CGImage), 0,
                                             CGImageGetColorSpace(aImage.CGImage),
                                             CGImageGetBitmapInfo(aImage.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (aImage.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            // Grr...
            CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
            break;
            
        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
            break;
    }
    // And now we just create a new UIImage from the drawing context
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    return img;
}
@end
//由于C++编译器需要支持函数的重载,会改变函数的名称,因此dll的导出函数通常是标准C定义的。
//这就使得C和C++的互相调用变得很常见。但是有时可能又会直接用C来调用,不想重新写代码,
//让标准C编写的dll函数定义在C和C++编译器下都能编译通过,通常会使用以下的格式:(这个格式在很多成熟的代码中很常见)
#if defined(__cplusplus)
extern "C" {
#endif
    //导出接口供unity使用
    void IOS_OpenCamera(){
        IOSCameraController *app = [[IOSCameraController alloc]init];
        UIViewController *vc = UnityGetGLViewController();
        [vc.view addSubview:app.view];
        [app OpenTarget:UIImagePickerControllerSourceTypeCamera];
    }
    void IOS_OpenAlbum(){
        IOSCameraController *app = [[IOSCameraController alloc]init];
        UIViewController *vc = UnityGetGLViewController();
        [vc.view addSubview:app.view];
        [app OpenTarget:UIImagePickerControllerSourceTypePhotoLibrary];
    }
#if defined(__cplusplus)
}
#endif

三. 下面我们来看看,再unity中,如何实现加载相册以及打开相机拍照获取图片

这里我就直接说代码方面,首先创建一个C#脚本,CameraAlbumController.cs 。代码如下

using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class CameraAlbumController : MonoBehaviour
{
    public Button openCamera;
    public Button openAlbum;
    public RawImage ico;

    [DllImport("__Internal")]
    private static extern void IOS_OpenCamera();
    [DllImport("__Internal")]
    private static extern void IOS_OpenAlbum();

    void Awake()
    {
        openCamera.onClick.AddListener(IOS_OpenCamera);
        openAlbum.onClick.AddListener(IOS_OpenAlbum);
    }
    //ios回调unity的函数
    void Message(string fileName)
    {
        //我们传进来的只是文件名字 这里合成路径,文件路径前面必须加file://
        string filePath = "file://"+Application.persistentDataPath + "/" + fileName;
        //开启一个协程加载图片
        StartCoroutine(HttpGetTexture(filePath));
    }
    IEnumerator HttpGetTexture(string url)
    {
        UnityWebRequest request = UnityWebRequestTexture.GetTexture(url);
            yield return request.SendWebRequest();
            Texture2D tex = new Texture2D(128, 128);
            tex.LoadImage(request.downloadHandler.data);
            ico.texture = tex;        
    }
}

这个脚本挂载到Manager物体上
Unity for IOS 加载手机相册图片以及打开相机拍照获取图片
界面展示效果
Unity for IOS 加载手机相册图片以及打开相机拍照获取图片

四. Xcode中需要开启相机以及访问相册的权限

IOS 相机等崩溃

This app has crashed because it attempted to access privacy- sensitive data without a usage description. The app’s Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.

意思是说:你需要在info.plist文件 添加一个 “NSContactsUsageDescription ”的Key,Value添加一个描述。

  • 需要在应用的info.plist里加入(使用source code模式):
  <key>NSCameraUsageDescription</key>
 <string>cameraDesciption</string>
 <key>NSContactsUsageDescription</key>
 <string>contactsDesciption</string>
 <key>NSMicrophoneUsageDescription</key>
 <string>microphoneDesciption</string>
 <key>NSPhotoLibraryUsageDescription</key>
 <string>photoLibraryDesciption</string>

五. 如果需要将加载出来的图片上传至服务器,请转移步至:

教程:将加载出来的图片上传至服务器

六. 完整项目下载地址

链接:下载完整项目:Unity for IOS 加载手机相册图片以及打开相机拍照获取图片

相关标签: Unity