Saving a canvas to png C# wpf

Daniel picture Daniel · Jan 28, 2014 · Viewed 13.6k times · Source

So I am trying to take a snapshot of my canvas in WPF C# so that I can save it out as a png. The image saves incorrectly at present as it is including the left and top margins.

This is what I have:

create a rectangle for the size of the canvas. if canvas.Margin.Left and Top are set to 0 then the saved image is of the correct size but the offset still occurs and thus cuts the bottom and right edges. Being set the Margin.Left and Top still causes the offset to occur but the whole image is saved but at the wrong size (margin.Left + ActualWidth) rather than just ActualWidth

Rect rect = new Rect(canvas.Margin.Left, canvas.Margin.Top, canvas.ActualWidth, canvas.ActualHeight);

double dpi = 96d;

RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right, (int)rect.Bottom, dpi, dpi, System.Windows.Media.PixelFormats.Default);

rtb.Render(canvas);

BitmapEncoder pngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(BitmapFrame.Create(rtb));

try
{
    System.IO.MemoryStream ms = new System.IO.MemoryStream();

    pngEncoder.Save(ms);
    ms.Close();

    System.IO.File.WriteAllBytes(filename, ms.ToArray());
}
catch (Exception err)
{
    MessageBox.Show(err.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}

Answer

Jasti picture Jasti · Jan 28, 2014

Replace the first four lines with these lines

Rect bounds = VisualTreeHelper.GetDescendantBounds(canvas);
double dpi = 96d;

RenderTargetBitmap rtb = new RenderTargetBitmap((int)bounds.Width, (int)bounds.Height, dpi, dpi, System.Windows.Media.PixelFormats.Default);

DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
    VisualBrush vb = new VisualBrush(canvas);
    dc.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
}

rtb.Render(dv);

I have followed this article http://mcleodsean.wordpress.com/2008/10/07/bitmap-snapshots-of-wpf-visuals/ (for more explanation) and able to save the canvas without margins.