Unlike any version of Windows before it, Windows 8.1 exposes the actual pixel density of the display for you to take advantage of in code. In this post, we’ll talk about a few techniques for using pixel density, some of the code to use it in your app.
All the screens
One of the best things about Windows, is the choice of devices that people have to buy. Maybe a small Dell Venue, a do-everything Surface Pro 2, or big workhorse Dell XPS All-in-one. Maybe all three? Each of these devices has a different screen, and each of these screens has a different number of pixels. This is great because you can choose the perfect device for you, for the right price, battery life, visual crispness, thickness, and weight.
How many pixels in an inch?
Knowing the pixel density of your screen in a very cool thing. It let’s your code know how big things are in the real world in a language it can understand, pixels. This lets you do things that wouldn’t be possible without some sort of awkward calibration UI. Here are a few examples:
- Draw a ruler on screen so you can measure stuff with your tablet
- Show a bunch of weird insects at actual size
- Draw a button exactly the size of the average finger, no bigger, no smaller
- Show different UI when you’re on a TV or a tablet even though they have the same resolution.
- Make text more comfortably readable on small screens
Why I care
I’m super excited about this because in my previous life as a PM on the Windows team, we did a ton of work to plumb the display information provided in the driver EDID all the way up to the user-mode code so we can build the dynamic high-DPI scaling features in Windows 8 (See more in this post I wrote on Scaling to different screens). In Windows 8.1 the team has gone the last mile so you can use this in your app.
Lies, damned lies, and DPI
If every screen is a different size, with a different number of pixels, how does your app know how big an inch is? Your answer might be, “Simple, just use one of those DPI properties that have been around forever.” But you’d be wrong. DPI and PPI are some of the most incorrectly used terms out there, especially in API design.
Eight APIs that lie about giving you pixels per inch:
Don’t get me wrong, each of these APIs is useful for many scenarios related to the pixel density of the screen. Like if you should load a higher resolution image when your app is zoomed. None of these APIs, however, give you any information about the actual physical size of the display. They only give you a number that lets you calculate how much your app is zoomed.
Enter RawXDPI and RawYDPI
Windows 8.1 introduces Windows.Graphics.Display.DisplayInformation.RawXDPI and RawYDPI. These ones are actually the droids you’ve been looking for. I can’t imagine trying to name this API, I’m surprised it’s not TheRealDPIPleaseStandup since so many of the other properties are so convincingly named.
Pixel density and logical pixels
RawDPI tells you how many native pixels there are in every physical inch. This would be cool, but apps may be zoomed in in order to automatically make things big enough to touch or read, so one of your CSS or XAML (logical) pixels might be several native pixels. So the first thing you need to calculate is the number of logical pixels in a physical inch.
<span class="kwrd">var</span> info = Windows.Graphics.Display.DisplayInformation.getForCurrentView();
<span class="kwrd">var</span> logicalPPI = info.rawDpiX / info.resolutionScale / 100;
How do I draw an inch
You can just start using that logicalPPI value right away. In this case I’ll just make a DIV an inch wide.
<span class="rem">// Resize the div to be an inch square</span>
inchDiv.style.width = logicalPPI + <span class="str">"px"</span>;
inchDiv.style.height = logicalPPI + <span class="str">"px"</span>;
How big is the screen
If you want to figure out the size of the screen’s diagonal, just dust off a little high school math.
<span class="kwrd">var</span> screenSizeX = window.screen.width / logicalPPI;
<span class="kwrd">var</span> screenSizeY = window.screen.height / logicalPPI;
<span class="kwrd">var</span> screenSize = Math.sqrt(Math.pow(screenSizeX, 2) +
Real Ruler: an app that uses pixel density
Whenever I find a new API or system capability that I want to try out, I make an app! So I decided to make “Real Ruler.” It’s basically like all the other ruler apps in the Windows 8 store except this one is the only one (so far) that doesn’t need calibration. I use the pixel density to draw the inches at the right size on the edge of the screen, and I measure how many inches between your fingers when you put them both on the screen.
Get the code
I published all the code for Real Ruler on github, go ahead and download if you want to make Real Centimeter Ruler.
Update: Don’t forget about projectors
Don’t forget to handle projectors and other screens that don’t expose screen size. Read how in this post: Handle projectors when using actual size in your app.