Search code examples
c#wpfdpipixel-perfect

Wpf Dpi and pixel-perfect WritableBitmap


I have a GPU rendering engine that produces textures. These textures are copied into a WriteableBitmap. This Bitmap is used as an ImageSource in a normal Windows Presentation Foundation view.

Now, I set my dpi to 120, that is, I enabled the 125% font size setting in Windows Control Panel.

Since that change, the WritableBitmap looks really ugly. It is no longer pixel-perfect and looks like badly antialiased (probably because Wpf is stretching it somehow).

I played around with the following settings:

  • This answer describes how to get Dpi from Wpf, and I adjusted the WritableBitmap dpi and Width/Height values accordingly.
  • Disable UseLayoutRounding and enable SnapToDevicePixels in the XAML that contains the image.

But I cannot get it to look good. I am not sure I understand what exactly I have to set to which values in order to get pixel-perfect display. It seems to be there are multiple settings that depend on each other.

A good answer would explain how which settings have to be set in combinations so that it works as expected.


Solution

  • In the xaml, set SnapsToDevicePixels to true.

    In the class that sets up the WritableBitmap, query ActualWidth and ActualHeight. Then multiply those with the scale factors from Dpi (1.25 for dpi 120, etc).

    var width = ActualWidth * _dpi_x_scale;
    var height = ActualHeight * _dpi_y_scale;
    

    I use those width and height value to set the size for the render texture on Gpu.

    When creating the WritableBitmap, also use those scaled width/height but make sure to set the correct dpi:

    _bitmap = new WriteableBitmap(
                width,
                height,
                _dpi_x, 
                _dpi_y,
                PixelFormats.Pbgra32,
                null
                );
    

    This solves the problem.