Graphics.DrawImage意外调整图像 [英] Graphics.DrawImage unexpectedly resizing image

查看:116
本文介绍了Graphics.DrawImage意外调整图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些code,需要一个PNG这是一个灰度图像的透明度,并试图创建一个具有给定的背景颜色(从数据库中查找)的新形象,并覆盖原始图像就可以了创建所需要的色彩搭配亮点和阴影的图像。在code运行在一个ASP.NET环境,但我不认为这是相关的。

在code正常工作,我的本地计算机上,但是当它被部署到我们的UAT服务器时,它提供了意想不到的效果。在UAT它创造合适尺寸的图像,但阴影/高光区域似乎已经缩小在每个维度了20%。所以,我期待在主图像最初是5x29,输出图像为5x29,但阴影区域是4x23.2(第24行是非常略有不同,但主要的背景颜色,所以我认为这是做一些插值与调整大小)。

我的code表示失败如下:

 专用字节[] GetImageData(CacheKey键)
{
    byte []的为imageData;
    使用(形象画像= Image.FromFile(key.FilePath))
    使用(位图newImage =新位图(image.Width,image.Height))
    {
        使用(图形图形= Graphics.FromImage(newImage))
        {
            使用(SolidBrush刷=新SolidBrush(ColorTranslator.FromHtml(key.BackgroundColour)))
            {
                graphic.FillRectangle(刷,0,0,image.Width,image.Height);
            }
            graphic.DrawImage(图像,0,0);

            / *
            下面的几行看看​​有没有透明度屏蔽创造的最终
             透明度。它这样做是使用getPixel和SetPixel,只是修改
             newImage的阿尔法与面罩的alpha。我不认为这应该低于反正有差别,但code。
            * /

            位图面膜;
            如果(TryGetMask(key.FilePath,出面具))
            {
                ApplyMask(newImage,掩模);
            }


            使用(VAR的MemoryStream =新的MemoryStream())
            {
                newImage.Save(MemoryStream的,ImageFormat.Png);
                为imageData = memoryStream.ToArray();
            }
        }
    }
    返回为imageData;
}

私人无效ApplyMask(位图位图,位图蒙)
{
    如果(mask.Width!= Bitmap.Width || mask.Height!= Bitmap.Height)
    {
        抛出新的ArgumentException(位图大小不匹配);
    }
    对于(INT Y = 0; Y< Bitmap.Height; Y ++)
    {
        为(中间体X = 0 X  - 其中; Bitmap.Width; X ++)
        {
            色色= Bitmap.GetPixel(X,Y);
            颜色= Color.FromArgb(mask.GetPixel(X,Y).A,颜色);
            Bitmap.SetPixel(X,Y,颜色);
        }
    }
}
 

下面是我收到的图像(重复4次,以更好地说明问题)。首先是正确的图像,因为我从我的本地计算机上获取。第二个是从我的UAT服务器对出现奇怪的降低20%的问题转向了。他们正在使用类似的方式来这是一个重复的背景,所以你可以看到为什么效果那么明显。这些被使用白色背景生成的,使之最容易看到的问题。我有类似的图像在其他的颜色,如果有人想他们。 :)

随着最后澄清使用应该是相同的图像(UAT是从我住进了GIT摄制部署和从未有过这些图像的多个版本,因此它不能使用了错误的版本。

我想,也许下面的GDI是做一些不同服务器上的比我的计算机上,但我不认为这是什么会是为什么。

或任何解释这种行为的更好的修复将是最AP preciated。否则我将不得不通过像素去做到这一切手动像素做的透明度和覆盖自己似乎有点傻。

解决方案

  graphic.DrawImage(图像,0,0);
 

在使用此重载的DrawImage的这不是奇怪的()。它会尝试在原来的物理的大小来显示图像。这是由DPI(每英寸点数)的视频适配器的设置影响。很常见的设置今天96,120和144 dpi时,很容易改变与Windows中的显示小程序。这些DPI值符合100%,125%和150%,在小程序。

如果你想确保不会发生这种情况,你会得到像素的确切大小,那么你就需要使用的DrawImage(图像,矩形)的过载。

请注意,物理尺寸问题。如果你使用你的程序上的视网膜显示屏,这天是越来越近了,那么5x29像素的图像是要看看,但像灰尘不错的显示上的雀斑。制作程序DpiAware已被忽略过去30年,但它越来越成为非常重要的。

I've got some code that takes a png that is a greyscale image with transparency and attempts to create a new image that has a given background colour (looked up from a database) and overlays the original image on it to create an image of the required colour with highlights and shading. The code is run in an ASP.NET context but I don't think that is relevant.

The code works fine on my local computer but when it is deployed to our UAT server it gives unexpected results. On the UAT it creates an image of the right size but the shaded/highlighted area seems to have been shrunk in each dimension by 20%. So the main image that I am looking at is initially 5x29 and the output image is 5x29 but the shaded area is 4x23.2 (the 24th row is very slightly different but mainly the background colour so I assumed it is doing some interpolation with the resize).

My code that is failing is as follows:

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);
        }
    }
}

Here are the images I am getting (repeated four times to better demonstrate the issue). The first is the correct image as I am getting from my local computer. The second is what is turning up from my UAT server which is exhibiting the strange "reduced by 20%" issue. They are being used in a similar way to this as a repeating background so you can see why the effect is so noticeable. These were generated with a white background to make it easiest to see the issue. I've got similar images in other colours if anybody wants them. :)

As final clarification the images being used should be identical (the UAT was deployed from what I checked into our GIT repro and there has never been more than one version of these images so it can't be using the wrong version.

I am thinking that maybe the underlying GDI is doing something different on the server than on my computer but I can't think what that would be or why.

Any explanations for this behaviour or better yet fixes would be most appreciated. Otherwise I'm going to have to go and do it all manually pixel by pixel doing the transparency and overlay myself which seems a bit silly.

解决方案

   graphic.DrawImage(image, 0, 0);

It's not that strange when you use this overload of DrawImage(). It will try to display the image at the original physical size. Which is affected by the DPI (dots per inch) setting of the video adapter. Very common settings today are 96, 120 and 144 dpi, very easy to change with the Display applet in Windows. These dpi values correspond with 100%, 125% and 150% in the applet.

If you want to make sure this does not happen and you get the exact size in pixels then you'll need to use the DrawImage(image, Rectangle) overload.

Do note that physical size matters. If you ever use your program on a "retina" monitor, that day is getting closer and closer, then that 5x29 pixel image is going to look but like a fleck of dust on that nice display. Making programs DpiAware has been ignored for the past 30 years but it is getting to be very important.

这篇关于Graphics.DrawImage意外调整图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆