代码之家  ›  专栏  ›  技术社区  ›  eflorico

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

  •  6
  • eflorico  · 技术社区  · 16 年前

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

    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 http://img523.imageshack.us/img523/2531/naturaerowoods.png

    注意:我有一个WPF应用程序,但是我使用winforms函数调整大小,因为它更简单,而且我已经需要一个对system.windows.forms的引用作为托盘图标。

    10 回复  |  直到 13 年前
        1
  •  7
  •   BFree    16 年前

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

    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
  •  7
  •   Jan Zich    16 年前

    目前我无法窥视.NET源,但最有可能的问题是 Image.GetThumbnailImage 方法。即使是msdn也说“当请求的缩略图图像的大小约为120 x 120像素时,它工作得很好,但是如果您从具有嵌入缩略图的图像请求一个大的缩略图图像(例如,300 x 300),缩略图图像可能会有明显的质量损失”。要真正调整大小(即不使用缩略图),应使用 Graphics.DrawImage 方法。你可能还需要玩 Graphics.InterpolationMode 如果需要,可以获得更好的质量。

        3
  •  3
  •   Jon Skeet    16 年前

    如果不创建缩略图,请使用名为 GetThumbnailImage 可能不是个好主意…

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

        4
  •  2
  •   Adam Robinson    16 年前

    如所示 MSDN , GetThumbnailImage() 不是为执行任意图像缩放而设计的。超过120x120的应手动缩放。试试这个:

    using(var newImg = new Bitmap(origImg, newWidth, newHeight))
    {
        newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
    }
    

    编辑

    作为澄清的一点,这个超载的 Bitmap 构造函数调用 Graphics.DrawImage 尽管您无法控制插值。

        5
  •  2
  •   nmokkary    13 年前

    代替此代码:

    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);
    
        6
  •  0
  •   James McMahon    16 年前

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

        7
  •  0
  •   TwentyMiles    16 年前

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

        8
  •  0
  •   Photo Resizer    16 年前

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

        9
  •  0
  •   Martin Murphy    15 年前

    有些相机会在文件中放置一个经过调整大小的缩略图,大概是为了在设备上预览。

    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)));
    }
    
        10
  •  -1
  •   GalacticCowboy    16 年前

    这将因以下因素而大不相同:

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