绘制图像时对原始图像进行缩放

7
我正在使用C#中的BitmapSystem.Drawing.Graphics将多个图像在水平和垂直方向上拼接为一个更大的图像(其总宽度和高度为单个图像的宽度和高度之和)。每个图像的大小为256像素乘以256像素。
当我使用System.Drawing.GraphicsDrawImage时,为什么会得到一个缩放或放大后的原始图像?

这是原始图像:

original image


当我以编程方式检索图像并在代码中写入文件时,我会得到以下结果:
var result = httpClient.GetStreamAsync(/* url */);
var bitmap = new Bitmap(await result);
...
using (var memory = new MemoryStream())
{ 
   using (var fs = new FileStream(/* path */, FileMode.OpenOrCreate, FileAccess.ReadWrite))
   {
        bitmap.Save(memory, ImageFormat.Png); // I save to .png if that makes a difference
        var bytes = memory.ToArray();
        await fs.WriteAsync(bytes, 0, bytes.Length);
   }
}

programmatic retrieval of image in code

我看不出任何区别。到目前为止,一切顺利。


然而,当我尝试横向拼接图像时,我得到了以下结果:

注意:参考上面的图片,在下面的拼接图像中它在最右边。

horizontally stitched image

它看起来被缩放、放大,绝不像上面原始的或通过编程检索的单个图像。

这是我用来拼接图像的代码:

注意:如果byWidthtrue,则我会水平拼接图像。

private Bitmap MergeImages(IEnumerable<Bitmap> images, bool byWidth)
{
    var enumerable = images as IList<Bitmap> ?? images.ToList();

    var width = 0;
    var height = 0;

    foreach (var image in enumerable)
    {
        if (byWidth)
        {
            width += image.Width;
            height = image.Height;
        }
        else
        {
            width = image.Width;
            height += image.Height;
        }
    }

    var bitmap = new Bitmap(width, height);
    using (var g = Graphics.FromImage(bitmap))
    {
        var localWidth = 0;
        var localHeight = 0;

        foreach (var image in enumerable)
        {
            if (byWidth)
            {
                g.DrawImage(image, localWidth, 0);
                localWidth += image.Width;
            }
            else
            {
                g.DrawImage(image, 0, localHeight);
                localHeight += image.Height;
            }
        }
    }

    return bitmap;
}
1个回答

17

是的,DrawImage 根据正在绘制的图像的 DPI 设置来缩放图像输出。以 72 DPI 保存的位图图像将被缩放以匹配您绘制它到的屏幕的 96 DPI(或者您实际设置的屏幕的 DPI)。这里的想法是源分辨率(DPI)应该与目标分辨率(DPI)相匹配,以保持分辨率独立性。

令人困惑的是,即使 DrawImageUnscaled 方法也使用此基于 DPI 的缩放逻辑。实际上,这是因为 DrawImageUnscaled 方法只是一个简单的包装器,用于包装 DrawImage 的一个重载方法之一。在概念上,我认为这似乎是一个错误。

无论哪种方式,解决方案很简单:显式地传递所需图像的大小到 DrawImage 调用中。实质上,您正在强制其缩放到所需的大小:

g.DrawImage(img, 0, 0, img.Width, img.Height);

这在KB317174中有部分记录。


只是为了澄清,这是否意味着在调用绘制图像之前,将要添加的图像的水平/垂直分辨率手动设置为目标图像的相同分辨率,可以适当地缩放到给定矩形大小的书写内容? - Noman_1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接