在Unity3D中加载外部图片的三种方法(包含保存,创建文件,加载图片方式性能对比)

//加载网络图片路径 
public string url = "http://www.yourwebsite.com/logo.png";
//加载本地图片路径
public string localUrl= @"file://C:\Users\Administrator\Desktop\md5\one.jpg";

//保存图片到本地使用如下方式:

 System.IO.File.WriteAllBytes(
 Application.persistentDataPath + "/" + screenShotFolder + "/" + Time.time + ".jpg" 
, bytes); 
//保存路径:screenShotFolder是文件夹名称,需要预先创建
 Application.persistentDataPath + "/" + screenShotFolder + "/" + Time.time + ".jpg" 

//创建文件代码:

 void CreateFolder(string folder)
    {
        string fullName = Application.persistentDataPath + "/" + folder + "/";
        try
        {
            bool flag = !Directory.Exists(fullName);
            if (flag)
            {
                Directory.CreateDirectory(fullName);
            }
        }
        catch (Exception ex2)
        {
            Debug.Log("create folder failure");
            return;
        }
    }

喜闻乐见的WWW方式

  喜闻乐见的WWW方式之所以喜闻乐见,这是因为这是我们最为熟悉的一种,我们都知道通过WWW可以从网络上加载文本、图片、音频等形式的内容,那么通过WWW能否加载本地外部(相对于应用程序)资源呢?答案是肯定的,这是因为WWW可以支持http和file两种协议。我们通常接触到的WWW默认都是指http协议,现在我们来说说file协议,该协议可以用来访问本地资源(绝对路径)。例如我们希望加载文件D:\TestFile\pic001.png这个文件,则此时对应的C#脚本为:

//请求WWW
WWW www = new WWW("file://D:\\TestFile\\pic001.png);
yield return www;        
if(www != null && string.IsNullOrEmpty(www.error))
{
    //获取Texture
    Texture texture=www.texture;   
    //更多操作...       
}

注意到这里出现了yield return结构,这表示这里使用到了协程,因此我们需要付出的代价就是需要在项目中使用StartCoroutine等协程相关的方法来调用这些协程。虽然在Unity3D中使用协程是件简单的事情,可是如果我们随随便便地使用协程而不注意去维护这些协程,那么这些让我们引以为傲的简单代码可能就会变成我们痛苦不堪的无尽深渊。

亘古不变的传统IO方式

  好了,下面我们隆重推出亘古不变的传统IO方式,这种方式相信大家都没有接触过,所以这里将这种方法和大家分享。既然是传统的IO方式,那么无非就是各种IO流的处理啦。好,我们一起来看下面这段代码:

//创建文件读取流
FileStream fileStream = new FileStream(screen, FileMode.Open, FileAccess.Read);
fileStream.Seek(0, SeekOrigin.Begin);
//创建文件长度缓冲区
byte[] bytes = new byte[fileStream.Length]; 
//读取文件
fileStream.Read(bytes, 0, (int)fileStream.Length);
//释放文件读取流
fileStream.Close();
fileStream.Dispose();
fileStream = null;

//创建Texture
int width=800;
int height=640;
Texture2D texture = new Texture2D(width, height);
texture.LoadImage(bytes);
  • 以看到在使用这种方式读取图片文件的时候主要是将图片文件转化为byte[]数组,再利用Texture2D的LoadImage方法转化为Unity3D中的Texture2D。这种方法需要在创建过程中传入图片的大小,在这里我们创建了一张800X640的图片。经过博主的研究发现,这种方式加载外部图片相对于使用WWW加载外部图片效率更高,所以如果大家遇到类似的需求,博主个人推荐大家使用这种方式进行加载。

  到目前为止我们解决了如何从外部加载图片到Unity3D中,现在我们回到最开始的问题,我们从外部读取到这些图片以后需要将它们加载到游戏界面中。比如当我们使用UGUI的时候,UGUI中的Image控件需要一个Sprite来作为它的填充内容,那么此时我们就需要将Texture转化为Sprite.号了,下面我们给出一个简单的例子:

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

public class TestLoading : MonoBehaviour 
{
    /// <summary>
    /// Image控件
    /// </summary>
    private Image image;

    void Start () 
    {
        image = this.transform.Find("Image").GetComponent<Image>();

        //为不同的按钮绑定不同的事件
        this.transform.Find("LoadByWWW").GetComponent<Button>().onClick.AddListener
        (
           delegate(){LoadByWWW();}
        );

        this.transform.Find("LoadByIO").GetComponent<Button>().onClick.AddListener
        (
          delegate(){LoadByIO();}
        );
    }

    /// <summary>
    /// 以IO方式进行加载
    /// </summary>
    private void LoadByIO()
    {
        double startTime = (double)Time.time;
        //创建文件读取流
        FileStream fileStream = new FileStream("D:\\test.jpg", FileMode.Open, FileAccess.Read);
        fileStream.Seek(0, SeekOrigin.Begin);
        //创建文件长度缓冲区
        byte[] bytes = new byte[fileStream.Length];
        //读取文件
        fileStream.Read(bytes, 0, (int)fileStream.Length);
        //释放文件读取流
        fileStream.Close();
        fileStream.Dispose();
        fileStream = null;

        //创建Texture
        int width = 300;
        int height = 372;
        Texture2D texture = new Texture2D(width, height);
        texture.LoadImage(bytes);

        //创建Sprite
        Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
        image.sprite = sprite;

        startTime=(double)Time.time-startTime;
        Debug.Log("IO加载用时:" + startTime);
    }

    /// <summary>
    /// 以WWW方式进行加载
    /// </summary>
    private void LoadByWWW()
    {
        StartCoroutine(Load());
    }

    IEnumerator Load()
    {
        double startTime = (double)Time.time;
        //请求WWW
        WWW www = new WWW("file://D:\\test.jpg");
        yield return www;        
        if(www != null && string.IsNullOrEmpty(www.error))
        {
            //获取Texture
            Texture2D texture=www.texture;

            //创建Sprite
            Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
            image.sprite = sprite;

            startTime = (double)Time.time - startTime;
            Debug.Log("WWW加载用时:" + startTime);
        }
    }
}

Unity使用WWW下载服务器上的图片,并保存到指定路径。


using UnityEngine;

using System.Collections;
using System.IO;


//图片下载测试
public class CWWWTest : MonoBehaviour {


    WWW www;                     //请求
    string filePath;             //保存的文件路径
    Texture2D texture2D;         //下载的图片
    public Transform m_tSprite;  //场景中的一个Sprite
void Start () {
        //保存路径
        filePath = Application.dataPath + "/Resources/picture.jpg"; 
}
void Update () {
        //点击鼠标左键开始下载
        if (Input.GetMouseButtonDown(0)) {
            Debug.Log("开始下载");
            StartCoroutine(LoadImg());
            
        }
}
    IEnumerator LoadImg() { 
        //开始下载图片
        www = new WWW("http://flashtest.sinaapp.com/gamesky/gamesky.jpg");
        yield return www;


        //下载完成,保存图片到路径filePath
        texture2D = www.texture;
        byte[] bytes = texture2D.EncodeToPNG();
        File.WriteAllBytes(filePath, bytes);


        //将图片赋给场景上的Sprite
        Sprite tempSp = Sprite.Create(texture2D, new Rect(0,0,texture2D.width,texture2D.height),new Vector2(0,0));
        m_tSprite.GetComponent<SpriteRenderer>().sprite = tempSp;
        Debug.Log("加载完成");
            
    }
}


using UnityEngine;
02. using System.Collections;
03. using System.IO;
04.  
05. public class AsyncImageDownload :MonoBehaviour {
06.  
07. public  Texture placeholder;
08. public static AsyncImageDownload  Instance=null;
09.  
10. private   string path=Application.persistentDataPath+"/ImageCache/" ;
11.  
12. //构建单例
13. public static AsyncImageDownload CreateSingleton()
14. {
15. if (!Directory.Exists(Application.persistentDataPath+"/ImageCache/")) {
16. Directory.CreateDirectory(Application.persistentDataPath+"/ImageCache/");
17. }
18.  
19. GameObject obj = new GameObject ();
20. obj.AddComponent<AsyncImageDownload> ();
21.  
22. AsyncImageDownload loader= obj.GetComponent<AsyncImageDownload>();
23. Instance=loader;
24. loader.placeholder=Resources.Load("placeholder") as Texture;
25. return loader;
26.  
27. }
28.  
29.  
30. public  void SetAsyncImage(string url,UITexture texture){
31.  
32.  
33.  
34. //开始下载图片前,将UITexture的主图片设置为占位图
35. texture.mainTexture = placeholder;
36.  
37. //判断是否是第一次加载这张图片
38.  
39. if (!File.Exists (path + url.GetHashCode())) {
40. //如果之前不存在缓存文件
41.  
42.  
43. StartCoroutine (DownloadImage (url, texture));
44.  
45.  
46. }
47. else {
48.  
49. StartCoroutine(LoadLocalImage(url,texture));
50.  
51. }
52.  
53. }
54.  
55. IEnumerator  DownloadImage(string url,UITexture texture){
56. Debug.Log("downloading new image:"+path+url.GetHashCode());
57. WWW www = new WWW (url);
58. yield return www;
59.  
60. Texture2D image = www.texture;
61. //将图片保存至缓存路径
62. byte[] pngData = image.EncodeToPNG(); 
63. File.WriteAllBytes(path+url.GetHashCode(), pngData); 
64.  
65. texture.mainTexture = image;
66.  
67. }
68.  
69. IEnumerator  LoadLocalImage(string url,UITexture texture){
70. string filePath = "file:///" + path + url.GetHashCode ();
71.  
72. Debug.Log("getting local image:"+filePath);
73. WWW www = new WWW (filePath);
74. yield return www;
75.  
76.  
77. //直接贴图
78. texture.mainTexture = www.texture;
79.  
80. }
81. }


1.将文件下载完成
2.通过URL获取文件名字(类型包括在里面了)
3.通过字节的形式,以写文件的方式写到本地。
直接上代码:
    private IEnumerator DownLoadToLocal(string url, string  number)
    {
        WWW www = new WWW(url);
        string img_name = url.Substring(url.LastIndexOf('/') + 1); //根据URL获取文件的名字。
        yield return www;
        if (www.error == null)
        {
                FileStream fs = File.Create(path + img_name); //path为你想保存文件的路径。
                fs.Write(www.bytes, 0, www.bytes.Length);
                fs.Close();
        }
        else
        {
            Debug.Log(www.error);
        }

    }





  现在我们运行程序可以发现两种方式均可以让图片加载进来,为了对比两种方式在执行效率上的高低,我们在脚本中加入了相关代码,通过对比可以发现使用IO方式加载一张227k的图片需要的时间为0s,而使用WWW方式加载需要0.0185s,因此传统的IO方式具有更高的效率,建议大家在遇到这类问题时尽可能地使用这种方式。好了,今天的内容就是这样啦,欢迎大家在我的博客中留言、欢迎大家关注和支持我的博客,谢谢大家!

猜你喜欢

转载自blog.csdn.net/lizhenxiqnmlgb/article/details/80436116