我很早以前就完成了一個通用類來處理.net中的圖片縮放和浮水印等處理,說實話,我從沒關注過其中的畫質問題。直到最近,終於有人給我指出來程式產生的圖片品質不高(他們總是把圖片放大到200%,300%來查看細節)。原圖如下:
現在要縮放使高固定在750px
1. 最早的相關代碼:Bitmap img = new Bitmap(object_width, object_height);
img.SetResolution(72f, 72f);
Graphics gdiobj = Graphics.FromImage(img);
gdiobj.CompositingQuality = CompositingQuality.HighQuality;
gdiobj.SmoothingMode = SmoothingMode.HighQuality;
gdiobj.InterpolationMode = InterpolationMode.HighQualityBicubic;
gdiobj.PixelOffsetMode = PixelOffsetMode.HighQuality;
gdiobj.FillRectangle(new SolidBrush(Color.White), 0, 0,
object_width, object_height);
Rectangle destrect = new Rectangle(0, 0,
object_width, object_height);
gdiobj.DrawImage(this.original_image, destrect, 0, 0, actual_width,
actual_heigh, GraphicsUnit.Pixel);img.Save(outputfilename, System.Drawing.Imaging.ImageFormat.Jpeg);強制以72px解析度來產生jpeg映像,結果用大家的話來說“慘不忍睹”,以下是這張圖片,大小大概100多k從局部細節上可以看出模糊。
2.先跳過網路上常用的GetThumbnailImage方法(最後討論),我先強制產生更高品質的格式呢(比如png和bmp,我這裡用png產生),只要修改最後一行代碼:Bitmap img = new Bitmap(object_width, object_height);
img.SetResolution(72f, 72f);
Graphics gdiobj = Graphics.FromImage(img);
gdiobj.CompositingQuality = CompositingQuality.HighQuality;
gdiobj.SmoothingMode = SmoothingMode.HighQuality;
gdiobj.InterpolationMode = InterpolationMode.HighQualityBicubic;
gdiobj.PixelOffsetMode = PixelOffsetMode.HighQuality;
gdiobj.FillRectangle(new SolidBrush(Color.White), 0, 0,
object_width, object_height);
Rectangle destrect = new Rectangle(0, 0,
object_width, object_height);
gdiobj.DrawImage(this.original_image, destrect, 0, 0, actual_width,
actual_heigh, GraphicsUnit.Pixel);img.Save(outputfilename, System.Drawing.Imaging.ImageFormat.Png);畫質和.net的GetThumbnailImage品質差不多,但是看看大小會昏死1.54mb,而且無論你怎麼定義解析度,都只有72px
3.看來用png是不行了,不然載入時間太長。現在我從原圖中取得圖片資訊再給新圖片導進去Bitmap img = new Bitmap(object_width, object_height);
img.SetResolution(72f, 72f);
Graphics gdiobj = Graphics.FromImage(img);
gdiobj.CompositingQuality = CompositingQuality.HighQuality;
gdiobj.SmoothingMode = SmoothingMode.HighQuality;
gdiobj.InterpolationMode = InterpolationMode.HighQualityBicubic;
gdiobj.PixelOffsetMode = PixelOffsetMode.HighQuality;
gdiobj.FillRectangle(new SolidBrush(Color.White), 0, 0,
object_width, object_height);
Rectangle destrect = new Rectangle(0, 0,
object_width, object_height);
gdiobj.DrawImage(this.original_image, destrect, 0, 0, actual_width,
actual_heigh, GraphicsUnit.Pixel);System.Drawing.Imaging.EncoderParameters ep = new System.Drawing.Imaging.EncoderParameters(1);
ep.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
System.Drawing.Imaging.ImageCodecInfo ici = GetEncoderInfo("image/jpeg");
if (ici != null)
{
img.Save(outputfilename, ici, ep);
}
else
{
img.Save(outputfilename, System.Drawing.Imaging.ImageFormat.Jpeg);
}畫質幾乎沒有得到損失,而且大小成為了568k,這個可以認為是最好的解決方案了。
4.最後再看一個網路上來的方法,這個方法不使用drawimage方法來縮放映像,而是使用.net的縮圖方法來建立(GetThumbnailImage)。System.Drawing.Image thumbnailImage =
original_image.GetThumbnailImage(object_width, object_height, new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);System.Drawing.Bitmap img = new System.Drawing.Bitmap(thumbnailImage);System.Drawing.Imaging.EncoderParameters ep = new System.Drawing.Imaging.EncoderParameters(1);
ep.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
System.Drawing.Imaging.ImageCodecInfo ici = GetEncoderInfo("image/jpeg");
if (ici != null)
{
img.Save(outputfilename, ici, ep);
}
else
{
img.Save(outputfilename, System.Drawing.Imaging.ImageFormat.Jpeg);
}產生的映像547k,畫質和方法3幾乎一樣,局部色彩上略有不同。但這個函數卻有一個致命的問題,如果對下面這張圖進行處理的話,產生的結果是會吐血的,畫質不是一般的糟糕。到底是哪裡出了問題呢,我們看下GetThumbnailImage方法在msdn上的說明:如果 Image 包含一個嵌入式縮圖像,則此方法會檢索嵌入式縮圖,並將其縮放為所需大小。如果 Image 不包含嵌入式縮圖像,此方法會通過縮放主映像建立一個縮圖像。
問題在於原照片上上,如果拿exif工具查看這張照片,你會發覺有一張160 * 120的縮圖包含在這張圖片裡面,因此GetThumbnailImage直接得到了這張縮圖返回了,而且因為我們要定義了大小,他實際上是把那張160*120的縮圖放到我指定的大小後返回了。畫質我們可以想象的到時多糟糕。
參考我在csdn上的文章:http://community.csdn.net/Expert/topic/5425/5425099.xml?temp=.341366http://community.csdn.net/Expert/TopicView.asp?id=5400258