DrawImage 缩放原始图像
DrawImage scales original image
我正在使用 Bitmap
和 [=13 将多张图像垂直和水平拼接在一起以创建一个更大的图像(其中总宽度和高度是各个图像的宽度和高度的总和) =] 在 C# 中。单个图像的大小为 256 像素 x 256 像素。
当我使用 System.Drawing.Graphics
中的 DrawImage
时,为什么我得到的是原始图像的缩放 and/or 放大版本?
这是原图:
当我以编程方式检索图像并用代码写入文件时,我得到以下信息:
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);
}
}
我看不出有什么不同。到目前为止,一切都很好。
但是,当我尝试水平拼接图像时,我得到以下信息:
注意:供参考,上图位于下方拼接图像的最右侧。
它看起来经过缩放、放大,绝对不像上面的原始图像或以编程方式检索的单个图像。
这是我用来将图像拼接在一起的代码:
注意:如果byWidth
是true
,我水平拼接图片。
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;
}
是的,DrawImage
根据所绘制图像的 DPI 设置缩放图像输出。以 72 DPI 保存的位图图像将被缩放以匹配您正在绘制它的屏幕的 96 DPI(或您的屏幕实际设置的任何 DPI)。这里的想法是源分辨率 (DPI) 应该与目标分辨率 (DPI) 相匹配,以保持分辨率独立性。
令人困惑的是,甚至 DrawImageUnscaled
方法也使用这种基于 DPI 的缩放逻辑。实际上,这是因为 DrawImageUnscaled
方法只是 DrawImage
的重载之一的简单包装。从概念上讲,这对我来说似乎是一个错误。
无论哪种方式,解决方案都很简单:将所需的图像大小显式传递给 DrawImage
调用。本质上,您是在强制它缩放到所需的大小:
g.DrawImage(img, 0, 0, img.Width, img.Height);
这在 KB317174 中有准记录。
我正在使用 Bitmap
和 [=13 将多张图像垂直和水平拼接在一起以创建一个更大的图像(其中总宽度和高度是各个图像的宽度和高度的总和) =] 在 C# 中。单个图像的大小为 256 像素 x 256 像素。
当我使用 System.Drawing.Graphics
中的 DrawImage
时,为什么我得到的是原始图像的缩放 and/or 放大版本?
这是原图:
当我以编程方式检索图像并用代码写入文件时,我得到以下信息:
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);
}
}
我看不出有什么不同。到目前为止,一切都很好。
但是,当我尝试水平拼接图像时,我得到以下信息:
注意:供参考,上图位于下方拼接图像的最右侧。
它看起来经过缩放、放大,绝对不像上面的原始图像或以编程方式检索的单个图像。
这是我用来将图像拼接在一起的代码:
注意:如果byWidth
是true
,我水平拼接图片。
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;
}
是的,DrawImage
根据所绘制图像的 DPI 设置缩放图像输出。以 72 DPI 保存的位图图像将被缩放以匹配您正在绘制它的屏幕的 96 DPI(或您的屏幕实际设置的任何 DPI)。这里的想法是源分辨率 (DPI) 应该与目标分辨率 (DPI) 相匹配,以保持分辨率独立性。
令人困惑的是,甚至 DrawImageUnscaled
方法也使用这种基于 DPI 的缩放逻辑。实际上,这是因为 DrawImageUnscaled
方法只是 DrawImage
的重载之一的简单包装。从概念上讲,这对我来说似乎是一个错误。
无论哪种方式,解决方案都很简单:将所需的图像大小显式传递给 DrawImage
调用。本质上,您是在强制它缩放到所需的大小:
g.DrawImage(img, 0, 0, img.Width, img.Height);
这在 KB317174 中有准记录。