InkCanvas にてストロークと背景の合成画像をリサイズしてJPG保存する

サンプルコードまで飛びたい方は[こちらのリンクをクリック](https://qiita.com/ymatsukawa/items/5970446ef6ffa645e636#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB)

## 前提条件および動作確認した環境

* C#
* .NET 4.0
* WPF
* VisualStudio 2019

なぜ .NET 4.0 なのか、というのは推し測ってほしい。

## 確認する内容

* 後述の BEFORE 画像(`640x480`)を画面読み込み時に `InkCanvas(640x480)` に背景画像として設定する
* `InkCanvas` に書き込み終わった後 Save ボタンをクリックする
* 同クリック後、リサイズされた「背景画像とストロークの合成画像」(`320x240`) が `C:\Temp\test.jpg` として保存される

上記をサンプルコードで示す。処理内容に粗はあることを了承願いたい。

### BEFORE

![sea.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31223/59251b3b-170b-a169-e964-548a83c8de0c.jpeg)



### AFTER

![test_after.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31223/45811d54-e202-de64-6e7f-0d3b302120cb.jpeg)


## サンプル

### xaml

```xml
<Window x:Class="ImageReflect.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ImageReflect"
        mc:Ignorable="d"
        Title="MainWindow" Width="640" Height="600" >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="640" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="480"/>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <InkCanvas
                Name="MainCanvas" />
        </Grid>
        <Grid Grid.Row="1">
            <Button
                Name="SaveButton"
                Content="Save"
                FontSize="24px"
                Click="onClickSave" />
        </Grid>
    </Grid>
</Window>
```

**デバッグウィンドウ表示時のイメージ**

![01_MainWIndow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31223/c3bd3593-31c1-db50-1604-330654f13ea3.png)

### xaml.cs

`{ソリューションディレクトリ}/Resource/Image/sea.jpg` を用意しておく。

```csharp
using System;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace ImageReflect
{
  public partial class MainWindow : Window
  {
    public MainWindow()
    {
      InitializeComponent();
      this.initializeMainCanvas();
    }

    public void initializeMainCanvas()
    {
      var imageBrush = new ImageBrush();
      imageBrush.ImageSource = new BitmapImage(new Uri("pack://application:,,,/Resource/Image/sea.jpg"));
      this.MainCanvas.Background = imageBrush;
    }

    #region UI event handler

    // Save ボタンクリック時の event handler
    private void onClickSave(object sender, RoutedEventArgs e)
    {
      // レンダリングオブジェクトの描画先を作成する
      var drawingVisual = new DrawingVisual();
      var drawingContext = drawingVisual.RenderOpen();

      // InkCanvas 原寸大の描画「領域(rectangle)」を定義する
      var rect = new Rect(0, 0, this.MainCanvas.ActualWidth, this.MainCanvas.ActualHeight);
      // レンダリングオブジェクトに、背景画像を描画する
      drawingContext.DrawRectangle(this.MainCanvas.Background, null, rect);
      // レンダリングオブジェクトに、追加でストローク情報を描画する
      this.MainCanvas.Strokes.Draw(drawingContext);
      // レンダリングオブジェクト情報をフラッシュする
      drawingContext.Close();

      // 描画先をビットマップにする(96dpi)
      var renderTargetBitmap = new RenderTargetBitmap(
        (int)rect.Width, (int)rect.Height, 96d, 96d, PixelFormats.Default
      );
      renderTargetBitmap.Render(drawingVisual);

      // 描画先を 幅・高さ共に0.5倍へ変換する
      var scaledBitmap = new TransformedBitmap(renderTargetBitmap,
        new ScaleTransform(0.5d, 0.5d));

      // ここまでの描画情報をエンコーダーのフレームに追加する
      var encoder = new JpegBitmapEncoder();
      encoder.Frames.Add(BitmapFrame.Create(scaledBitmap));

      // C:\Temp\test.jpg へ JPG として出力
      using (var fileStream = File.Create(@"C:\Temp\test.jpg"))
      {
        encoder.Save(fileStream);
      }
    }

    #endregion UI event handler
  }
}
```

## その他

まだ把握しきれていないが、`RenderBitmap` 周りでメモリ枯渇(or リーク) の話がちらほら見えるので

サンプルコードはあくまで参考としてほしい。

https://stackoverflow.com/questions/14786490/wpf-memory-leak-using-rendertargetbitmap

## 参考にしたページ

* http://blog.wdnet.jp/tech/archives/112
* https://stackoverflow.com/questions/15779564/resize-image-in-wpf

## サンプルに使った画像

* https://pixabay.com/ja/photos/%E6%B5%B7-%E6%B9%BE-%E3%82%A6%E3%82%A9%E3%83%BC%E3%82%BF%E3%83%BC-%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88-418742/