2017-03-24 33 views
2

我面臨以下問題:我從谷歌驅動器下載一個PNG文件,所有字節都成功接收(看起來),但是當我嘗試構建一個Texture2D並設置它作爲SpriteImage中,只有紅色的問號出現。用HttpWebRequest下載後顯示爲紅色問號的PNG文件

我錯過了什麼嗎?下面

代碼:

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

回答

2

我做了一個快速測試你確切的代碼,這image去這樣的:

的問題是,你是不是下載所有圖像字節。這不是如何用HttpWebRequest下載所有圖像字節。在while循環中使用MemoryStreamStream.Read。如果沒有別的東西要讀,Stream.Read將返回0

看那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的WWWUnityWebRequest 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; 
} 
+2

Omg !!謝謝! 我是(錯誤地)假設,如果response.ContentLength給出正確的字節數,那麼Read將簡單地返回所有內容。 我已經在以異步方式進行通訊,上面的代碼被簡化爲提綱。現在一切正常,因爲它應該:)再次感謝! – MerlinBG

+1

不是。你必須繼續閱讀,直到你得到0. *「我已經在以異步方式進行通信,上面的代碼被簡化以概述問題」*很好。只是人們在Unity中犯了這個錯誤。看起來你在正確的軌道上。快樂的編碼! – Programmer

0

您可能會得到一個錯誤的響應或中間頁,這將使紋理無效。嘗試檢查收到的數據是否真的是一個有效的PNG圖片有兩種方式:

  1. 通過System.IO.File.WriteAllBytes(path, bytes)將其導出到圖像文件。
  2. 比較前四個字節與the PNG header

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

參見red question mark loading image as texture with WWW

+1

是的,這部分我已經做了和PNG頭是有......事實證明,不是整個PNG交付,請參閱接受的答案。感謝您的幫助。 – MerlinBG