Apps that ignore per-display scale go blurry or misaligned on high-DPI screens
Aliases: DPI unaware · high-DPI blur · logical-pixel mismatch
What it is
An app paints into a backing buffer at 96 DPI; the OS then stretches that whole buffer onto a 200% screen. Type goes soft, hairlines become two-pixel smudges, and hit areas stay where they were before the stretch. DPI-unaware failure is blur and misalignment on a high-density display: the pixels people see and the rectangles the system hit-tests are not the same coordinate system. This is not the procedure for looking up a scale, and not the question of whether an icon file should be swapped. It is the two failure looks users actually get when the app does not perceive per-display scale.
Why it happens
An unaware app draws and hit-tests in logical pixels; the OS can only take that already-painted image and enlarge it as a bitmap. Enlargement is blur: each source pixel becomes a same-color block, and glyph edges lose alignment with screen pixels. Misalignment is a second coordinate system: if hit-testing still uses the unscaled window rect while the compositor has stretched the picture, the cursor hotspot sits on empty space or on a neighbor. A second kind of misalignment needs no stretch: the app mixes physical and logical pixels, strokes a “1-pixel” border in physical units that nearly vanishes at 200%, or strokes in logical units and hit-tests in physical ones, shifting the hot zone by a whole factor. Blur is undersampling; misalignment is two units that were never unified. They can co-occur and they repair differently.
Where it stops holding
On an exact integer stretch (200%), some icons remain readable by luck, and people file the blur as “a bit off” rather than broken; non-integer scales (125%, 150%) interpolate dirtier, and complaints concentrate there. Text already re-rasterized by the system at the per-screen ratio may look sharp while icons stay mushy—do not take “the type is fine” as proof the whole window is aware. On a low-density screen, unaware and correct look the same; the problem only appears on high-DPI. Full-screen exclusive apps that paint at the physical resolution and skip the desktop compositor do not get this stretch-blur, then show it the moment they window.
Applying it
- Declare per-monitor awareness and paint text and vectors at the current screen’s scale; do not let the system stretch the whole window as a bitmap.
- Draw and hit-test in one logical space, then multiply once by the current screen ratio to get physical pixels; never let some code write logical and some write physical.
- Align 1-logical-pixel hairlines to the physical pixel grid so they do not sit between two physical pixels and turn into a gray band.
- Verify: open the app on a 200% screen and check whether glyphs and hairlines are soft; walk the cursor along a button edge one physical pixel at a time and see whether the hot zone matches the visible border. Drag the window to a 100% screen and confirm there is no reverse “hot zone too large, picture too small.” Log blur and misalignment separately: the former from screenshot edges, the latter from click coordinates.
Related
- Within the group: K2.08.1 Apps must read each display's scale, not a system-wide value · K2.08.2 Bitmaps must reload at the destination display's resolution when moved · K2.08.4 Font size and spacing conversions accumulate error under mixed resolutions
- Adjacent: K2.02 Multiple Displays · A1.16 Visual angle and size conversion
- Search terms:
DPI unaware·bitmap stretch·logical versus physical pixels