Device‑Independent Graphics
Device‑independent graphics (DIG) enable applications to render content consistently across displays with varying pixel densities. By abstracting the physical pixel size, you can create UI that scales gracefully on high‑DPI monitors, tablets, and mixed‑density environments.
Overview
DIG works by defining logical units (device‑independent pixels) that are automatically scaled to the underlying device's DPI. In Windows, the standard logical unit is 1/96th of an inch. This section explains the concepts, APIs, and best practices for using DIG in modern Windows applications.
Key Principles
- Logical Units: Use logical pixels (dip) instead of physical pixels.
- DPI Scaling: Let the system apply the appropriate scaling factor.
- Vector Graphics: Prefer vector‑based resources (e.g., SVG, XAML Path) for crisp rendering.
- High‑Resolution Assets: Provide @2x, @3x assets for bitmap resources.
DPI Awareness in Windows
Declare DPI awareness in your manifest or via SetProcessDpiAwarenessContext to opt‑in to per‑monitor scaling:
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware>true</dpiAware>
<dpiAwareness>PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
Programmatic approach (C++):
#include <windows.h>
int main()
{
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
// Application initialization…
return 0;
}
Using DIG in WPF
WPF automatically uses device‑independent units. Ensure you set UseLayoutRounding="True" and SnapsToDevicePixels="True" for crisp edges.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="DIG Demo"
Width="400"
Height="300"
UseLayoutRounding="True"
SnapsToDevicePixels="True">
<Canvas Background="White">
<Rectangle Width="200" Height="100" Fill="LightBlue"
Canvas.Left="50" Canvas.Top="50"/>
</Canvas>
</Window>
Sample Code (C#)
Drawing a DPI‑aware ellipse using Windows.Graphics APIs:
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Shapes;
using Windows.Graphics.Display;
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
var displayInfo = DisplayInformation.GetForCurrentView();
var scale = displayInfo.RawPixelsPerViewPixel; // e.g., 2.0 on 200% DPI
var ellipse = new Ellipse
{
Width = 100 * scale,
Height = 100 * scale,
Fill = new SolidColorBrush(Windows.UI.Colors.CornflowerBlue)
};
Canvas.SetLeft(ellipse, 50 * scale);
Canvas.SetTop(ellipse, 50 * scale);
MyCanvas.Children.Add(ellipse);
}
}