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.
Here's 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.
Here's right:
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:
72.009 72.009
56 10
96 96
56 10
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.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
Seriously though, changing the DPI without warning is messed up...
Like they expect people not to care.
I saw a bunch of Three Letter Abbreviations though ;-)
</pedant>
This typically a bigger problem when dealing with smaller icon size images (16x16).
Since virtually no one has a monitor capable of more than 96 dpi (maybe capable of a little more but not much) I think it is good PNGOUT changes it, this makes it obvious when an image is wasting file size.
Since virtually no one has a monitor capable of more than 96 dpi (maybe capable of a little more but not much) I think it is good PNGOUT changes it, this makes it obvious when an image is wasting file size.
So then, wouldn't the best choice be to work with your designer to get your images as .svg or .wmf files such that you have the vector information on hand? XamlTune does a great job of converting svg files to xaml code. No more DPI problems!
You can meet accessibility concerns with css tricks. My favorite is Leahy/Langridge image replacement (LIR), explained at Stuart Langridge's site.
Another positive vote for PNGGauntlet -- I really like it. I also use optipng on the command-line, which uses a different algorithm. Occasionally running both PNGOUT and optipng can squeeze a few more bytes or KB out of images.
Using these compression tools can also benefit your application's performance. If you're loading a lot of small PNG's, like Paint.NET does in order to populate its toolbars and such, then you can save a good amount of disk I/O. It won't show up on most "warm" benchmarking, but it *really* helps in the "cold" and low-memory states (think of a freshly booted 512MB box, where every page fault is terribly evil).
The 'default' of 96dpi that matters here is actually your operating system, not WPF. Windows XP defaults to 96dpi out of the box, but my XP (for example) is set to 120dpi. So on my system your 96dpi image will still get scaled. In other words you haven't eliminated scaling by marking your image as 96dpi - you've just eliminated it on Windows systems where the OS is set to 96dpi (many but not all).
But WPF is doing the right thing here. If you have an image that is 96 pixels by 96 pixels, and is marked as 96 dpi, that means the image should be displayed as 1 inch by 1 inch, regardless of the hardware dpi. So if your hardware dpi (which WPF gets from the OS) is 120, then the image should be displayed as 120 pixels by 120 pixels, not 96 pixels by 96 pixels.
BTW It's actually pretty awesome when you first run a complex WPF app on a 120 dpi system and notice that everything scales up to the same size as it would be on a 96 dpi system. So everything is the right size, just rendered more 'finely'. The only 'disappointment' is bitmap icons that become blurry when they get scaled - but that's a minor downside in my view, and as others have suggested the best way to overcome that is to use vector icons (though unfortunately WPF has quite poor support for that).
Blurry Bitmaps
TLA is, itself, NOT a Three Letter Acronym.
Not the difference between an Acronym and an Abbreviation.
http://www.merriam-webster.com/dictionary/acronym
Each of the TLAs used is indeed an acronym because it expands to three separate words. Unlike, for example, APT, which is an three letter abbreviation for a single word, apartment.
I would not consider TLA, PNG nor WFP acronyms. They are more specifically initialisms, which is a form of abbreviation. I read out each letter when I speak "T","L","A" so it is an initialism. If you personally pronounce it "tlaaaa" then it's an acronym.
The Merriam-Webster site says if you read it carefully, though this page explains it much more clearly: http://www.lyberty.com/encyc/articles/abbr.html
</BA, English>
But with regards to the actual post, I would side with those suggesting the raster text be replaced, lest you end up doing so later down the line when someone with a 120dpi display complains about a blurry UI.
That was seriously disappointing first WPF experience. That and the fact that Microsoft thinks it's no problem for the text on buttons to blur when the button is pressed (since all text blurs during 'animation'). I never touched WPF again... :-(
if Microsoft really wants to promote WPF, then why doesn't it at least provide the same icons/images in svg (http://en.wikipedia.org/wiki/Scalable_Vector_Graphics) format as well?
Device independence is a lofty goal, but the truth is that many (or dare i say most?) managed (.NET) Windows Apps are written for enterprise users who have standard dpi settings (i.e 96) on their desktop PCs. So in this case the developer of these apps can't care less about dpi. I personally know people who want to move to WPF but gave up after getting stuck by stupid issues like this (and a few others).
On a side note, can anyone point me to a few commercial products with a UI written in Windows Forms or WPF that are being sold at a decent price (well, let's just say over $99) instead of being given away for free?
Pete: I haven’t seen a new 96 PPI display in a long time. :P
From the Pixel density article at Wikipedia:
Typical circa-2000 cathode ray tube or LCD computer displays range from 67 to 130 PPI. The IBM T220/T221 LCD monitors marketed from 2001 to 2005 reached 204 PPI. The Toshiba Portégé G900 Windows Mobile 6 Professional phone, launched in mid 2007, came with a 3" WVGA LCD having "print-quality" pixel density of 313 PPI…
Comments are closed.
PNGOUT should warn about possible data loss, sure the data was in an optional tag; but just because the information does not have to be present doesn't mean it's not important. It mangles [badly] APNG's for example.
PS. That super special awesome secret software looks very Zune client-like, but of course Zune is DirectUI - not WPF....