C#
WPF

WPF - CanvasをBitmapに変換して画像ファイルとして保存する

More than 1 year has passed since last update.

WPF で図形を作成する場合、Canvas を利用するのが手っ取り早い。だけど残念ながら Canvas クラスには描画した図形を直接ビットマップ形式の画像ファイルとして保存するメソッドは用意されていない。

Canvas を画像ファイルとして保存するには、RenderTargetBitmap クラスのインスタンスを作成し BitmapSoruce に変換した後、保存したい形式の BitmapEncoder に食わせてエンコード、FileStream に保存するという手順を踏む。この時、RenderTargetBitmap でビットマップに変換する前に Canvasn に対して、Measure メソッドと Arrange メソッドを呼び出してレイアウトを再計算させる必要がある。でないと画像が保存されない。

定型の処理なので、Canvas クラスの拡張メソッドとして実装してやると使い勝手が良い。

CanvasExtensions.css
// Canvas クラスの拡張メソッドとして実装する
public static class CanvasExtensions
{
    // Canvas を画像ファイルとして保存する。
    public static void toImage(this Canvas canvas, string path, BitmapEncoder encoder = null)
    {
        // レイアウトを再計算させる
       var size = new Size(canvas.Width, canvas.Height);
       canvas.Measure(size);
       canvas.Arrange(new Rect(size));

       // VisualObjectをBitmapに変換する
       var renderBitmap = new RenderTargetBitmap((int)size.Width,       // 画像の幅
                                                 (int)size.Height,      // 画像の高さ
                                                 96.0d,                 // 横96.0DPI
                                                 96.0d,                 // 縦96.0DPI
                                                 PixelFormats.Pbgra32); // 32bit(RGBA各8bit)
       renderBitmap.Render(canvas);

       // 出力用の FileStream を作成する
       using (var os = new FileStream(path, FileMode.Create))
       {
           // 変換したBitmapをエンコードしてFileStreamに保存する。
           // BitmapEncoder が指定されなかった場合は、PNG形式とする。
           encoder = encoder ?? new PngBitmapEncoder();
           encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
           encoder.Save(os);
       }
    }
}

使い方は↓のような感じ。

sample.css
// Canvas をビットマップ形式の画像に保存する
private void SaveCanvas()
{
    // CreateCanvas() は描画済みのCanvasを返すとする
    var canvas = CreateCanvas();

    // PNG形式で保存
    canvas.toImage(@"C:¥Path¥To¥Test.png");

    // JPEG形式で保存
    var encoder = new JpegBitmapEncoder();
    canvas.toImage(@"c:¥Path¥To¥Test.jpg", encoder);
}