【问题标题】:Load Image form PersistenceDataPath从 PersistentDataPath 加载图像
【发布时间】:2019-08-17 07:48:51
【问题描述】:

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

【问题讨论】:

    标签: c# image unity3d


    【解决方案1】:

    一般你应该使用Path.Combinelike

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

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


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


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

    解释为 UTF8 字符串

    因此,由于图像很可能包含一些无法在 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);
    }
    

    比场景中的白色图像通常意味着精灵是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 存在时创建一个额外的绘制调用,因此最好仅将它用于背景或临时可见图形。

    【讨论】:

    • 非常感谢您的回答,@derHugo。我做了您建议的更改,现在我可以打开从服务器下载的图像。但是当我尝试在 unity 上加载它时,我仍然看到一个白色图像。
    • 所以我们修复了第一部分;)如果这修复了本地加载部分,您可以查看我添加的底部部分吗?
    • 非常感谢@derHugo。我遵循了您使用 rawImage 的建议。我其实不知道 image 和 rawImage 之间的区别。我只是想在应用程序中显示图像。我使用您建议的第二种方法,它在 Unity 编辑器中运行良好,但在 android 设备上却不行,我不知道为什么。但是我尝试了一种我已经看过的方法,现在它正在工作。我把它放在我的问题中。再次感谢!
    猜你喜欢
    • 2018-08-03
    • 1970-01-01
    • 1970-01-01
    • 2017-06-11
    • 2014-06-27
    • 1970-01-01
    • 2013-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多