Graphics.DrawImage意外调整图像大小

Chr*_*ris 7 .net c# system.drawing

我有一些代码,它采用带有透明度的灰度图像的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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我得到的图像(重复四次以更好地证明问题).第一个是我从本地计算机获取的正确图像.第二个是从我的UAT服务器出现的问题,该服务器表现出奇怪的"减少了20%"的问题.它们以与此类似的方式用作重复背景,因此您可以看到效果如此明显的原因.这些是使用白色背景生成的,以便最容易看到问题.如果有人想要的话,我有其他颜色的相似图像.:)

在此输入图像描述在此输入图像描述在此输入图像描述在此输入图像描述

在此输入图像描述在此输入图像描述在此输入图像描述在此输入图像描述

作为最后的澄清,使用的图像应该是相同的(UAT是从我检查到我们的GIT repro中部署的,并且从未有过多个版本的这些图像因此它不能使用错误的版本.

我在想,也许底层的GDI在服务器上做的事与在我的电脑上做的不同,但我想不出那是什么或为什么.

对此行为或更好的解决方案的任何解释都将非常感激.否则我将不得不逐个像素地手动执行透明度并覆盖自己,这看起来有点傻.

Han*_*ant 10

   graphic.DrawImage(image, 0, 0);
Run Code Online (Sandbox Code Playgroud)

当你使用DrawImage()的这个重载时,这并不奇怪.它将尝试以原始物理尺寸显示图像.这受视频适配器的DPI(每英寸点数)设置的影响.今天非常常见的设置是96,120和144 dpi,使用Windows中的Display小程序非常容易更改.这些dpi值对应于applet中的100%,125%和150%.

如果你想确保没有发生这种情况并且你得到了像素的确切大小,那么你需要使用DrawImage(图像,矩形)重载.

请注意,物理尺寸很重要.如果你曾经在"视网膜"显示器上使用你的程序,那一天越来越近,那5x29像素的图像看起来会像在那个漂亮的显示器上的灰尘斑点.制作程序DpiAware在过去的30年里一直被忽视,但它变得非常重要.

  • graphics.DrawImage(image, x, y, width, height); (2认同)
  • 您的答案并不完全正确,但解决方案有效。它与视频适配器无关。我在屏幕上什么也没画。我在内存中的另一个位图上绘制了一个位图并调整了它的大小。两个图像都来自磁盘。原因是在图像文件中存储了 DPI 分辨率。我只有一张具有 72 DPI 的图像有这个问题。其他具有 96 DPI 的图像工作正常。您必须为 DrawImage() 提供目标矩形,而不仅仅是目标位置 (X, Y)。我使用 DrawImage(Image, destRect, srcRect, GraphicsUnit.Pixel) 现在它工作得很好。 (2认同)