PNG file displayed as red question mark after download with HttpWebRequest

本小妞迷上赌 提交于 2019-12-11 02:46:11

问题


I face the following issue: I downloading a png file from google drive, all bytes are successfully received (as it seems), but when I try to construct a Texture2D and set it as Sprite in an Image, only red a question mark appears.

Am I missing something?

Code below:

HttpWebRequest request = (HttpWebRequest) WebRequest.Create("https://content.googleapis.com/drive/v3/files/" + fileId + "?alt=media");
request.Method = "GET";
request.ContentType = "image/png";
request.Headers.Add("Authorization", "Bearer " + AUTH_TOKEN);

WebResponse response = request.GetResponse();
byte[] bytes = new byte[response.ContentLength];
response.GetResponseStream().Read(bytes, 0, (int) response.ContentLength);
response.Close();

Texture2D texture2d = new Texture2D(8, 8);
Sprite sprite = null;
if (texture2d.LoadImage(bytes)) {
    sprite = Sprite.Create(texture2d, new Rect(0, 0, texture2d.width, texture2d.height), Vector2.zero);
}
if (sprite != null) {
    imageToUpdate.sprite = sprite;
}

回答1:


I did a quick test with your exact code and this image and go this:

The problem is that you are not downloading all the image bytes. This is not how to download all the image bytes with HttpWebRequest. Use MemoryStream and Stream.Read in a while loop. If there is nothing else to read, Stream.Read will return 0.

Look at the downloadFullData function for how to do this properly:

public Image imageToUpdate;

void Start()
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://wallpaper-gallery.net/images/hq-images-wallpapers/hq-images-wallpapers-12.jpg");
    request.Method = "GET";
    //request.ContentType = "image/png";
    //request.Headers.Add("Authorization", "Bearer " + AUTH_TOKEN);

    WebResponse response = request.GetResponse();

    if (response == null)
    {
        return;
    }

    //Download All the bytes
    byte[] bytes = downloadFullData(request);

    //Load Image
    Texture2D texture2d = new Texture2D(8, 8);
    Sprite sprite = null;
    if (texture2d.LoadImage(bytes))
    {
        sprite = Sprite.Create(texture2d, new Rect(0, 0, texture2d.width, texture2d.height), Vector2.zero);
    }
    if (sprite != null)
    {
        imageToUpdate.sprite = sprite;
    }
}

byte[] downloadFullData(HttpWebRequest request)
{
    using (WebResponse response = request.GetResponse())
    {

        if (response == null)
        {
            return null;
        }

        using (Stream input = response.GetResponseStream())
        {
            byte[] buffer = new byte[16 * 1024];
            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while (input.CanRead && (read = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                return ms.ToArray();
            }
        }
    }
}

Result:

This should work but don't use HttpWebRequest because it will block your program until image is downloaded. If you want to use it then you must use it in another Thread. This gets really complicated from here because you can't use Unity's API in another Thread and would have to use something like this to call Unity's API( texture2d.LoadImage(bytes) ) in another Thread.

Use Unity's WWW or UnityWebRequest API for this. The example below will accomplish the-same exact thing with UnityWebRequest.

public Image imageToUpdate;

void Start()
{
    StartCoroutine(downloadImage());
}

IEnumerator downloadImage()
{
    string authorization = authenticate("YourUserName", "YourPass");

    string url = "http://wallpaper-gallery.net/images/hq-images-wallpapers/hq-images-wallpapers-12.jpg";

    UnityWebRequest www = UnityWebRequest.Get(url);
    //www.SetRequestHeader("AUTHORIZATION", authorization);

    DownloadHandler handle = www.downloadHandler;

    //Send Request and wait
    yield return www.Send();

    if (www.isError)
    {

        UnityEngine.Debug.Log("Error while Receiving: " + www.error);
    }
    else
    {
        UnityEngine.Debug.Log("Success");

        //Load Image
        Texture2D texture2d = new Texture2D(8, 8);
        Sprite sprite = null;
        if (texture2d.LoadImage(handle.data))
        {
            sprite = Sprite.Create(texture2d, new Rect(0, 0, texture2d.width, texture2d.height), Vector2.zero);
        }
        if (sprite != null)
        {
            imageToUpdate.sprite = sprite;
        }
    }
}

string authenticate(string username, string password)
{
    string auth = username + ":" + password;
    auth = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(auth));
    auth = "Basic " + auth;
    return auth;
}



回答2:


You may get an error response or an intermediate page which will make the texture invalid. Try checking if the data received is really a valid PNG picture in two ways:

  1. Export it to an image file via System.IO.File.WriteAllBytes(path, bytes).
  2. Compare the first four bytes with the PNG header:

    //0x89, 'P', 'N', 'G'
    public static readonly byte[] PngHeaderBytes =
    {
        0x89, 0x50, 0x4E, 0x47
    };
    

See also red question mark loading image as texture with WWW.



来源:https://stackoverflow.com/questions/43010898/png-file-displayed-as-red-question-mark-after-download-with-httpwebrequest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!