Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
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.
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.
–
–
–
Did you save and compared the generated images on both side? This looks a bit like a 24bit/32bit color problem.
What happens if you use this constructor:
public Bitmap(
int width,
int height,
PixelFormat format
using (Bitmap newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb))
As i read the remarks on MSDN:
Remarks
This constructor creates a Bitmap with a PixelFormat enumeration value of Format32bppArgb.
It shouldn't make any difference.
–
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.