从流/StreamReader加载图像到Image或RawImage组件

4
我正在使用 AWS Unity (v3.3.50.0): S3 SDK (AWSSDK.S3.3.3.5.4.unitypackage),该SDK已从https://aws.amazon.com/mobile/sdk/下载。我的 Unity 版本是 5.5.1。
我想要下载一个位于 S3 存储桶上的图像,存储桶已经配置好可以进行下载。我在响应中看到字符串数据。
但是我无法将返回的 StreamReader 转换为 UnityEngine.UI.Image.sprite 或 UnityEngine.UI.RawImage.texture 在 S3 示例 GetObject() 函数中。
private void GetObject()
{
    ResultText.text = string.Format("fetching {0} from bucket {1}", SampleFileName, S3BucketName);
    Client.GetObjectAsync(S3BucketName, SampleFileName, (responseObj) =>
        {
            string data = null;
            var response = responseObj.Response;
            if (response.ResponseStream != null)
            {
                using (StreamReader reader = new StreamReader(response.ResponseStream))
                {
                    data = reader.ReadToEnd();
                }

                ResultText.text += "\n";
                ResultText.text += data;
            }
            Debug.Log("GetObject: " + data);
        });
}

需要帮忙解决以下问题:)

S3存储桶中的图像是PNG格式。但未来必须启用JPG、JPEG格式支持。


图片在服务器上是什么格式? - Programmer
你能展示一下从流中输出的数据示例吗?也许它是以 base64 的形式呈现,或者它只是原始二进制数据,你应该使用 BinaryReader 进行读取。 - mrogal.ski
输出为:�PNG - eagle
1个回答

7

StreamReader 用于处理文本数据,而不是像你想要下载的图片这样的二进制数据。我可以理解你为什么使用它,但我也不知道你为什么对一张图片执行 Debug.Log("GetObject: " + data); 操作。

下载图片后,使用 Texture2D.LoadImage 将其转换为 Texture2D,然后可以将其加载到你的 RawImage 中显示。

public RawImage displayTexture;

private void GetObject()
{
    ResultText.text = string.Format("fetching {0} from bucket {1}", SampleFileName, S3BucketName);
    Client.GetObjectAsync(S3BucketName, SampleFileName, (responseObj) =>
    {
        byte[] data = null;
        var response = responseObj.Response;
        if (response.ResponseStream != null)
        {
            using (StreamReader reader = new StreamReader(response.ResponseStream))
            {
                using (var memstream = new MemoryStream())
                {
                    var buffer = new byte[512];
                    var bytesRead = default(int);
                    while ((bytesRead = reader.BaseStream.Read(buffer, 0, buffer.Length)) > 0)
                        memstream.Write(buffer, 0, bytesRead);
                    data = memstream.ToArray();
                }
            }

            //Display Image
            displayTexture.texture = bytesToTexture2D(data);
        }
    });
}

public Texture2D bytesToTexture2D(byte[] imageBytes)
{
    Texture2D tex = new Texture2D(2, 2);
    tex.LoadImage(imageBytes);
    return tex;
}

如我上面所提到的,使用StreamReader不适合处理二进制数据。你可以直接使用MemoryStream来处理。在这种情况下,你的新的GetObject函数应该像这样:

private void GetObject()
{
    ResultText.text = string.Format("fetching {0} from bucket {1}", SampleFileName, S3BucketName);
    Client.GetObjectAsync(S3BucketName, SampleFileName, (responseObj) =>
    {
        byte[] data = null;
        var response = responseObj.Response;
        Stream input = response.ResponseStream;

        if (response.ResponseStream != null)
        {
            byte[] buffer = new byte[16 * 1024];
            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                data = ms.ToArray();
            }

            //Display Image
            displayTexture.texture = bytesToTexture2D(data);
        }
    });
}

干得好!它起作用了!谢谢! :) 有没有性能优化的方法来做这件事?就像这样,首先你读取它,然后将其写入缓冲区,然后将其转换为byte[]。 难道没有一种直接将流转换为byte[]的方法吗? - eagle
1
不行。您不知道流的大小,这是唯一的方法。另一种方法是不使用亚马逊服务。开发自己的带有TCP协议的服务,该服务将首先发送字节计数,然后发送字节。在这种情况下,您知道字节数量,并且将一次性分配内存以下载图像。 - Programmer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接