7

我正在根据用户的屏幕分辨率调整一些图像的大小;如果纵横比错误,则应剪切图像。我的代码如下所示:

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

在大多数情况下,这可以正常工作。但是对于某些图像,结果的质量极差。看起来会被调整为非常小的东西(缩略图大小)并再次放大。但图像的分辨率是正确的。我能做些什么?

原始图像示例: 替代文字 http://img523.imageshack.us/img523/1430/naturaerowoods.jpg

调整大小的图像示例: 替代文字

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

4

10 回答 10

8

将方法的最后两行更改为:

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();
于 2009-04-29T20:02:50.940 回答
7

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

于 2009-04-29T19:57:02.607 回答
3

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

有关其他选项,请查看此 CodeProject 文章。具体来说,它会创建一个新图像,为其创建一个图像,Graphics并将插值模式设置为HighQualityBicubic并将原始图像绘制到图形上。至少值得一试。

于 2009-04-29T19:57:35.990 回答
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,尽管您对插值没有任何控制权。

于 2009-04-29T19:57:08.177 回答
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);
于 2012-05-02T06:20:53.993 回答
0

一些相机将调整大小的缩略图放入文件本身,大概是为了在设备本身上进行预览。

GetThumbnail 方法实际上是获取嵌入在图像文件中的缩略图图像,而不是获取更高分辨率的方法。

简单的解决方案是欺骗 .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)));
}
于 2009-09-20T21:52:08.773 回答
0

例如,原始图像为 JPG,调整大小后的图像为 PNG。您是否有意在格式之间进行转换?在不同的有损压缩方案之间切换会导致质量损失。

于 2009-04-29T19:57:11.717 回答
0

调整大小时是增加还是减小图像的大小?如果您从较小的图像创建较大的图像,则可以预料到这种退化。

于 2009-04-29T20:13:40.493 回答
0

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

于 2009-07-18T12:16:47.700 回答
-1

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

  1. 目标分辨率与原始分辨率的“自然”比例的匹配程度
  2. 源图像颜色深度
  3. 图像类型 - 有些比其他有损
于 2009-04-29T19:58:32.917 回答