Reputation: 55
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
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
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