Unity社交功能开发——图片上传

来源:互联网 发布:变形相机是什么软件 编辑:程序博客网 时间:2024/06/07 05:13

一、图片上传功能的意义

随着梦幻西游、大话西游、问道等回合制游戏的兴起,手游制作团队越来越重视社交功能的开发。笔者前一篇文章介绍了如何在Unity中加入语音聊天功能,本篇文章将介绍下一个社交功能——图片上传。
有了图片上传玩家就可以自定义头像、聊天发送图片甚至还可以在Unity中做一个『朋友圈』。

二、获取图片到Unity

Unity没有提供直接的Api打开移动端的相机、相册功能,所以需要调用Android/IOS的系统Api来打开移动端的相机和相册

1. Android获取相机、相册图片

主要功能实现参考雨松momo的文章Unity3D研究院之打开照相机与本地相册进行裁剪显示(三十三)

第一步,建立Unity项目对应的Android工程

如果不会可以查看雨松momo的文章Unity3D研究院之与Android相互传递消息(十九)

第二步,书写打开相机、相册代码by Android

    /**     * 打开相机 为什么要指定一个保存路径,是因为如果不指定onActivityResult只能从data参数中获取图片,可是获取到的是略缩图     */    public void TakePhotoChoose() {        int hasCameraPermission = checkCallingOrSelfPermission(Manifest.permission.CAMERA);        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");        File imageFile = new File(Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/"                + format.format(new Date()) + ".jpg");        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile));        PhotoPath = imageFile.getPath();        startActivityForResult(intent, PIC_TAKE_PHOTO);    }    /**     * 打开相册     */    public void TakePickChoose() {        Intent intent = new Intent(Intent.ACTION_PICK, null);        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_TYPE);        startActivityForResult(intent, PIC_TAKE_PICK);    }

第三步,获取到图片处理图片发送到Unity

    @Override    public void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if (resultCode == 0) {            // 取消接口            UnityPlayer.UnitySendMessage("GameMain", "CandleShowPhoto", "");            return;        }        if (requestCode == PIC_TAKE_PHOTO) {            // 获取到图片的资源使用bitmap压缩,并且转成base64的String直接将字符串发回去            Log.e("Unity", "GetPhotoPath");            UnityPlayer.UnitySendMessage("GameMain", "GetPath", PhotoPath);            Bitmap bm = PhotoUtil.getImageFromPath(PhotoPath, 40, 500, 750);            Bitmap bmSmall = PhotoUtil.getImageFromPath(PhotoPath, 40, 60, 80);            UnityPlayer.UnitySendMessage("GameMain", "ShowPhoto", PhotoUtil.getBitmapStrBase64(bm));            UnityPlayer.UnitySendMessage("GameMain", "SaveMiniPhoto", PhotoUtil.getBitmapStrBase64(bmSmall));        }        if (requestCode == PIC_TAKE_PICK) {            // 读取相册缩放图片            Bitmap bm = null;            ContentResolver resolver = getContentResolver();            Uri originalUri = data.getData();            Cursor cursor = getContentResolver().query(originalUri, null, null, null, null);            if (cursor != null && cursor.moveToFirst()) {                String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));                bm = PhotoUtil.getImageFromPath(path, 40, 500, 750);                Bitmap bmSmall = PhotoUtil.getImageFromPath(path, 40, 60, 80);                UnityPlayer.UnitySendMessage("GameMain", "ShowPhoto", PhotoUtil.getBitmapStrBase64(bm));                UnityPlayer.UnitySendMessage("GameMain", "SaveMiniPhoto", PhotoUtil.getBitmapStrBase64(bmSmall));            } else {                try {                    bm = MediaStore.Images.Media.getBitmap(resolver, originalUri);                } catch (IOException e) {                    e.printStackTrace();                }                if (bm != null) {                    Thread thread = new YaSuoPicThread(bm);                    thread.start();                }            }        }    }

在对图片处理过程中与鱼松momo有些不同,我没有将图片再次保存,而是将bitmap转成了string直接发送回了unity,省去了保存图片的时间,并且效果上看运行速度还是可以接受的。大家可以自己试试。

第四步,Unity显示图片

由于显示图片功能放在了Unity,Android和IOS是公用的所以下文IOS中不再重复

    /// <summary>    /// 从Android/IOS获取图片的base64串并显示图片    /// </summary>    /// <param name="base64">图片的base64串</param>    void ShowPhoto(string base64)    {        int targetHeight = 400;        int targetWidth = 600;        byte[] inputBytes = System.Convert.FromBase64String(base64);        base64 = "";        Texture2D text = BttetoPicByByte(inputBytes);        int curHeight = text.height;        int curWidth = text.width;        int newHeight = 0;        int newWidth = 0;        GetCutSize(targetHeight, targetWidth, curHeight, curWidth, ref newHeight, ref newWidth);        if (BigImage != null)        {            BigImage.gameObject.SetActive(true);            BigImage.rectTransform.sizeDelta = new Vector2(newWidth, newHeight);            BigImage.texture = text;            m_Stream = new MemoryStream(inputBytes);            inputBytes = null;        }        CloseDialogJuHua();    }    /// <summary>    /// 工具:将string转成图片    /// </summary>    /// <param name="base64"></param>    /// <returns></returns>    Texture2D BttetoPic(string base64)    {        Texture2D pic = new Texture2D(600, 400);        //将base64转码为byte[]          byte[] data = System.Convert.FromBase64String(base64);        //加载byte[]图片         pic.LoadImage(data);        return pic;    }    /// <summary>    /// 工具:将bytes转成图片    /// </summary>    /// <param name="bytes"></param>    /// <returns></returns>    Texture2D BttetoPicByByte(byte[] bytes)    {        Texture2D pic = new Texture2D(600, 400);        //加载byte[]图片         pic.LoadImage(bytes);        return pic;    }    /// <summary>    /// 工具:返回给定高宽内的图片高度和宽度 比如给定400*600 肯定返回一个400*600之内的照片    /// </summary>    /// <param name="targetHeight"></param>    /// <param name="targetWidth"></param>    /// <param name="curHeight"></param>    /// <param name="curWidth"></param>    /// <param name="newHeight"></param>    /// <param name="newWidth"></param>    public static void GetCutSize(int targetHeight, int targetWidth, int curHeight, int curWidth, ref int newHeight, ref int newWidth)    {        int TargetHeight = targetHeight;        int TargetWidth = targetWidth;        int width = curWidth;        int height = curHeight;        float bili = 1f;        if (width > TargetWidth)        {            bili = (float)TargetWidth / (float)width;        }        newHeight = (int)((float)height * bili);        if (newHeight > TargetHeight)        {            bili = (float)TargetHeight / (float)height;        }        newHeight = (int)((float)height * bili);        newWidth = (int)((float)width * bili);    }

2. IOS获取相机、相册图片

如果不会IOS与Unity交互的同学请戳这里

第一步,书写打开相机、相册代码by IOS

需要用到Assetslibrary.framework

////  GetPhotoControl.m//  image2////  Created by tengjiang on 16/4/26.//  Copyright © 2016年  All rights reserved.//#import <Foundation/Foundation.h>#import "GetPhotoManager.h"#include <sys/param.h>#include <sys/mount.h>#import <AssetsLibrary/AssetsLibrary.h>#import <AVFoundation/AVCaptureDevice.h>#import <AVFoundation/AVMediaFormat.h>extern "C"{    void _GetPhotoControl(int index);}static GetPhotoManager *getPhotoControl;void _GetPhotoControl(int index){    if(getPhotoControl == NULL)    {        getPhotoControl = [[GetPhotoManager alloc] init];    }    [getPhotoControl GetPhotoChoose:index];}@implementation GetPhotoManagertypedef enum {    kCLAuthorizationStatusNotDetermined = 0, // 用户尚未做出选择这个应用程序的问候    kCLAuthorizationStatusRestricted,        // 此应用程序没有被授权访问的照片数据。可能是家长控制权限    kCLAuthorizationStatusDenied,            // 用户已经明确否认了这一照片数据的应用程序访问    kCLAuthorizationStatusAuthorized         // 用户已经授权应用访问照片数据} CLAuthorizationStatus;};- (void)GetPhotoChoose:(NSInteger)ChooseIndex{    UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypePhotoLibrary;    // 判断是否支持相机    if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {        switch (ChooseIndex) {            case 0:                //来源:相机                if([self GetCameraPermission] == -1)                {                    UnitySendMessage("GameMain", "CandleShowPhoto", "");                    return;                }                sourceType = UIImagePickerControllerSourceTypeCamera;                break;            case 1:                if([self GEtPickPermission] == -1)                {                    UnitySendMessage("GameMain", "CandleShowPhoto", "");                    return;                }                //来源:相册                sourceType = UIImagePickerControllerSourceTypePhotoLibrary;                break;            case 2:                UnitySendMessage("GameMain", "CandleShowPhoto", "");                return;        }    }    else    {        if (ChooseIndex == 2) {            UnitySendMessage("GameMain", "CandleShowPhoto", "");            return;        }        else        {            if([self GEtPickPermission] == -1)            {                UnitySendMessage("GameMain", "CandleShowPhoto", "");                return;            }            sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;        }    }    // 跳转到相机或相册页面    UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];    imagePickerController.delegate = self;    //imagePickerController.allowsEditing = NO;    imagePickerController.sourceType = sourceType;    //仔细看这句话Unity中如果获取presentViewController并跳转,需要这样写    [UnityGetGLViewController() presentViewController:imagePickerController animated:YES completion:^{    }];    //↑↑↑↑↑↑↑↑↑↑↑↑↑仔细看↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑}//获取图片后的回调- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{    [picker dismissViewControllerAnimated:YES completion:^{    }];    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];    NSData *fData = [self imageCompressForWidth:image targetWidth:600 targetHeight:400];    NSString *stringPhoto = [fData base64EncodedStringWithOptions:0];    UnitySendMessage("GameMain", "ShowPhoto", [stringPhoto UTF8String]);    NSData *fDataSmall = [self imageCompressForWidth:image targetWidth:80 targetHeight:60];    NSString *stringPhotoSmall = [fDataSmall base64EncodedStringWithOptions:0];    UnitySendMessage("GameMain", "ShowMiniPhoto", [stringPhotoSmall UTF8String]);}//取消的回调- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{    NSLog(@"您取消了选择图片");    [picker dismissViewControllerAnimated:YES completion:^{    }];    UnitySendMessage("GameMain", "CandleShowPhoto", "");}//工具:图片裁剪- (NSData *) imageCompressForWidth:(UIImage *)sourceImage targetWidth:(CGFloat)defineWidth targetHeight:(CGFloat)defineHeight{    CGSize imageSize = sourceImage.size;    CGFloat width = imageSize.width;    CGFloat height = imageSize.height;    CGFloat targetWidth = defineWidth;    CGFloat targetHeight = (targetWidth / width) * height;    if(targetHeight > defineHeight)    {        targetHeight = defineHeight;        targetWidth = (targetHeight / height) * width;    }    UIGraphicsBeginImageContext(CGSizeMake(targetWidth, targetHeight));    [sourceImage drawInRect:CGRectMake(0,0,targetWidth,  targetHeight)];    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();    UIGraphicsEndImageContext();    NSData *fData = UIImageJPEGRepresentation(newImage, 1);    return fData;}//判断是否开启访问相机权限-(int) GetCameraPermission{    NSString *mediaType = AVMediaTypeVideo;    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];    if(authStatus == AVAuthorizationStatusRestricted|| authStatus == AVAuthorizationStatusDenied){        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"                                                        message:@"请在设备的设置-隐私-相机中允许访问相机。"                                                       delegate:self                                              cancelButtonTitle:@"确定"                                              otherButtonTitles:nil];        [alert show];        return -1;    }    else if(authStatus == AVAuthorizationStatusAuthorized){//允许访问        return 0;    }    return 0;}//判断是否开启访问相册权限-(int) GEtPickPermission{    ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus];    if (author == kCLAuthorizationStatusRestricted || author == kCLAuthorizationStatusDenied){        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"                                                        message:@"请在设备的设置-隐私-照片中允许访问照片。"                                                       delegate:self                                              cancelButtonTitle:@"确定"                                              otherButtonTitles:nil];        [alert show];        return -1;    }    return 0;}@end

三、上传图片

已经拿到了图片文件的Steam可以直接上传到服务器,生成CDN链接,将链接分发的其他用户。
如果觉得麻烦或者觉得没有必要自己实现,可以通过云储存功能,将图片直接存到云服务。笔者用的是UCloud。当然市场上还有很多厂家提供云储存功能:七牛、阿里云、腾讯云等。。
使用云储存的好处:
1.奉行“专业的人做专业的事”原则
2.节省了开发时间,减少服务器压力
3.云储存都会提供图像再次处理功能,可以再次压缩图片,使用户下来的图片更小,节省用户流量提高用户体验。

四、下载图片并显示

成功上传到云服务器会自动生成一个链接,可以通过链接直接访问图片
Unity加载外部资源主要依靠www协议。可以直接铜鼓www协议加载图片到游戏中,但是用户不可能永远只点开一个图片一次。笔者先将图片下载到本地,然后通过www协议将本地的图片加载到Unity,如果用户再次点开,可以节省用户的流量。

  public void LoadPicByUrlBySmallImage(string _url)    {        string url = "";#if UNITY_STANDALONE_WIN        url = "file:///" + _url;#else        url = "file://" + _url;#endif        StartCoroutine(LoadTextureBySmallImage(url));    }    /// <summary>    /// load大图携程    /// </summary>    /// <param name="name"></param>    /// <returns></returns>    IEnumerator LoadTexture(string name)    {        string path = name;        WWW www = new WWW(path);        yield return www;        if (www.isDone)        {            Texture2D txt = www.texture;            int width = txt.width;            int height = txt.height;            int targetHeight = 400;            int targetWidth = 600;                 int newHeight = 0;            int newWidth = 0;            GetCutSize(targetHeight, targetWidth, height, width, ref newHeight, ref newWidth);            if (BigImage != null)            {                BigImage.gameObject.SetActive(true);                BigImage.rectTransform.sizeDelta = new Vector2(newWidth, newHeight);                BigImage.texture = txt;            }            CloseDialogJuHua();        }    }

最后笔者将本篇博文的源码放出来, 源码包括Android的工程、Plugins/IOS目录下的IOS代码和Unity的工程

下载地址:https://github.com/Prince-Ling/Unity_PushPhoto

0 0
原创粉丝点击