在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);
}