Graphics.DrawImage意外调整图像大小

时间:2013-08-07 12:16:38

标签: c# .net 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);
        }
    }
}

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

enter image description here enter image description here enter image description here enter image description here

enter image description here enter image description here enter image description here enter image description here

作为最后的澄清,使用的图像应该是相同的(UAT是从我检查到我们的GIT repro中部署的,并且这些图像从未出现过多个版本,所以它不能使用错误的版本。< / p>

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

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

3 个答案:

答案 0 :(得分:9)

   graphic.DrawImage(image, 0, 0);

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

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

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

答案 1 :(得分:1)

可能您遇到 graphics.DpiX graphics.DpiY 的问题,检查两个属性在您的计算机和服务器中是否具有相同的值

答案 2 :(得分:0)

您是否保存并比较了两侧生成的图像?这看起来有点像24位/ 32位颜色问题。

如果您使用此构造函数会发生什么:

公共位图(     整数宽度,     int高度,     PixelFormat格式 )

using (Bitmap newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb))

当我阅读MSDN上的评论时:

Remarks
This constructor creates a Bitmap with a PixelFormat enumeration value of Format32bppArgb.

它应该没有任何区别。