加载图像表格PersistenceDataPath

时间:2019-03-26 20:05:50

标签: c# image unity3d

我正在制作一个Android应用程序,该应用程序应从一开始就从MySQL数据库加载数据和从服务器加载一些图像。之后,用户将在外面,因此该应用将可离线使用。

我编写了代码,以将所有数据库数据(有效)和来自服务器的映像保存到ApplicationPersistenceDataPath(不起作用)。我已经在寻找应该如何做。我拥有的代码不会引发任何错误。但是,当我尝试将其显示在应用程序上时,图像为空白。那是当我查看存储图像的文件夹时,我无法打开它们。

这是我必须保存图像的方法:

IEnumerator loadBgImage(string url, string file_name)
    {
        using (UnityWebRequest www = UnityWebRequest.Get(url))
        {
            yield return www.Send();
            if (www.isNetworkError || www.isHttpError)
            {
                print("erro");
            }
            else
            {
                string savePath = string.Format("{0}/{1}", Application.persistentDataPath, file_name);
                if (!File.Exists(savePath))
                {
                    System.IO.File.WriteAllText(savePath, www.downloadHandler.text);
                }
            }
        }
    }

这是在图像中显示图像文件的代码:

string path = Application.persistentDataPath + "/" + nomeImagem;
imagem.GetComponent<SpriteRenderer>().sprite = LoadSprite(path);

这是称为:

的方法
    private Sprite LoadSprite(string path)
    {
        if (string.IsNullOrEmpty(path)) return null;
        if (System.IO.File.Exists(path))
        {            
            byte[] bytes = File.ReadAllBytes(path);
            Texture2D texture = new Texture2D(900, 900, TextureFormat.RGB24, false);
            texture.filterMode = FilterMode.Trilinear;
            texture.LoadImage(bytes);
            Sprite sprite = Sprite.Create(texture, new Rect(0, 0, 8, 8), new Vector2(0.5f, 0.0f), 1.0f);

        }
        return null;
    }

我真的需要先保存图像,然后将其离线显示。有人可以告诉我我在做什么错吗?

更新 在遵循@derHugo答案的建议之后,这是我必须保存图像的代码:

IEnumerator loadBgImage(string url, string file_name)
    {
        using (UnityWebRequest www = UnityWebRequest.Get(url))
        {
            yield return www.Send();
            if (www.isNetworkError || www.isHttpError)
            {
                print("erro");
            }
            else
            {
                var savePath = Path.Combine(Application.persistentDataPath, file_name);
                var data = www.downloadHandler.data;
                using (var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write))
                {
                    fs.Write(data, 0, data.Length);
                }
            }
        }
    }

它可以工作,但运行该应用程序时仍然看不到图像。在显示精灵的方法中,我添加了创建的精灵的返回。

第二次更新

我再次遵循@derHugo的建议,并使用rawImage代替Image。现在它可以在Unity编辑器和Android设备上使用。这是我使用的方法:

private void LoadSprite(string path)
    {
        if (string.IsNullOrEmpty(path)) print("erro");
        if (System.IO.File.Exists(path))
        {
            byte[] bytes = File.ReadAllBytes(path);
            Texture2D texture = new Texture2D(900, 900, TextureFormat.RGB24, false);
            texture.filterMode = FilterMode.Trilinear;
            texture.LoadImage(bytes);
            imagem.texture = texture;
        }
    }

1 个答案:

答案 0 :(得分:1)

通常,您应该宁愿使用Path.Combine

var path = Path.Combine(Application.persistentDataPath, FileName);

代替系统路径!可能是您的目标设备根本不将/理解为路径分隔符。


或者如果文件已经存在(也可能是较新版本?并且您已经下载了文件),也要写文件,或者如果文件已经存在以节省带宽,甚至不应该开始下载。


我还认为WriteAllText并不是二进制图像数据的正确解决方案,因为www.downloadHandler.text已经是

  

解释为UTF8字符串

因此,由于图像很可能具有一些UTF8字符串中无法表示的字节,因此此处的数据已损坏!

您应该直接使用

www.downloadHandler.data

,它返回原始byte[]而不是例如File.WriteAllBytes(仅在UWP上)或用于将byte[]写入文件的适当的FileStream。像

var data = www.downloadHandler.data;
File.WriteAllBytes(path, data);

var data = www.downloadHandler.data;
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
    fs.Write(data, 0, data.Length);
}

场景中的白色图像通常意味着精灵为null

如果没有错字,则您的LoadSprite 总是返回null。您忘记了返回创建的sprite

private Sprite LoadSprite(string path)
{
    if (string.IsNullOrEmpty(path)) return null;
    if (System.IO.File.Exists(path))
    {            
        byte[] bytes = File.ReadAllBytes(path);
        Texture2D texture = new Texture2D(900, 900, TextureFormat.RGB24, false);
        texture.filterMode = FilterMode.Trilinear;
        texture.LoadImage(bytes);
        Sprite sprite = Sprite.Create(texture, new Rect(0, 0, 8, 8), new Vector2(0.5f, 0.0f), 1.0f);

        // You should return the sprite here!
        return sprite;
    }
    return null;
}

但是请注意,实际上,UnityWebRequestTexture也是加载本地图像的更好方法。它还将本地文件路径作为URL和

  

与下载原始字节并在脚本中手动创建纹理相比,使用此类可以大大减少内存分配。另外,纹理转换将在工作线程上执行。

而且

  

仅支持JPG和PNG格式。

但是我猜这应该不是问题,因为到目前为止您使用的LoadImage具有相同的限制。

这将是异步的,因此您必须等待纹理才能创建精灵。因此,实际上我宁愿传递相应的Sprite组件的引用,而直接替换其Image,而不是重新调整sprite。像

private IEnumerator LoadLocalTexture(string path, Image receivingImage)
{
    UnityWebRequest www = UnityWebRequestTexture.GetTexture(path);
    yield return www.SendWebRequest();

    if(www.isNetworkError || www.isHttpError) 
    {
        Debug.Log(www.error);
    }
    else 
    {
        var texture = ((DownloadHandlerTexture)www.downloadHandler).texture;
        var sprite = Sprite.Create(texture, new Rect(0, 0, 8, 8), new Vector2(0.5f, 0.0f), 1.0f);

        receivingImage.sprite = sprite;
    }
}

如果您不一定要实际使用Sprites,我总是建议您宁愿使用RawImage组件,而可以直接使用Texture2D!比做类似的事情

private IEnumerator LoadLocalTexture(string path, RawImage receivingImage)
{
    UnityWebRequest www = UnityWebRequestTexture.GetTexture(path);
    yield return www.SendWebRequest();

    if(www.isNetworkError || www.isHttpError) 
    {
        Debug.Log(www.error);
    }
    else 
    {
        var texture = ((DownloadHandlerTexture)www.downloadHandler).texture;

        receivingImage.texture = texture;
    }
}

而且

  

注意:请记住,使用RawImage会在存在每个RawImage的情况下创建一个额外的绘制调用,因此最好仅将其用于背景或临时可见图形。