我有一些代码接受一个 png 图像,它是一个具有透明度的灰度图像,并尝试创建一个具有给定背景颜色(从数据库中查找)的新图像,并在其上覆盖原始图像以创建一个具有高光和阴影的所需颜色的图像。该代码在 ASP.NET 上下文中运行,但我认为这不相关。
该代码在我的本地计算机上运行良好,但是当它被部署到我们的 UAT 服务器时,它给出了意想不到的结果。在 UAT 上,它创建了一个大小合适的图像,但阴影/突出显示区域似乎在每个维度上都缩小了 20%。所以我正在查看的主图像最初是 5x29,输出图像是 5x29,但阴影区域是 4x23.2(第 24 行略有不同,但主要是背景颜色,所以我假设它正在通过调整大小进行一些插值).
我失败的代码如下:
private byte[] GetImageData(CacheKey key)
{
byte[] imageData;
using (Image image = Image.FromFile(key.FilePath))
using (Bitmap newImage = new Bitmap(image.Width, image.Height))
{
using (Graphics graphic = Graphics.FromImage(newImage))
{
using (SolidBrush brush = new SolidBrush(ColorTranslator.FromHtml(key.BackgroundColour)))
{
graphic.FillRectangle(brush, 0, 0, image.Width, image.Height);
}
graphic.DrawImage(image, 0, 0);
/*
The following lines see if there is a transparency mask to create final
transparency. It does this using GetPixel and SetPixel and just modifying
the alpha of newImage with the alpha of mask. I don't think this should make a difference but code below anyway.
*/
Bitmap mask;
if (TryGetMask(key.FilePath, out mask))
{
ApplyMask(newImage, mask);
}
using (var memoryStream = new MemoryStream())
{
newImage.Save(memoryStream, ImageFormat.Png);
imageData = memoryStream.ToArray();
}
}
}
return imageData;
}
private void ApplyMask(Bitmap Bitmap, Bitmap mask)
{
if (mask.Width != Bitmap.Width || mask.Height != Bitmap.Height)
{
throw new ArgumentException("Bitmap sizes do not match");
}
for (int y = 0; y < Bitmap.Height; y++)
{
for (int x = 0; x < Bitmap.Width; x++)
{
Color colour = Bitmap.GetPixel(x, y);
colour = Color.FromArgb(mask.GetPixel(x, y).A, colour);
Bitmap.SetPixel(x, y, colour);
}
}
}
这是我得到的图像(重复四次以更好地展示问题)。第一个是我从本地计算机获取的正确图像。第二个是我的 UAT 服务器出现的问题,它出现了奇怪的“减少 20%”的问题。它们以与此类似的方式用作重复背景,因此您可以看到为什么效果如此明显。这些是用白色背景生成的,以便最容易看到问题。如果有人想要的话,我有其他颜色的类似图片。 :)
作为最后的澄清,所使用的图像应该是相同的(UAT 是根据我检查到我们的 GIT 复制中的内容部署的,并且这些图像的版本从未超过一个,因此它不能使用错误的版本。
我在想,也许底层 GDI 在服务器上做的事情与在我的计算机上做的不同,但我想不出那会是什么或为什么。
对此行为的任何解释或更好的修复将不胜感激。否则,我将不得不去手动逐个像素地完成所有操作,自己进行透明度和覆盖,这看起来有点傻。
最佳答案
graphic.DrawImage(image, 0, 0);
当您使用 DrawImage() 的重载时,这并不奇怪。它将尝试以原始物理 大小显示图像。这受视频适配器的 DPI(每英寸点数)设置的影响。今天非常常见的设置是 96、120 和 144 dpi,使用 Windows 中的显示小程序很容易更改。这些 dpi 值对应于小程序中的 100%、125% 和 150%。
如果您想确保不会发生这种情况并且您获得以像素为单位的准确大小,那么您将需要使用 DrawImage(image, Rectangle) 重载。
请注意物理尺寸很重要。如果您曾经在“视网膜”显示器上使用过您的程序,那一天越来越近了,那么 5x29 像素的图像在那个漂亮的显示器上看起来就像一粒灰尘。制作程序 DpiAware 在过去的 30 年里一直被忽视,但它正变得非常重要。
关于c# - Graphics.DrawImage 意外调整图像大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18103146/