我正在调整一些图像以调整用户的屏幕分辨率;如果宽高比错误,应该剪切图像。 我的代码如下所示:
protected void ConvertToBitmap(string filename)
{
var origImg = System.Drawing.Image.FromFile(filename);
var widthDivisor = (double)origImg.Width / (double)System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
var heightDivisor = (double)origImg.Height / (double)System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
int newWidth, newHeight;
if (widthDivisor < heightDivisor)
{
newWidth = (int)((double)origImg.Width / widthDivisor);
newHeight = (int)((double)origImg.Height / widthDivisor);
}
else
{
newWidth = (int)((double)origImg.Width / heightDivisor);
newHeight = (int)((double)origImg.Height / heightDivisor);
}
var newImg = origImg.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero);
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
}
在大多数情况下,这很好用。但对于某些图像,结果的极质量差。它似乎已被调整为非常小(缩略图大小)的东西并再次放大..但图像的分辨率是正确的。我该怎么办?
示例原始图片: alt text http://img523.imageshack.us/img523/1430/naturaerowoods.jpg
注意:我有一个WPF应用程序,但我使用WinForms函数进行大小调整,因为它更容易,因为我已经需要一个对托盘图标的System.Windows.Forms的引用。
答案 0 :(得分:7)
目前我无法查看.NET源代码,但很可能问题出在Image.GetThumbnailImage
方法中。甚至MSDN都说“当请求的缩略图图像的大小约为120 x 120像素时效果很好,但是你从具有嵌入式缩略图的图像中请求一个大的缩略图图像(例如,300 x 300),在缩略图中明显损失质量“。要进行真正的大小调整(即不是缩略图),您应该使用Graphics.DrawImage
方法。如果需要,您可能还需要使用Graphics.InterpolationMode
来获得更好的质量。
答案 1 :(得分:7)
将方法的最后两行更改为:
var newImg = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(newImg);
g.DrawImage(origImg, new Rectangle(0,0,newWidth,newHeight));
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
g.Dispose();
答案 2 :(得分:3)
如果您没有创建缩略图,使用名为GetThumbnailImage
的方法可能不是一个好主意......
有关其他选项,请查看this CodeProject article。特别是,它会创建一个新图像,为其创建Graphics
并将插值模式设置为HighQualityBicubic
并将原始图像绘制到图形上。值得一试,至少。
答案 3 :(得分:2)
如MSDN所示,GetThumbnailImage()
并非旨在进行任意图像缩放。任何超过120x120的东西都应该手动缩放。试试这个:
using(var newImg = new Bitmap(origImg, newWidth, newHeight))
{
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
}
修改强>
作为澄清的一点,Bitmap
构造函数的这个重载调用了Graphics.DrawImage
,尽管你没有对插值的任何控制。
答案 4 :(得分:2)
代替此代码:
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
使用这个:
System.Drawing.Imaging.ImageCodecInfo[] info = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
System.Drawing.Imaging.EncoderParameters param = new System.Drawing.Imaging.EncoderParameters(1);
param.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
newImg.Save(dest_img, info[1], param);
答案 5 :(得分:0)
例如,原始图像是JPG,调整大小的图像是PNG。你是故意转换格式吗?在不同的lossey压缩方案之间切换会导致质量损失。
答案 6 :(得分:0)
调整大小时是增加还是减小图像的大小?如果要从较小的图像创建较大的图像,则可以预期会出现这种降级。
答案 7 :(得分:0)
如果放大图像肯定会降级。
答案 8 :(得分:0)
有些相机会将调整大小的缩略图放入文件中,大概是为了预览设备本身。
GetThumbnail方法实际上获取了此缩略图图像,该图像嵌入在图像文件中,而不是获得更高的res方法。
简单的解决方案是在调整大小或其他操作之前欺骗.Net丢弃缩略图信息。像这样....
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
//removes thumbnails from digital camera shots
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
如果你试图调整约束比例,我在System.Drawing.Image上编写了一个你可能会觉得很方便的扩展方法。
/// <summary>
///
/// </summary>
/// <param name="img"></param>
/// <param name="size">Size of the constraining proportion</param>
/// <param name="constrainOnWidth"></param>
/// <returns></returns>
public static System.Drawing.Image ResizeConstrainProportions(this System.Drawing.Image img,
int size, bool constrainOnWidth, bool dontResizeIfSmaller)
{
if (dontResizeIfSmaller && (img.Width < size))
return img;
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
float ratio = 0;
ratio = (float)img.Width / (float)img.Height;
int height, width = 0;
if (constrainOnWidth)
{
height = (int)(size / ratio);
width = size;
}
else
{
width = (int)(size * ratio);
height = size;
}
return img.GetThumbnailImage(width, height, null, (new System.IntPtr(0)));
}
答案 9 :(得分:-1)
根据以下因素,这将有很大差异: