.NET Image DPI Scaling Problems

.NET Image DPI Scaling Problems

Today I noticed that the buttons in my Windows forms app were being scaled. As you can see from the image below there is a ghosting around the edges of the lines which isn’t in the original image.

I eventually tracked this down to DPI scaling issues. I’m drawing the image using DrawImage:

 System.Windows.Forms.Graphics.DrawImage

The graphics object has a correct DPI of 96, but the image DPI is 95.91039. This incorrect DPI value is what is causing the scaling.

e.Graphics.DpiY = 96
image.VerticalResolution = 95.91039

The image was created in Paint.NET so that was the first thing to check. The DPI settings can be found in the resize dialog, and it was indeed wrong.

The DPI in Paint.NET settings is correctly set to 96 so it is unclear why the DPI has been set incorrectly. So, simple fix, just change it to 96 and re-save right? Wrong. Reloading the image in Paint.NET now shows 95.99 DPI. Close but still not right. Interestingly GIMP appears to have similar accuracy problem with displaying and loading/saving the DPI. Even after this change, loading the image in .NET still shows a DPI of 95.91039.

A quick python script shows that the DPI is actually correct:

from PIL import Image
image = Image.open("ScopeColourModeButton.png")
print(str(image.info['dpi']))

Just to be sure let’s try re-saving the file:

image.save("ScopeColourModeButton.png", dpi=(96,96))

Unfortunately this doesn’t help either. It appears that the png is at the correct DPI (or close enough with whatever rounding is going on). The problem lies with the .NET Image class. I assume that this is a bug in the image loading code when the image is embedded into the resources file.

The only work-around I could find was to forcibly change the DPI before displaying the image

 public static Image To96Dpi(Image image) public static Image To96Dpi(Image image) { if (image != null)
 {
     Bitmap bitmap = (Bitmap)image; bitmap.SetResolution(96.0f, 96.0f); image = bitmap; }
     return image;
 }
...
Image image = Utils.To96Dpi(Properties.Resources.ScopeColourModeButton);

This fixes the problem and now my button images are pixel perfect!

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: