1
0

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-10-06

サンプルコードまで飛びたい方はこちらのリンクをクリック

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

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

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

確認する内容

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

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

BEFORE

sea.jpg

AFTER

test_after.jpg

サンプル

xaml

<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

xaml.cs

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

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 リーク) の話がちらほら見えるので

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

参考にしたページ

サンプルに使った画像

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0