PNG file displayed as red question mark after download with HttpWebRequest

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

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