c bunker
c bunker

Reputation: 55

Rendering WPF to PNG produces blank image

I am trying to render a figure to a PNG using WPF (rather than the old GDI API) and the result is always blank.

I am writing a small program that will produce images routes around a warehouse to various items. I am using WPF API for drawing rather than the old GDI API as the images need to be both saved to disk and displayed within a WPF application. The problem is that all of the png files that it produces are currently entirely black.

To reduce the scope of the problem and prove that it was not a problem with code for drawing the map I made a minimal test method that should simply render a red circle on a black background. However the result is still an entirely black.

    [TestMethod]
    public void DrawingTest()
    {
        //define the dimensions of the test image
        int width = 100;
        int height = 100;
        int dpi = 100;

        //define where the image should be saved
        var path = @"C:\temp\DrawingTest.png";

        //create a bitmap to render the image into
        RenderTargetBitmap bitmap = new RenderTargetBitmap(
                    width, height, dpi, dpi, PixelFormats.Default);

        //create a drawing context to draw the image onto
        DrawingVisual drawingVisual = new DrawingVisual();
        using (DrawingContext canvas = drawingVisual.RenderOpen())
        {
            //draw a circle  
            canvas.DrawEllipse(Brushes.Red, new Pen(Brushes.Red, 1), new System.Windows.Point(50, 50), 50, 50);

            //render the image into a bitmap
            bitmap.Render(drawingVisual);
        }

        //create the file encoder
        var encoder = new PngBitmapEncoder();
        //encode the bitmap in PNG format
        encoder.Frames.Clear();
        encoder.Frames.Add(BitmapFrame.Create(bitmap));

        //make sure that the file can be saved in this location
        var directory = System.IO.Path.GetDirectoryName(path);
        if (!System.IO.Directory.Exists(directory))
            System.IO.Directory.CreateDirectory(directory);
        if (System.IO.File.Exists(path))
            System.IO.File.Delete(path);

        //save the map to file
        using (var stream = System.IO.File.Create(path))
            encoder.Save(stream);
    }

The test method runs without any errors and produces a png file at the location that I expected. However, this file is simply a black square rather than the red circle in a black square that I was expecting. Can anybody tell me why it is just rendering a black image, and what I can do to make it show the red circle.

Upvotes: 1

Views: 982

Answers (2)

Mike-Kilo
Mike-Kilo

Reputation: 1312

One and a half year later I faced the same problem - how to properly render a canvas without displaying it in the screen.

The solution was simpler than I thought and produces exactly the result one expects.
Long story short - to render the canvas without displaying it call Arrange(Rect finalRect) method on your canvas:

canvas.Arrange(new Rect(new Size(width, height)));

According to the documentation it:

Positions child elements and determines a size for a UIElement. Parent elements call this method from their ArrangeCore(Rect) implementation (or a WPF framework-level equivalent) to form a recursive layout update. This method constitutes the second pass of a layout update.

Upvotes: 1

Clemens
Clemens

Reputation: 128062

You have to call bitmap.Render(drawingVisual) after the DrawingContext is closed.

From the Remarks on DrawingContext.Close:

A DrawingContext must be closed before its content can be rendered ...

So just move the Render call outside the using block:

using (DrawingContext dc = drawingVisual.RenderOpen())
{
    dc.DrawEllipse(Brushes.Red, new Pen(Brushes.Red, 1),
                   new System.Windows.Point(50, 50), 50, 50);
}

bitmap.Render(drawingVisual);

Besides that, the red Pen seems redundant, since the circle is already filled red. So this should be ok:

dc.DrawEllipse(Brushes.Red, null, new System.Windows.Point(50, 50), 50, 50);

Also make sure to create the bitmap with a DPI value of 96, which corresponds to WPF device-independent units. Otherwise you would have to scale the drawing appropriately.

Upvotes: 0

Related Questions