Search code examples
c#.netwpfwindowsgdi

WPF Bitmap Image drawn using System.Drawing.Graphics is blurred when screen resolution is low


I have a Bitmap drawn using System.Drawing.Graphics which is used to show a print preview. It is looking like this on low resolution screens (or if I changed the resolution in my pc in settings).

Blurry image

But in a higher resolution (1920 * 1080) it is displayed correctly. Like this:

Expected image

XAML looks like this:

`<Border BorderBrush="Gray"
     BorderThickness="1"
     Margin="5"
     DockPanel.Dock="Top">
     <ScrollViewer VerticalScrollBarVisibility="Auto"
                   Width="300"
                   BorderThickness="0">
                   <Border Padding="20">
                       <Image Source="{Binding ImageSource}" />
                   </Border>
     </ScrollViewer>
 </Border>`

ViewModel code to set the image source looks like this:

`var height = CalculateHeight();

 var bitmap = new Bitmap(previewWidth, height);
 using (var g = Graphics.FromImage(bitmap))
 {
      _printService.PrintSalesOrder(g, Order, new Rectangle
      {
           X = 0,
           Y = 0,
           Width = previewWidth,
           Height = height
      });
 }

 _hBitMap = bitmap.GetHbitmap();

 var bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
       _hBitMap, // you will need to delete this hbitmap
       IntPtr.Zero,
       Int32Rect.Empty,
       BitmapSizeOptions.FromWidthAndHeight(previewWidth, height));

 ImageSource = bitmapSource;`

I tried the following:

  1. Setting UseLayoutRounding="True" in the MainWindow
  2. Setting RenderOptions.BitmapScalingMode="NearestNeighbor" in the image element

Edit:

I tried setting RenderOptions.BitmapScalingMode="Fant" in Image element (suggested by @Fixation) but it did not fix the problem.


Solution

  • I'm guessing your problem is caused by unintended downscaling of the image.

    I would try setting Stretch="None", that should ensure the image is displayed in at least 1:1 pixel resolution. Note that this might cause the image to become larger, i.e. in inches/mm on the screen. You might also need to set the dpi of the image, but I think it should default to 96 dpi that is the common resolution in windows.

    If that does not work I would try PrintSalesOrder with a simple g.DrawString("test");, just to eliminate one potential source of problems. I would also set height/previewWidth to a fixed values, since the CalculateHeight function may do something that depend on the resolution of the screen.

    Also note that the display resolution will be affected by the UI scaling in windows, but that is mostly a concern with high resolution screen, where images are Scaled up to maintain the same physical size. I do not think it should be a factor here, but I would still make sure that both screens are configured to 100% UI scaling.