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

问题描述 投票:6回答:10

我正在调整一些图像到用户的屏幕分辨率;如果宽高比错误,应该剪切图像。我的代码看起来像这样:

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引用。

c# image resize image-scaling
10个回答
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();

-1
投票

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

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

7
投票

我目前无法窥探.NET源代码,但很可能问题出在Image.GetThumbnailImage方法中。甚至MSDN都说“当请求的缩略图图像的大小约为120 x 120像素时效果很好,但是你从具有嵌入式缩略图的图像请求一个大的缩略图图像(例如,300 x 300),在缩略图中明显损失质量“。要进行真正的大小调整(即不是缩略图),您应该使用Graphics.DrawImage方法。如果需要,您可能还需要使用Graphics.InterpolationMode以获得更好的质量。


3
投票

如果您没有创建缩略图,使用名为GetThumbnailImage的方法可能不是一个好主意......

有关其他选项,请查看this CodeProject article。特别是,它创建一个新图像,为它创建一个Graphics并将插值模式设置为HighQualityBicubic并将原始图像绘制到图形上。值得一试,至少。


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,尽管你没有对插值的任何控制。


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);

0
投票

例如,原始图像是JPG,调整大小的图像是PNG。你是故意转换格式吗?在不同的lossey压缩方案之间切换会导致质量损失。


0
投票

调整大小时是增加还是减小图像的大小?如果要从较小的图像创建较大的图像,则会出现这种降级。


0
投票

如果放大图像肯定会降级。


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)));
}
© www.soinside.com 2019 - 2024. All rights reserved.