Be Aware of DPI with Image PNGs in WPF - Images Scale Weird or are Blurry
Is that enough TLAs (Three Letter Acronyms) in the title there? I continue to mentally deny the existence of DPI (dots per inch) as a concept. It's my own fault. I have been living on PCs at 96dpi for so many years, I just stopped caring. This problem we ran into is SO obvious after the fact, but it flummoxed us for a half-hour.
I've been helping a buddy on a super-cool super secret WPF application and the window has multiple states - regular, compact, and minimized. We've got three transparent PNGs for these three buttons. The designer created them and sent them along.
However, with one of them, it kept showing up at the wrong size, and was blurry. Even if we set the width and height ourselves, it looked totally wrong.
Unrelated to the scaling issue, I saw that the file was 3099 bytes, which I thought was a little large. I opened it up in the Visual Studio binary hex editor and noticed that I could see strings like "Photoshop ICC profile" in the header. PNGs are lossless (they are like Bitmaps, not JPEGs) and while they compress, there are may ways they can compress, like removing crap from headers.
I like to run PNGOUT on all my PNGs as it'll try different techniques to make the PNG as small as possible without losing any data (without changing the way the PNG looks). I ran PNGOUT on the wrong file and it went from 3099 bytes to 292 bytes. It also just happened it look right afterwards.
So why did it look right suddenly? Turns out that PNGOUT also changes the DPI, without asking, to 96dpi. Here's a little C# program I wrote to test:
static void Main(string args)
Image i = Image.FromFile(@"c:\users\scott\desktop\collapse-wrong.png");
Console.WriteLine(i.HorizontalResolution + " " + i.VerticalResolution);
Console.WriteLine(i.Width + " " + i.Height);
Image i2 = Image.FromFile(@"c:\users\scott\desktop\collapse.png");
Console.WriteLine(i2.HorizontalResolution + " " + i2.VerticalResolution);
Console.WriteLine(i2.Width + " " + i2.Height);
The output of this is:
Both files are 56x10 in dimension, but the first is 72.009 dpi and the second is 96 dpi. WPF defaults to 96 dpi so when it encounters the 72 dpi image it scales it up. If you can't change the image, there are funky ways around it. Personally, I believe if you are running into this because of a designer/developer mismatch, then just coordinate between each other and decide on a DPI, probably 96. In our case, DPI didn't really matter as the designer was developing pixel-accurate images, so we just run PNGOUT on all the images.
I usually run PNGOUT from Powershell, but there is a nice free .NET app called PNGGaunlet from Ben Hollis that provides a nice GUI frontend.