使用 HttpWebRequest 下载后 PNG 文件显示为红色问号
PNG file displayed as red question mark after download with HttpWebRequest
我面临以下问题:我从 google 驱动器下载一个 png 文件,所有字节都已成功接收(看起来),但是当我尝试构建 Texture2D
并设置它时as Sprite
in an Image
, 只出现红色的问号。
我是不是漏掉了什么?
代码如下:
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;
}
您可能会收到错误响应或中间页面,这会使纹理无效。尝试通过两种方式检查接收到的数据是否真的是有效的PNG图片:
- 通过
System.IO.File.WriteAllBytes(path, bytes)
将其导出为图像文件。
前四个字节与the PNG header比较:
//0x89, 'P', 'N', 'G'
public static readonly byte[] PngHeaderBytes =
{
0x89, 0x50, 0x4E, 0x47
};
我用你的确切代码和这个 image 做了一个快速测试,然后这样做:
问题是您没有下载所有图像字节。这不是如何使用 HttpWebRequest
下载所有图像字节。在 while 循环中使用 MemoryStream
和 Stream.Read
。如果没有别的可看的,Stream.Read
会return0
.
查看 downloadFullData
函数以了解如何正确执行此操作:
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();
}
}
}
}
结果:
这应该可以,但不要使用 HttpWebRequest
,因为它会阻止您的程序,直到图像下载完毕。如果你想使用它,那么你必须在另一个 Thread
中使用它。这从这里变得非常复杂,因为你不能在另一个 Thread
中使用 Unity 的 API 并且必须使用类似 this 的东西来调用 Unity 的 API( texture2d.LoadImage(bytes)
) 在另一个线程中。
为此使用 Unity 的 WWW
or UnityWebRequest
API。下面的示例将完成与 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;
}
我正在创建自定义 .NET 5 Web API 并从 Unity 中获取大量数据。我认为简单地 return 从我的图像中读取一个字节 [] 并解析它们就可以了,但是当我将 API 方法的 return 类型改回 FileResult 时,我的图像终于正确加载了.我的猜测是 byte[] 本身没有 Unity 需要的必要图像元数据,return将它们作为 FileResult 解决了这些格式问题。
我面临以下问题:我从 google 驱动器下载一个 png 文件,所有字节都已成功接收(看起来),但是当我尝试构建 Texture2D
并设置它时as Sprite
in an Image
, 只出现红色的问号。
我是不是漏掉了什么?
代码如下:
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;
}
您可能会收到错误响应或中间页面,这会使纹理无效。尝试通过两种方式检查接收到的数据是否真的是有效的PNG图片:
- 通过
System.IO.File.WriteAllBytes(path, bytes)
将其导出为图像文件。 前四个字节与the PNG header比较:
//0x89, 'P', 'N', 'G' public static readonly byte[] PngHeaderBytes = { 0x89, 0x50, 0x4E, 0x47 };
我用你的确切代码和这个 image 做了一个快速测试,然后这样做:
问题是您没有下载所有图像字节。这不是如何使用 HttpWebRequest
下载所有图像字节。在 while 循环中使用 MemoryStream
和 Stream.Read
。如果没有别的可看的,Stream.Read
会return0
.
查看 downloadFullData
函数以了解如何正确执行此操作:
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();
}
}
}
}
结果:
这应该可以,但不要使用 HttpWebRequest
,因为它会阻止您的程序,直到图像下载完毕。如果你想使用它,那么你必须在另一个 Thread
中使用它。这从这里变得非常复杂,因为你不能在另一个 Thread
中使用 Unity 的 API 并且必须使用类似 this 的东西来调用 Unity 的 API( texture2d.LoadImage(bytes)
) 在另一个线程中。
为此使用 Unity 的 WWW
or UnityWebRequest
API。下面的示例将完成与 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;
}
我正在创建自定义 .NET 5 Web API 并从 Unity 中获取大量数据。我认为简单地 return 从我的图像中读取一个字节 [] 并解析它们就可以了,但是当我将 API 方法的 return 类型改回 FileResult 时,我的图像终于正确加载了.我的猜测是 byte[] 本身没有 Unity 需要的必要图像元数据,return将它们作为 FileResult 解决了这些格式问题。