【问题标题】:Graphics.DrawImage unexpectedly resizing imageGraphics.DrawImage 意外调整图像大小
【发布时间】:2013-08-07 20:54:23
【问题描述】:

我有一些代码采用 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 在服务器上做的事情与在我的电脑上做的事情不同,但我想不出那会是什么或为什么。

对此行为的任何解释或更好的修复将不胜感激。否则我将不得不手动逐个像素地进行透明化并覆盖自己,这似乎有点愚蠢。

【问题讨论】:

    标签: c# .net system.drawing


    【解决方案1】:
       graphic.DrawImage(image, 0, 0);
    

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

    如果您想确保不会发生这种情况并获得以像素为单位的确切大小,那么您需要使用 DrawImage(image, Rectangle) 重载。

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

    【讨论】:

    • 啊,有道理。我曾考虑过 DPI,但认为使用相同的图像这不会是问题。我没想到它可能正在使用服务器设置。感谢您的指点。尽管这听起来像是正确的答案,但我会等待将代码部署到 UAT 并在实际运行之前进行测试。 :)
    • 很好的解决方案。这让我发疯了。
    • graphic.DrawImage(image, x, y, width, height);
    • 您的答案并不完全正确,但解决方案有效。它与视频适配器无关。我在屏幕上什么也没画。我在内存中的另一个位图上绘制了一个位图并调整了它的大小。两个图像都来自磁盘。原因是图像文件中存储了 DPI 分辨率。我只有一张具有 72 DPI 的图像有这个问题。其他具有 96 DPI 的图像可以正常工作。您必须为 DrawImage() 提供目标矩形,而不仅仅是目标位置(X,Y)。我使用 DrawImage(Image, destRect, srcRect, GraphicsUnit.Pixel),现在它可以完美运行了。
    • 好东西。谢谢!
    【解决方案2】:

    也许您的 graphics.DpiXgraphics.DpiY 有问题,请检查这两个属性在您的计算机和服务器中是否具有相同的值

    【讨论】:

    • 看起来是正确的想法,但我认为 Hans 建议不依赖 dpi 是正确的方法。 :) 不过谢谢。
    【解决方案3】:

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

    如果你使用这个构造函数会发生什么:

    公共位图( 整数宽度, 整数高度, 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.
    

    应该没什么区别。

    【讨论】:

    • msdn.microsoft.com/en-us/library/vstudio/… 建议我使用的构造函数“创建一个 PixelFormat 枚举值为 Format32bppArgb 的位图”,所以我看不出使用您的代码行有什么帮助。您能否澄清一下您所说的 24 位/32 位颜色问题是什么意思?
    • 会不会是服务器平台不支持? msdn.microsoft.com/en-us/library/…
    • 这个答案是完全错误的! 24bit/32bit 只影响透明度(alpha 通道)它与问题无关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-07
    • 2011-09-11
    • 2015-02-27
    • 1970-01-01
    • 2012-10-03
    • 1970-01-01
    相关资源
    最近更新 更多