图像大小调整 - 有时质量很差?

时间:2009-04-29 19:52:01

标签: c# image resize image-scaling

我正在调整一些图像以调整用户的屏幕分辨率;如果宽高比错误,应该剪切图像。 我的代码如下所示:

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

示例已调整大小的图片: alt text

注意:我有一个WPF应用程序,但我使用WinForms函数进行大小调整,因为它更容易,因为我已经需要一个对托盘图标的System.Windows.Forms的引用。

10 个答案:

答案 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)

根据以下因素,这将有很大差异:

  1. 目标分辨率与原始分辨率的“自然”比例的匹配程度
  2. 源图像颜色深度
  3. 图像类型 - 有些比其他类型更有损耗