Unity 图片及截图本地存储、相册更新等系列问题总结

在Unity中对图像资源进行处理时,会有很多问题需要注意。比如:

一、标准方法

using System.IO;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

1、图片存储至本地相册

    /// <summary>
    /// 图片存储至本地相册
    /// </summary>
    /// <param name="target">需要存储的指定图片</param>
    public void GetTexture2d(Image target)
    {
    
    
        //sprite为图集中的某个子Sprite对象
        Sprite sprite = target.sprite;
        // sprite转换成Texture2D
        var targetTex = textureFromSprite(sprite);
        // 编码纹理为PNG格式
        byte[] bytes = targetTex.EncodeToPNG();
        targetTex.Compress(true);
        targetTex.Apply();
        //存储路径
        string path = "";
        //应用平台判断,路径选择
        if (Application.platform == RuntimePlatform.Android)
        {
    
    
            //手机文件管理中的存储位置:我的手机/Android/data/come.XX.XX(PackageName)/files/XXX.png
            path = Application.persistentDataPath + "/" + target.name + ".png";
        }
        else if (Application.platform == RuntimePlatform.WindowsEditor) {
    
    
            path = Application.dataPath + "/" + target.name + ".png";
        }
        //保存文件
        File.WriteAllBytes(path, bytes);
        //调用安卓方法,刷新相册
        using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
        {
    
    
            using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity"))
            {
    
    
                //为安卓方法提供图片存储的路径参数,方便刷新至相册
                jo.Call("file", path);
            }
        }
    }
    /// <summary>
    /// sprite转换成Texture2D
    /// </summary>
    /// <param name="sprite"></param>
    /// <returns></returns>
 	public static Texture2D textureFromSprite(Sprite sprite)
        {
    
    
            if (sprite.rect.width != sprite.texture.width)
            {
    
    
                Texture2D newText = new Texture2D((int)sprite.rect.width, (int)sprite.rect.height);
                Color[] newColors = sprite.texture.GetPixels((int)sprite.textureRect.x,
                                                             (int)sprite.textureRect.y,
                                                             (int)sprite.textureRect.width,
                                                             (int)sprite.textureRect.height);
                newText.SetPixels(newColors);
                newText.Apply();
                return newText;
            }
            else
                return sprite.texture;
        }

在这里插入图片描述

截图存储至本地
关于截图操作,由于要读取屏幕内容,所以图片要允许可读,勾选Read/Writer Ebable
在这里插入图片描述

2、截图到本地

IEnumerator GetTexture2d_ScreenShot()
    {
    
    
        // 因为"WaitForEndOfFrame"在OnGUI之后执行
        // 所以我们只在渲染完成之后才读取屏幕上的画面
        yield return new WaitForEndOfFrame();
        //创建一个纹理,传入长宽参数,如下是创建一个1/2屏幕大小的纹理
        Texture2D targetTex = new Texture2D(Screen.width/2, Screen.height/2, TextureFormat.RGB24, false);
        // 读取屏幕内容到我们自定义的纹理图片中,如下读取的是屏幕右上角的纹理
        targetTex.ReadPixels(new Rect(Screen.width / 2, Screen.height / 2, Screen.width / 2, Screen.height / 2), 0, 0, true);
        // 保存前面纹理的修改
        targetTex.Apply();
        // 编码纹理为PNG格式
        byte[] bytes = targetTex.EncodeToPNG();
        //存储路径
        string path = "";
        //应用平台判断,路径选择
        if (Application.platform == RuntimePlatform.Android)
        {
    
    
            // 这个路径会将图片保存到手机的沙盒中,这样就可以在手机上对其进行读写操作了
            //手机文件管理中的存储位置:我的手机/Android/data/come.XX.XX(PackageName)/files/XXX.png
            path = Application.persistentDataPath + "/ScreenShot.png";
        }
        else if (Application.platform == RuntimePlatform.WindowsEditor)
        {
    
    
            // 将字节保存成图片,这个路径只能在PC端对图片进行读写操作
            //Assets目录下
            path = Application.dataPath + "/ScreenShot.png";
            //保存D盘目录下
            //path = "D:/ScreenShot.png";
        }
        //保存文件
        File.WriteAllBytes(path, bytes);
     
    }

保存后有一定延迟,等待几秒钟再点击unity就会出现。
在这里插入图片描述
在这里插入图片描述

二、问题解决办法

1、如何截图指定区域及位置?

在这里插入图片描述

2、Texture2D和Sprite如何互相转换?

如果能够知道资源所在地址,最简便安全的方法是使用Resources.Load。由于资源类型不是由文件确定的,而是由Unity本身确定的,因此可以将sprite源图像用作任何图形资产。

如果只能获取到组件中的资源,如Image.sprite,需要进行资源转换,
1.Sprite转Texture2D

 public static Texture2D textureFromSprite(Sprite sprite)
        {
    
    
            if (sprite.rect.width != sprite.texture.width)
            {
    
    
                Texture2D newText = new Texture2D((int)sprite.rect.width, (int)sprite.rect.height);
                Color[] newColors = sprite.texture.GetPixels((int)sprite.textureRect.x,
                                                             (int)sprite.textureRect.y,
                                                             (int)sprite.textureRect.width,
                                                             (int)sprite.textureRect.height);
                newText.SetPixels(newColors);
                newText.Apply();
                return newText;
            }
            else
                return sprite.texture;
        }

2.克隆Texture2D

 //originTex为克隆对象
 Texture2D newTex;
 newTex = new Texture2D(originTex.width, originTex.height);
 Color[] colors = originTex.GetPixels(0, 0, originTex.width, originTex.height);
 newTex.SetPixels(colors);
 newTex.Apply();//必须apply才生效

3.Texture2D转Sprite

//t2d为待转换的Texture2D对象
Sprite s= Sprite.Create(t2d, new Rect(0, 0, t2d.width, t2d.height), Vector2.zero);

3、手机、电脑的存储路径

详细介绍可查看此博客:
在这里插入图片描述
在这里插入图片描述
保存后有一定延迟,等待几秒钟再点击unity就会出现。
在这里插入图片描述
在这里插入图片描述

4、如何把存储的图片更新到手机相册?

正常保存图片文件到手机磁盘,但是系统相册APP内看不到图片,所以保存完毕之后就是要通知相册刷新。

在这里插入图片描述

5、Vuforia切换回识别场景后黑屏?

使用Vuforia SDK开发时,如果从其他非识别场景切换回识别场景,可能会出现黑屏问题。解决方法是在切换到其他场景时,先将当前场景的Tracker信息全部Stop。

IEnumerator LoadScenes(string sceneName)
    {
    
    
        if (TrackerManager.Instance.GetTracker<MarkerTracker>() != null)
        {
    
    
            MarkerTracker marker = TrackerManager.Instance.GetTracker<MarkerTracker>();
            marker.Stop();
        }
 
        if (TrackerManager.Instance.GetTracker<TextTracker>() != null)
        {
    
    
            TextTracker textTracker = TrackerManager.Instance.GetTracker<TextTracker>();
            textTracker.Stop();
        }
 
        if (TrackerManager.Instance.GetTracker<ObjectTracker>() != null)
        {
    
    
            ObjectTracker objTracker = TrackerManager.Instance.GetTracker<ObjectTracker>();
            objTracker.Stop();
        }
     
    //此处返回waitForSeconds,因为我是在OnGUI中启动协程,如果不用WaitForSeconds,就会识别两次模型
        yield return new WaitForSeconds(0.5f);  //WaitForEndOfFrame();
 
        Application.LoadLevel(sceneName);
    }

猜你喜欢

转载自blog.csdn.net/qq_43505432/article/details/114310461