4

I am using a DrawingContext to draw images. I then render the result to a RenderTargetBitmap. I also render a Canvas to the same RenderTargetBitmap. Even though the pixel boundaries are crisp on screen, they become blurred and fuzzy when saved.

In the screenshot below, you can see the issue (with BitmapScalingMode = NearestNeighbor). enter image description here

Here it is with BitmapScalingMode = HighQuality. It's smoother but not crisp and clean. enter image description here

Here is the relevant section of my code. You can see that I tried setting the RenderOptions at multiple places but it seems to have no effect.

        DrawingVisual drawingVisual = new DrawingVisual();
        RenderTargetBitmap result = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);

        RenderOptions.SetBitmapScalingMode(drawingVisual, BitmapScalingMode.NearestNeighbor);   // This forces the scaling to be on even-pixel boundaries
        RenderOptions.SetBitmapScalingMode(drawCanvas, BitmapScalingMode.NearestNeighbor);  // This forces the scaling to be on even-pixel boundaries
        RenderOptions.SetBitmapScalingMode(result, BitmapScalingMode.NearestNeighbor);  // This forces the scaling to be on even-pixel boundaries

        using (DrawingContext context = drawingVisual.RenderOpen()) {
            context.DrawRectangle(Brushes.Black, null, new Rect(new Point(), new Size(size.Width, size.Height)));

            if (layers.Count >= 1 && layers[0].LayerImage != null && layers[0].LayerImage.Source != null && gridImage.Children[1].Visibility == System.Windows.Visibility.Visible)
                context.DrawImage(layers[0].LayerImage.Source, new Rect(size)); // Draw first image.

            context.Close();
        }

        result.Render(drawingVisual);

        drawCanvas.Measure(drawCanvas.RenderSize);
        drawCanvas.Arrange(new Rect(drawCanvas.RenderSize));

        for (int i = 0; i < drawCanvas.Children.Count; i++) {
            RenderOptions.SetBitmapScalingMode(drawCanvas.Children[i], BitmapScalingMode.NearestNeighbor);  // This forces the scaling to be on even-pixel boundaries
        }

        result.Render(drawCanvas);

        BitmapEncoder encoder = new PngBitmapEncoder();
        if (result!= null) {
            encoder.Frames.Add(BitmapFrame.Create((BitmapSource)result));
            encoder.Save(fileStream);
        }
nb1forxp
  • 385
  • 2
  • 14

2 Answers2

0

I don't know if you have fixed that but that function works very good on my side.

    public BitmapSource SnapShotPNG(UIElement source)
    {
        double actualWidth = source.RenderSize.Width;
        double actualHeight = source.RenderSize.Height;

        RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)actualWidth, (int)actualHeight, 96, 96, PixelFormats.Pbgra32);


        DrawingVisual visual = new DrawingVisual();

        using (DrawingContext context = visual.RenderOpen())
        {
            VisualBrush sourceBrush = new VisualBrush(source);
            context.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(actualWidth, actualHeight)));
        }
        source.Measure(source.RenderSize); //Important
        source.Arrange(new Rect(source.RenderSize)); //Important

        renderTarget.Render(visual);

        try
        {
            return new CroppedBitmap(renderTarget, new Int32Rect(0, 0, (int)actualWidth, (int)actualHeight));
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
    }
gmetax
  • 3,853
  • 2
  • 31
  • 45
  • Thanks! I'll give it a try. – nb1forxp Feb 07 '16 at 18:41
  • not yet, sorry! my code has been reformatted since I put up the post, so I need to deconvolute it to figure out how to test your function. Stay tuned! – nb1forxp Feb 10 '16 at 14:42
  • I've been using something similar for a while, but had to actually run measure + arrange with 1 pixel bigger for width and height, and then run it again at the correct size. If you see any weirdness with things not rendering then try that [sic] – Simon_Weaver Jul 28 '19 at 03:37
-1
 public static BitmapSource CaptureScreen(this UIElement visualElement, int? desiredLongestEdge = null)
    {
        double scale = 1;
        if (desiredLongestEdge.HasValue)
        {
            if (visualElement.RenderSize.Width > visualElement.RenderSize.Height)
            {
                scale = desiredLongestEdge.Value/ visualElement.RenderSize.Width;
            }
            else
            {
                scale = desiredLongestEdge.Value / visualElement.RenderSize.Height ;
            }
        }

        var targetBitmap =
                     new RenderTargetBitmap(
                        (int) Math.Ceiling(scale * (visualElement.RenderSize.Width + 1)),
                         (int) Math.Ceiling(scale * (visualElement.RenderSize.Height + 1)),
                                                       scale * 96,
                                                       scale * 96,
                                                        PixelFormats.Pbgra32);

        visualElement.Measure(visualElement.RenderSize); //Important
        visualElement.Arrange(new Rect(visualElement.RenderSize)); //Important

        targetBitmap.Render(visualElement);

        return targetBitmap;
    }
Andreas
  • 3,843
  • 3
  • 40
  • 53