Saving a canvas to png C# wpf
Asked Answered
L

1

13

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);
}
Lymphatic answered 28/1, 2014 at 16:54 Comment(3)
Why do you create MemoryStream? Create FileStream and save the encoder directly.Tiffanytiffi
If there are elements outside the visible canvas area: #67473318Kalbli
About the cut off bottom and right edge also keep in mind, that casting a double to int will just truncate the fractional digits. So you might want to try RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right + 1, (int)rect.Bottom + 1, dpi, dpi, System.Windows.Media.PixelFormats.Default);Irizarry
L
21

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.

Lightheaded answered 28/1, 2014 at 18:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.