2009-12-07 93 views
10

我在.NET中遇到圖像縮放問題。我用的是標準的顯卡類型來調整圖像就像這個例子:C#調整大小的圖像有黑色邊框

public static Image Scale(Image sourceImage, int destWidth, int destHeight) 
{ 
     Bitmap toReturn = new Bitmap(sourceImage, destWidth, destHeight); 

     toReturn.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); 

     using (Graphics graphics = Graphics.FromImage(toReturn)) 
     { 
      graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; 
      graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; 
      graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 
      graphics.DrawImage(sourceImage, 0, 0, destWidth, destHeight); 
     } 
     return toReturn; 
    } 

但是我有縮放後的圖像一個很大的問題:他們有灰色和黑色邊框,並做出有圖像,而他們這是非常重要的。

他們爲什麼會出現,我能做些什麼使他們消失?

樣本輸出:

sample output

+2

請問HTML看起來這是什麼發送到瀏覽器這些圖像? – DOK 2009-12-07 17:01:33

+2

圖像的原始類型是什麼? – 2009-12-07 17:02:17

+2

發佈您的輸入圖像 – 2009-12-07 17:06:06

回答

6

嘗試:

graphic.CompositingMode = CompositingMode.SourceCopy; 
+4

不幸的是,這是沒有解決方案。它沒有效果。灰色邊框不斷產生。如果它適用於OP,那麼僅僅是出於意外。解決方案在於指定圖像屬性,正如在這個答案中指出的那樣:http://stackoverflow.com/questions/2319983/resizing-an-image-in-asp-net-without-losing-the-image-quality/2324414# 2324414 – 2011-03-23 15:29:29

+3

@Developer Art,你的源碼是24位還是32位的alpha?使用alpha調整圖像大小將導致沿着邊緣的半透明像素;通過設置這種模式,這些像素將與背景混合,否則它們與黑色混合從而導致邊界。我不知道24位圖像會發生什麼。 – 2011-03-23 15:40:26

+1

@Mark Ransom,看到我的回答,你有部分權利,但沒有給出正確的解決方案。 – Jeroen 2011-08-07 17:14:08

2

如何爲你做下面的工作?這是我用來做同樣事情的代碼。我注意到的主要區別是我沒有使用SetResolution(我假設有一個方形輸入和輸出,因爲這是我的情況)。

/// <summary> 
/// Resizes a square image 
/// </summary> 
/// <param name="OriginalImage">Image to resize</param> 
/// <param name="Size">Width and height of new image</param> 
/// <returns>A scaled version of the image</returns> 
internal static Image ResizeImage(Image OriginalImage, int Size) 
{ 
    Image finalImage = new Bitmap(Size, Size); 

    Graphics graphic = Graphics.FromImage(finalImage); 

    graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed; 
    graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed; 
    graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; 

    Rectangle rectangle = new Rectangle(0, 0, Size, Size); 

    graphic.DrawImage(OriginalImage, rectangle); 

    return finalImage; 
} 
+2

他從頭開始創建一個默認的黑色背景的圖像。您正在加載可能沒有背景的圖片。 – Jeroen 2011-08-07 17:19:36

3

這是因爲採樣是從照片的邊緣拍攝的。

1

這是因爲繪製圖像時邊緣的平滑(與背景混合)。

你可以畫兩次,一次沒有,一次使用平滑。或者你可以把它拉大一點。或者如果原始背景顏色是已知的,則可以先用背景顏色填充圖像。

+0

@Downvoter,我真的很感激評論,說爲什麼我的答案是如此不合適或不好... – Lucero 2012-01-03 23:46:53

5

問題在於這樣一個事實:你的位圖toReturn默認有一個黑色的背景。 在其上覆制新圖像會形成黑色或灰色邊框。

的解決方法是刪除了黑色默認背景,通過調用:

toReturn.MakeTransparent(); 

由於這一行,你會一個新的形象沒有任何背景色邊框將消失被牽拉之後。

7

這可能是由錯誤內插邊緣周圍的像素造成的。我會稱這是一個錯誤。

這裏的解決方案,但:

graphics.CompositingMode = CompositingMode.SourceCopy; 
graphics.PixelOffsetMode = PixelOffsetMode.Half; 
graphics.InterpolationMode = InterpolationMode.NearestNeighbor; 

// Draw your image here. 

graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 

// Draw it again. 

這樣做是先繪製一個「背景」與邊緣的正確填充,然後用插值重新繪製。如果你不需要插值,那麼這是沒有必要的。

+0

這解決了很多麻煩。非常感謝你! – Tillito 2013-04-12 09:11:03

+0

@Tillito沒有問題:)請注意,儘管這是有效的,但並非最優化的解決方案,性能明智。除非你有一個非常大的圖像,或者你正在做一個自定義組件分發,重用等等,你可能需要一些更復雜的方法來解決這個問題,比如使用[lock bits ](http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.lockbits.aspx)和「手動」繪圖/插值。 – 2013-04-13 00:16:23

6

真正的解決方案是使用DrawImage的超載,它允許您傳遞ImageAttributes對象。

ImageAttributes實例,它傳遞給DrawImage之前調用下面的方法:

using (var ia = new ImageAttributes()) 
{ 
    ia.SetWrapMode(WrapMode.TileFlipXY); 
    aGraphic.DrawImage(..., ia); 
} 

參見this answer

+0

這對我來說非常合適。謝謝。 – user892381 2013-12-06 18:20:38

+0

這是這個問題的真正解決方案。 – kaiyaq 2015-03-04 01:00:59

+0

我一直在嘗試解決這個問題約3小時。這個答案是唯一有效的。我希望這是可以接受的解決方案。 – Andy 2016-12-27 03:29:08

1

這些都不爲我工作。

然而,改變從

System.Drawing.Imaging.PixelFormat.Format24bppRgb 

的格式

System.Drawing.Imaging.PixelFormat.Format32bppArgb 

解決了問題

using (System.Drawing.Bitmap newImage = new System.Drawing.Bitmap(newWidth, newHeight, 
       // System.Drawing.Imaging.PixelFormat.Format24bppRgb // OMG bug 
        System.Drawing.Imaging.PixelFormat.Format32bppArgb 
       )) 
      { 
0

一個正確的答案可以從一些其他反應的拼湊在一起,但沒有一個是完整的,有些提出了一些非常糟糕的想法(如兩次繪製圖像)。

原因有三對您看到的構件:

  1. 默認Graphics.PixelOffsetMode設置導致的像素值被錯誤地採樣,從而導致圖像的輕度變形,特別是在邊緣周圍。
  2. InterpolationMode.HighQualityBicubic從圖像邊緣以外採樣像素,默認情況下它們是透明的。這些透明像素通過採樣器與邊緣像素混合,產生半透明邊緣。
  3. 當您以不支持透明度的格式(例如JPEG)保存半透明圖像時,透明值將被替換爲黑色。

這些都加起來就是半黑(即灰色)的邊緣。

刪除這些工件的正確方法是使用PixelOffsetMode.Half並使用ImageAttributes對象指定邊緣平鋪,以便HighQualityBicubic採樣器具有除透明像素以外的其他樣本。

還有一些其他問題的代碼你張貼的:

您使用的是通過調整原始圖像大小初始化新Bitmap,所以你在做調整操作兩次Bitmap構造函數。您應該使用僅具有所需維度的構造函數重載來創建空白畫布。

請記住,Bitmap類表示內存中圖像的非託管副本。它需要進行處理,以便GDI +在完成後可以被告知釋放該內存。我假設你在接收返回Image的代碼中這樣做,但我指出,以防其他人借用此代碼。

代碼中使用的CompositingQuality.HighQuality設置將不會產生視覺效果,如果其他設置正確並且實際上會嚴重影響性能並結合默認值CompositingMode.SourceOver。您可以省略CompositingQuality設置並設置CompositingMode.SourceCopy以獲得相同的結果並獲得更好的性能。

代碼中使用的SmoothingMode設置對DrawImage()根本沒有影響,因此可以將其刪除。

你可以閱讀更多關於Graphics類設置及其對圖像質量和性能在這裏的影響:http://photosauce.net/blog/post/image-scaling-with-gdi-part-3-drawimage-and-the-settings-that-affect-it

修改後的代碼應該是這個樣子:

public static Image Scale(Image sourceImage, int destWidth, int destHeight) 
{ 
    var toReturn = new Bitmap(destWidth, destHeight); 

    using (var graphics = Graphics.FromImage(toReturn)) 
    using (var attributes = new ImageAttributes()) 
    { 
     toReturn.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); 

     attributes.SetWrapMode(WrapMode.TileFlipXY); 

     graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 
     graphics.PixelOffsetMode = PixelOffsetMode.Half; 
     graphics.CompositingMode = CompositingMode.SourceCopy; 
     graphics.DrawImage(sourceImage, Rectangle.FromLTRB(0, 0, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, attributes); 
    } 

    return toReturn; 
}