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