c# - 从 PersistentDataPath 加载图像

标签 c# image unity-game-engine

我正在制作一个 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);
                }
            }
        }
    }

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

第二次更新

我再次遵循@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;
        }
    }

最佳答案

通常你应该使用 Path.Combine喜欢

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

改为系统路径!您的目标设备可能根本无法将 / 理解为路径分隔符。


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


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

interpreted as a UTF8 string

因此,由于图像很可能有一些无法用 UTF8 字符串表示的字节,因此您会在这里得到损坏的数据!

你应该直接使用

www.downloadHandler.data

它返回原始的byte[]而不是例如File.WriteAllBytes (仅在 UWP 上)或正确的 FileStream用于将 byte[] 写入文件。类似的东西

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

场景中的白色图像通常意味着 Sprite 为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 和

Using this class significantly reduces memory reallocation compared to downloading raw bytes and creating a texture manually in script. In addition, texture conversion will be performed on a worker thread.

而且

Only JPG and PNG formats are supported.

但我想这不应该是一个问题,因为您到目前为止使用的 LoadImage 也存在相同的限制。

但是,这将是异步的,因此您必须等待纹理才能创建 Sprite 。因此,我实际上宁愿传递相应的 Image 组件的引用并直接替换其 sprite,而不是重新调整 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;
    }
}

而且

Note : Keep in mind that using a RawImage creates an extra draw call with each RawImage present, so it's best to use it only for backgrounds or temporary visible graphics.

关于c# - 从 PersistentDataPath 加载图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55365436/

相关文章:

c# - 如何使用数组值进行大小写切换(不是数组编号)

c# - 如何在 unity c# 脚本和 android Activity 之间正确通信?

c# - 如何使用 Unity 3D 使物体振动?

c# - 以编程方式延长启动画面上 Android 加载指示器的持续时间

c# - 查找 sizeof 类型的对象?

C# 无法读取 MVC 中的 App.config 文件

c# - 我可以指定要从哪个类调用虚拟方法吗?

html - 如何在 <img> 标签内创建具有固定高度的响应式图像?

python - 如何在python中从多个图像创建一个psd分层文件

html - 将 div 放在居中的图像顶部