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

发布于 2024-07-18 04:33:03 字数 1579 浏览 9 评论 0 原文

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

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< /a>

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

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

I'm resizing some images to the screen resolution of the user; if the aspect ratio is wrong, the image should be cut.
My code looks like this:

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

In most cases, this works fine. But for some images, the result has an extremely poor quality. It looks like the would have been resized to something very small (thumbnail size) and enlarged again.. But the resolution of the image is correct. What can I do?

Example orig image:
alt text http://img523.imageshack.us/img523/1430/naturaerowoods.jpg

Example resized image:
alt text

Note: I have a WPF application but I use the WinForms function for resizing because it's easier and because I already need a reference to System.Windows.Forms for a tray icon.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

浅忆流年 2024-07-25 04:33:03

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

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

Change the last two lines of your method to this:

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();
捶死心动 2024-07-25 04:33:03

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

I cannot peek into the .NET source at the moment, but most likely the problem is in the Image.GetThumbnailImage method. Even MSDN says that "it works well when the requested thumbnail image has a size of about 120 x 120 pixels, but it you request a large thumbnail image (for example, 300 x 300) from an Image that has an embedded thumbnail, there could be a noticeable loss of quality in the thumbnail image". For true resizing (i.e. not thumbnailing), you should use the Graphics.DrawImage method. You may also need to play with the Graphics.InterpolationMode to get a better quality if needed.

顾北清歌寒 2024-07-25 04:33:03

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

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

If you're not creating a thumbnail, using a method called GetThumbnailImage probably isn't a good idea...

For other options, have a look at this CodeProject article. In particular, it creates a new image, creates a Graphics for it and sets the interpolation mode to HighQualityBicubic and draws the original image onto the graphics. Worth a try, at least.

在你怀里撒娇 2024-07-25 04:33:03

MSDN 所示, GetThumbnailImage() 并非旨在进行任意图像缩放。 任何超过 120x120 的内容都应手动缩放。 请尝试以下操作:

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

Edit

需要澄清的是,尽管您没有任何控制权,但 Bitmap 构造函数的重载会调用 Graphics.DrawImage超过插值。

As indicated on MSDN, GetThumbnailImage() is not designed to do arbitrary image scaling. Anything over 120x120 should be scaled manually. Try this instead:

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

Edit

As a point of clarification, this overload of the Bitmap constructor calls Graphics.DrawImage, though you do not have any control over the interpolation.

葬花如无物 2024-07-25 04:33:03

而不是这个代码:

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

instead of this code:

newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);

use this one :

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);
翻身的咸鱼 2024-07-25 04:33:03

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

For examples, the original image is JPG and the resized image is PNG. Are you converting between formats on purpose? Switching between different lossey compression schemes can cause quality loss.

木槿暧夏七纪年 2024-07-25 04:33:03

调整图像大小时是增大还是减小图像的大小? 如果您要从较小的图像创建较大的图像,这种降级是可以预料的。

Are you increasing or decreasing the size of the image when you resize it? If you are creating a larger image from a smaller one, this sort of degradation is to be expected.

紫﹏色ふ单纯 2024-07-25 04:33:03

如果放大图像肯定会降低质量。

Images will definitely be degraded if you enlarge them.

梦巷 2024-07-25 04:33:03

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

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

Some camera's put a resized thumbnail into the file itself presumably for preview purposes on the device itself.

The GetThumbnail method actually gets this Thumbnail image which is embedded within the image file instead of getting the higher res method.

The easy solution is to trick .Net into throwing away that thumbnail information before doing your resize or other operation. like so....

img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
//removes thumbnails from digital camera shots
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);

If you are attempting to resize constraining proportions I wrote an extension method on System.Drawing.Image that you might find handy.

/// <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)));
}
浮世清欢 2024-07-25 04:33:03

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

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

This is going to vary widely based on the following factors:

  1. How closely the destination resolution matches a "natural" scale of the original resolution
  2. The source image color depth
  3. The image type(s) - some are more lossy than others
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文