As part of a side project, I needed to take the contents of a WPF application render it (or a subset of it on a Canvas) as a bitmap.

The attached Visual Studio 2008 sample application shows how to accomplish both tasks.

To illustrate, this is the application window

image

 

Clicking Save Window will save the image the following image to “d:\window.png”

 

image

Clicking Save Canvas will save the image the following image to “d:\canvas.png”

image

The code (project available as a zip file)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void button_save_window_Click(object sender, RoutedEventArgs e)
        {

            util.SaveWindow(this,96,"d:\\window.png");
        }

        private void button_save_canvas_Click(object sender, RoutedEventArgs e)
        {

            util.SaveCanvas(this,this.canvas1, 96, "d:\\canvas.png");
        }
    }

    public static class util
    {
        public static void SaveWindow(Window window, int dpi, string filename)
        {

            var rtb = new RenderTargetBitmap(
                (int)window.Width, //width
                (int)window.Width, //height
                dpi, //dpi x
                dpi, //dpi y
                PixelFormats.Pbgra32 // pixelformat
                );
            rtb.Render(window);

            SaveRTBAsPNG(rtb, filename);

        }

        public static void SaveCanvas(Window window, Canvas canvas, int dpi, string filename)
        {
            Size size = new Size(window.Width , window.Height );
            canvas.Measure(size);
            //canvas.Arrange(new Rect(size));

            var rtb = new RenderTargetBitmap(
                (int)window.Width, //width
                (int)window.Height, //height
                dpi, //dpi x
                dpi, //dpi y
                PixelFormats.Pbgra32 // pixelformat
                );
            rtb.Render(canvas);

            SaveRTBAsPNG(rtb, filename);
        }

        private static void SaveRTBAsPNG(RenderTargetBitmap bmp, string filename)
        {
            var enc = new System.Windows.Media.Imaging.PngBitmapEncoder();
            enc.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(bmp));

            using (var stm = System.IO.File.Create(filename))
            {
                enc.Save(stm);
            }
        }
    }
}

 

Why is the call to Arrange() in SaveCanvas() commented out?

It resizes the Canvas element which is not what I wanted.

 

What’s Next?

Soon I’ll post an example of how to save a WPF animation as an video file.