我很早以前就完成了一个通用类来处理.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.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.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);
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);
}
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);
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);
}
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的缩略图放到我指定的大小后返回了。画质我们可以想象的到时多糟糕。
问题在于原照片上上,如果拿exif工具查看这张照片,你会发觉有一张160 * 120的缩略图包含在这张图片里面,因此GetThumbnailImage直接得到了这张缩略图返回了,而且因为我们要定义了大小,他实际上是把那张160*120的缩略图放到我指定的大小后返回了。画质我们可以想象的到时多糟糕。
参考我在csdn上的帖子: