【问题标题】:Image resizing - sometimes very poor quality?图像大小调整 - 有时质量很差?
【发布时间】:2010-10-22 16:25:42
【问题描述】:

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

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 的引用来获取托盘图标。

【问题讨论】:

  • 感谢您提出这个问题!这个问题现在仍然存在......

标签: c# image resize image-scaling


【解决方案1】:

将方法的最后两行改为:

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】:

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 他们只是嫉妒你的史诗般的知识乔恩忽略他们
    【解决方案4】:

    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】:

      代替这段代码:

      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】:

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

        【讨论】:

        • 我想将图片用作壁纸,为此我必须将其转换为 BMP,因为 Win XP 不接受任何其他格式的壁纸。
        【解决方案7】:

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

        【讨论】:

        • 他的两张图片似乎表明原件更大。
        【解决方案8】:

        图片放大肯定会变质。

        【讨论】:

          【解决方案9】:

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

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

            【讨论】:

              猜你喜欢
              • 2012-11-30
              • 2021-02-15
              • 1970-01-01
              • 2012-12-05
              • 1970-01-01
              • 1970-01-01
              • 2014-02-17
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多