Charles Petzold

The 96 DPI Solution

November 25, 2005
Utica, NY

In the never-ending quest to achieve device-independent programming under Windows, the Windows Presentation Foundation developers have devised a system in which all coordinates and sizes are in units of 96 dots per inch, called "device-independent units" or sometimes (rather oxymoronically) "device-independent pixels." I will avoid the latter term and sometime abbreviate the former as DIU.

The choice of 96 DPI (rather than, say, 72 DPI or 100 DPI) might seem arbitrary and even perverse only to people who aren't aware that Windows by default assumes a video display resolution of 96 DPI. (Of course, the user can change this assumed display resolution through the Control Panel Display applet, Settings tab, Advanced button, General tab. One common alternative — particularly popular among users prior to the Moon landing — is 120 DPI, which generally increases fonts and other user interface elements by 125%. I believe that 96 DPI was chosen as the default Windows resolution rather than a rounder figure of 100 DPI because 96 DPI is 4/3rds of the one-pixel-per-point resolution of 72 DPI.)

In WPF, you always draw in units of 96 DPI. For example, if you want to create a one-inch square Rectangle object, you make it 96 units wide and 96 units high. If the program runs on a video display set at 96 DPI, the object will be drawn 96 pixels square. In the most common case device-independent units map directly to pixels. If the program runs on a video display set at 120 DPI, the object will be drawn as 120 pixels square. That's a fairly clean 3 units-to-4 pixels mapping.

These device-independent units aren't restricted to graphics programming. They pervade the entire WPF. You use device-independent units to specify sizes of controls, for example. You get mouse coordinates in terms of device-independent units. Device-independent units even show up in system parameters. The beauty of the system is that everything is consistent. It's not like a mapping mode where you have to convert between mouse coordinates in pixels and whatever graphics units you happen to have set. It's an entire consistent world out of which you really can't escape.

The pervasiveness of this coordinate system takes some getting used to. Here, for example, are the values of three static properties of the SystemParameters class obtained under four different Windows sessions with the display resolution set as shown in the column headings:

Property 72 DPI 96 DPI 120 DPI 144 DPI
SystemParameters.PrimaryScreenWidth/Height 1866-2/3 x 1400 1400 x 1050 1120 x 840 933-1/3 x 700
SystemParameters.IconWidth/Height 42-2/3 32 25.6 21-1/3
SystemParameters.CaptionWidth/Height 25-1/3 25 24.8 25-1/3

The video display on which I ran the little program that interrogated these properties is actually 1400 by 1050 pixels. When the Windows display resolution is set to 96 DPI, that's exactly what's reported. That pixel size and resolution implies a metrical size of about 14.6 inches by 10.9 inches. The dimensions of the video display in device-independent units is reported as something different when other display resolutions are set, but the metrical size remains the same.

Icons displayed on the desktop are 32 pixels square regardless of the display resolution. If you have Windows set for 96 DPI, the icon size is reported as 32 device-independent units. As the assumed display resolution goes up, the size of the icons in device-independent units goes down proportionally.

Windows uses a different pixel size of buttons displayed on the caption bar depending on the display resolution. The idea is that the buttons should always have about the same relationship to the default font. In device-independent units, therefore the button size is roughly the same regardless of display resolution, and is always approximately 1/4 inch. It's not exactly the same across display resolutions because these buttons always have an integral pixel size. For example, at a display resolution of 144 DPI, the pixel size is 38, which (multiplied by 2/3) is a DIU size of 25-1/3. For 120 DPI, the pixel size is 31, which (when multiplied by 0.8) is the DIU size of 24.8. For 72 DPI, the pixel size is 19. Multiply by 4/3 for the DIU size of 25-1/3.

I was recently working on a little calculator program where I made square buttons by simply giving them a dimension of 32 by 32 device-independent units. That's 1/3 inch regardless of display resolution, and a comfortable size to accomodate text in the default font.

Where I haven't quite grown accustomed to device-independent units is in specifying font sizes. Font sizes are specified in units of 96 DPI as well, so if you want a 24-point font, you need to increase the point size by 1/3 and specify a FontSize property of 32. Every time I do that, I think that WPF should have used a device-independent coordinate system based on 72 DPI rather than 96 DPI. Of course, a 72 DPI coordinate system has been done before in other graphical environments, but there's no shame in that.

It's not quite clear how this will work with printing. In the November CTP of WPF that we're all running, the entire System.Printing namespace hasn't even a tiny morsel of documentation.