2009-10-17 56 views
3

我有這樣的方法萎縮下來了網站的形象,我的工作:調整圖像GDI +圖形.NET

static byte[] createSmallerImage(
    BlogPhoto blogPhoto, 
    int newMaxWidth, 
    int newMaxHeight) 
{ 
    Image img; 
    using (MemoryStream originalImage = 
      new MemoryStream(blogPhoto.BlogPhotoImage)) 
    { 
    img = Image.FromStream(originalImage); 
    } 

    int newWidth; 
    int newHeight; 
    byte[] arr; 

    if (img.Width > img.Height) 
    { 
    if (img.Width <= newMaxWidth) 
    { 

     using (MemoryStream thumbStr = new MemoryStream()) 
     { 
     img.Save(thumbStr, ImageFormat.Jpeg); 
     img.Dispose(); 
     arr = thumbStr.ToArray(); 
     } 
     return arr; 
    } 

    newWidth = newMaxWidth; 
    newHeight = 
     (int)(((float)newWidth/(float)img.Width) * (float)img.Height); 
    } 
    else 
    { 
    if (img.Height <= newMaxHeight) 
    { 

     using (MemoryStream thumbStr = new MemoryStream()) 
     { 
     img.Save(thumbStr, ImageFormat.Jpeg); 
     img.Dispose(); 
     arr = thumbStr.ToArray(); 
     } 
     return arr; 
    } 

    newHeight = newMaxHeight; 
    newWidth = 
     (int)(((float)newHeight/(float)img.Height) * (float)img.Width); 
    } 

    Image thumb = new Bitmap(newWidth, newHeight); 

    Graphics g = Graphics.FromImage(thumb); 
    g.InterpolationMode = InterpolationMode.HighQualityBicubic; 
    g.SmoothingMode = SmoothingMode.HighQuality; 
    g.PixelOffsetMode = PixelOffsetMode.HighQuality; 
    g.CompositingQuality = CompositingQuality.HighQuality; 

    g.DrawImage(img, 0f, 0f, (float)newWidth, (float)newHeight); 


    using (MemoryStream thumbStr = new MemoryStream()) 
    { 
    thumb.Save(thumbStr, ImageFormat.Jpeg); 
    arr = thumbStr.ToArray(); 
    } 

    g.Dispose(); 
    img.Dispose(); 

    return arr; 
} 

大多數它的偉大工程,但有時它給了我這個例外的時候: GDI +發生一般性錯誤。錯誤代碼-2147467259。來源:「System.Drawing」。這發生在Image.Save上(...我試圖讓這個代碼儘可能防禦,但是仍然沒有得到什麼導致這個,如果有人知道答案是好的,那麼批評也是受歡迎的

+0

您是否嘗試保存到您加載的同一個文件? –

+0

blogPhoto.BlogPhotoImage是從linq-to-sql檢索到的一個字節[ – maxfridbe

回答

2

看看在Image.FromStream的文檔()

http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx

你需要保持流打開圖像的壽命。保持第一個MemoryStream打開時間更長,並且它應該工作。

+2

底層的GDI +圖像類不需要流保持打開,這非常奇怪。 (http://msdn.microsoft.com/en-us/library/ms535371.aspx)但是通過反射器搜索,我終於明白爲什麼:他們必須將.NET Stream包裝成適合GDI +的IStream。接口是引用計數,而.NET Stream對象則不是。由於它們只將流對象封裝在一個新的接口中,而不是複製實際的數據,所以必須保留源對象。 –

0

我不知道有什麼可以發生,但也許較少MemoryStreams問題消失:?

using (Image original = Image.FromStream(new MemoryStream(blogPhoto))) 
{ 
    using (MemoryStream thumbData = new MemoryStream()) 
    { 
     int newWidth; 
     int newHeight; 
     if ((original.Width <= newMaxWidth) || 
      (original.Height <= newMaxHeight)) 
     { 
      original.Save(thumbData, ImageFormat.Jpeg); 
      return thumbData.ToArray(); 
     } 

     if (original.Width > original.Height) 
     { 
      newWidth = newMaxWidth; 
      newHeight = (int)(((float)newWidth/
       (float)original.Width) * (float)original.Height); 
     } 
     else 
     { 
      newHeight = newMaxHeight; 
      newWidth = (int)(((float)newHeight/
       (float)original.Height) * (float)original.Width); 
     } 

     //original.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero) 
     // .Save(thumbData, ImageFormat.Jpeg); 
     //return thumbData.ToArray(); 

     using (Image thumb = new Bitmap(newWidth, newHeight)) 
     { 
      Graphics g = Graphics.FromImage(thumb); 
      g.InterpolationMode = InterpolationMode.HighQualityBicubic; 
      g.SmoothingMode = SmoothingMode.HighQuality; 
      g.PixelOffsetMode = PixelOffsetMode.HighQuality; 
      g.CompositingQuality = CompositingQuality.HighQuality; 
      g.DrawImage(original, 0f, 0f, (float)newWidth, (float)newHeight); 
      thumb.Save(thumbData, ImageFormat.Jpeg); 
     } 
    } 
} 
+0

]我很困惑這是如何工作的,因爲你是這樣調用的:img.Save(imageSource,ImageFormat.Jpeg); 和thumb.Save(imageSource,ImageFormat.Jpeg); 然後返回imageSource.ToArray(); 不會導致內存流中的兩個圖像? – maxfridbe

+0

對不起,我的錯誤;你能依靠GetThumbnailImage來完成你的工作嗎?我剛剛更新了我的答案以使用此方法。 –

+0

我想我可以(如果這個錯誤仍然存​​在,我可以嘗試),但規範說: 當請求的縮略圖圖像的大小約爲120 x 120像素時,GetThumbnailImage方法效果很好。如果您從具有嵌入式縮略圖的圖像請求較大的縮略圖圖像(例如,300 x 300),縮略圖圖像中可能會出現明顯的質量損失。通過調用DrawImage方法來縮放主圖像(而不是縮放嵌入的縮略圖)可能會更好。 這可能不適合我創建更大的縮略圖。 – maxfridbe

1

有一點要看看是blogPhoto和基礎數據要離開它從哪裏獲得從裝上膛從一個流?該流在createSmallerImage之前關閉了嗎?從流關閉的流加載的圖像在95%的時間內工作,並且僅偶爾拋出一個通用的GDI +錯誤

+0

BlogPhotoImage是從linq-to-sql加載的延遲加載byte []。 – maxfridbe

+0

您是直接加載還是從MemoryStream加載?調用createSmallerImage之前有沒有機會超出範圍? –

5

我個人使用此代碼,沒有流(我不關心perfs,雖然)調整大小的圖片:

public Image resizeImage(int newWidth, int newHeight, string stPhotoPath) 
{ 
    Image imgPhoto = Image.FromFile(stPhotoPath); 

    int sourceWidth = imgPhoto.Width; 
    int sourceHeight = imgPhoto.Height; 

    //Consider vertical pics 
    if (sourceWidth < sourceHeight) 
    { 
     int buff = newWidth; 

     newWidth = newHeight; 
     newHeight = buff; 
    } 

    int sourceX = 0, sourceY = 0, destX = 0, destY = 0; 
    float nPercent = 0, nPercentW = 0, nPercentH = 0; 

    nPercentW = ((float)newWidth/(float)sourceWidth); 
    nPercentH = ((float)newHeight/(float)sourceHeight); 
    if (nPercentH < nPercentW) 
    { 
     nPercent = nPercentH; 
     destX = System.Convert.ToInt16((newWidth - 
       (sourceWidth * nPercent))/2); 
    } 
    else 
    { 
     nPercent = nPercentW; 
     destY = System.Convert.ToInt16((newHeight - 
       (sourceHeight * nPercent))/2); 
    } 

    int destWidth = (int)(sourceWidth * nPercent); 
    int destHeight = (int)(sourceHeight * nPercent); 


    Bitmap bmPhoto = new Bitmap(newWidth, newHeight, 
       PixelFormat.Format24bppRgb); 

    bmPhoto.SetResolution(imgPhoto.HorizontalResolution, 
      imgPhoto.VerticalResolution); 

    Graphics grPhoto = Graphics.FromImage(bmPhoto); 
    grPhoto.Clear(Color.Black); 
    grPhoto.InterpolationMode = 
     InterpolationMode.HighQualityBicubic; 

    grPhoto.DrawImage(imgPhoto, 
     new Rectangle(destX, destY, destWidth, destHeight), 
     new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), 
     GraphicsUnit.Pixel); 

    grPhoto.Dispose(); 
    return bmPhoto; 
} 

希望這有助於。