2012-07-10 41 views
3

我已經編寫了一些代碼來從我的Blogger博客導入內容。一旦我下載了所有的HTML內容,我就會瀏覽圖片標籤並下載相應的圖片。在很多情況下,System.Drawing.Bitmap.FromStream拋出一個ArgumentException。我從下載的網址看起來很不錯,並按照預期提供了一張圖片(以下是其中一張問題圖片的網址:http://4.bp.blogspot.com/_tSWCyhtOc38/SgIPcctWRZI/AAAAAAAAAGg/2LLnVPxsogI/s1600-h/IMG_3590.jpg)。ArgumentException從流中實例化位圖

private static System.Drawing.Image DownloadImage(string source) 
    { 
     System.Drawing.Image image = null; 

     // used to fetch content 
     var client = new HttpClient(); 

     // used to store image data 
     var memoryStream = new MemoryStream(); 

     try 
     { 
      // fetch the image 
      var imageStream = client.GetStreamAsync(source).Result; 

      // instantiate a system.drawing.image from the data 
      image = System.Drawing.Bitmap.FromStream(imageStream, false, false); 

      // save the image data to a memory stream 
      image.Save(memoryStream, image.RawFormat); 
     } 
     catch (IOException exception) 
     { 
      Debug.WriteLine("{0} {1}", exception.Message, source); 
     } 
     catch (ArgumentException exception) 
     { 
      // sometimes, an image will link to a web page, resulting in this exception 
      Debug.WriteLine("{0} {1}", exception.Message, source); 
     } 
     catch (AggregateException exception) 
     { 
      // sometimes, an image src will throw a 404 
      Debug.WriteLine("{0} {1}", exception.Message, source); 
     } 
     finally 
     { 
      // clean up our disposable resources 
      client.Dispose(); 
      memoryStream.Dispose(); 
     } 

     return image; 
    } 

任何想法爲什麼一個ArgumentException在這裏被拋出?

編輯:發生,我認爲這可能是一個代理髮行,所以我增加了以下到我的web.config:

<system.net> 
    <defaultProxy enabled="true" useDefaultCredentials="true"> 
    <proxy usesystemdefault="True" /> 
    </defaultProxy> 
</system.net> 

並稱部分並沒有作出任何區別,但是。

編輯:此代碼從EF數據庫初始值設定項的上下文中調用。這裏有一個堆棧跟蹤:

Web.dll Web.Models.Initializer.DownloadImage(字符串源)234線C# Web.dll Web.Models.Initializer.DownloadImagesForPost.AnonymousMethod__5(HtmlAgilityPack.HtmlNode標籤)線! 126 + 0x8字節C# [External Code] Web.dll!Web.Models.Initializer.DownloadImagesForPost(Web.Models.Post post)119+ 0x34 bytes C# Web.dll!Web.Models.Initializer.Seed(Web .Models.FarmersMarketContext上下文)線320 + 0XB字節C# [外部代碼] App_Web_l2h4tcej.dll!ASP._Page_Views_Home_Index_cshtml.Execute()線28個+ 0×15字節C# [外部代碼]

+0

你確定圖像的來源始終是一個有效的URI嗎?有時它可能是一個相對地址,這對Blogger路徑有意義,但不能使用HttpClient進行檢索。 – 2012-07-10 14:27:24

+0

好吧,我剛剛讀完你的整個問題,對於無用的評論抱歉。 – 2012-07-10 14:27:51

+0

一個Stacktrace將有助於查明原因,但關閉我的頭頂,我會建議'imageStream'在某種程度上是畸形的。 – xiy 2012-07-10 14:31:18

回答

4

好的,我找到了問題。事實證明,在某些情況下,Blogger會引用呈現圖片的HTML頁面,而不是引用圖片本身。所以,這種情況下的迴應不是有效的圖像。我已經添加了代碼來檢查響應頭,然後嘗試保存圖像數據,並解決了問題。對於別人的誰打這個問題上的利益,這裏的更新代碼:

private static System.Drawing.Image DownloadImage(string source) 
    { 
     System.Drawing.Image image = null; 

     // used to fetch content 
     var client = new HttpClient(); 

     // used to store image data 
     var memoryStream = new MemoryStream(); 

     try 
     { 
      // Blogger tacks on a -h to an image Url to link to an HTML page instead 
      if (source.Contains("-h/")) 
       source = source.Replace("-h/", "/"); 

      // fetch the image 
      var response = client.GetAsync(source).Result; 
      response.EnsureSuccessStatusCode(); 

      var contentType = response.Content.Headers.ContentType.MediaType; 

      if (!contentType.StartsWith("image/")) 
      { 
       Debug.WriteLine(contentType); 
       throw new ArgumentException("Specified source did not return an image"); 
      } 

      var imageStream = response.Content.ReadAsStreamAsync().Result; 

      // instantiate a system.drawing.image from the data 
      image = System.Drawing.Bitmap.FromStream(imageStream, true, true); 

      // save the image data to a memory stream 
      image.Save(memoryStream, image.RawFormat); 
     } 
     catch (HttpRequestException exception) 
     { 
      // sometimes, we'll get a 404 or other unexpected response 
      Debug.WriteLine("{0} {1}", exception.Message, source); 
     } 
     catch (IOException exception) 
     { 
      Debug.WriteLine("{0} {1}", exception.Message, source); 
     } 
     catch (ArgumentException exception) 
     { 
      // sometimes, an image will link to a web page, resulting in this exception 
      Debug.WriteLine("{0} {1}", exception.Message, source); 
     } 
     finally 
     { 
      // clean up our disposable resources 
      client.Dispose(); 
      memoryStream.Dispose(); 
     } 

     return image; 
    } 
+0

。在這種情況下,您可以輕鬆鑽研響應並從中挖掘圖像。 Upvote偵探工作:] – xiy 2012-07-10 15:19:33

1

您正在處理另一個問題,我想你意外固定它。不幸的是,GDI +的例外情況不是很好,他們通常不會告訴你真正的問題是什麼。

Image.FromStream()實現中一個不明確的花絮是GDI +在從流中加載位圖時使用流的Seek()方法。然而,只有當流允許尋找時,這纔會奏效,其CanSeek屬性必須返回true。這通常不是網絡流的情況,沒有提供足夠的緩衝來允許任意的查找。

這與HttpClient.GetStreamAsync()的一個問題,它的MSDN庫文件說:

這種方法不緩衝流

雖然工作版本,你寫的用途HttpContent。ReadAsStreamAsync(),它的MSDN Library文檔說:

返回後,所有的內容任務目標將完成已寫爲一個字節數組

所以,你的第一個版本不因爲工作流的CanSeek屬性是錯誤的,第二個版本的工作原理是整個響應被讀入允許查找的字節數組中。通用的解決方案是首先將流傳輸到MemoryStream中。

+0

謝謝,漢斯。這很可能是一個問題,儘管不是我正在琢磨的問題。如果這確實是一個問題,我會期望其他圖像也會失敗。 – 2012-07-12 03:03:25