Reputation: 348
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;
}
Upvotes: 2
Views: 5203
Reputation: 633
I'm creating a custom .NET 5 Web API and getting quite a bit of data from within Unity. I thought simply returning a byte[] from my images and parsing them would work, but as soon as I changed my API method's return type back to a FileResult my images finally loaded properly. My guess is the byte[] alone doesn't have the necessary image metadata that Unity needs, and returning them as FileResult fixes these formatting problems.
Upvotes: 0
Reputation: 125455
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;
}
Upvotes: 3
Reputation: 4889
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:
System.IO.File.WriteAllBytes(path, bytes)
.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.
Upvotes: 1