SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Silverlight/WPFで使える逆引きTips集

Silverlight/WPFで使える逆引きTips集
――インクキャンバス機能

(6) InkCanvasコントロール

ダウンロード InkCanvas_WPF_VB.zip (2.0 MB)
ダウンロード InkCanvas_WPF_CS.zip (72.0 KB)

11.キャンバスに描いた絵を画像ファイルとして保存する

 InkCnavasに描いた絵を画像として保存するTipsを紹介します。下の方にコードを示しますので、併せてご覧ください。

  1. InkCanvasに描かれた画像を別な場所に転送(描画)します。この転送先は、DrawingVisual クラスを使用して作成した変数とします。
  2. 作成した変数(DrawingVisual オブジェクト)の RederOpen() メソッドを使用し、返されたDrawingContext オブジェクトに対して描画行います。
  3. 2.で描画されたオブジェクトを RendarTagetBitmap クラスを利用して、ビットマップへ変換しておきます。
  4. ビットマップへ変換されたオブジェクトから、目的の形式に合わせたエンコーダーのインスタンスを作成します。

 使用できるエンコーダーには下記のようなものがあります。

イメージ用エンコーダークラス
クラス名 説明
BmpBitmapEncoder BMP形式のエンコーダー
GifBitmapEncoder GIF形式のエンコーダー
JpegBitmapEncoder JPEG形式のエンコーダー
PngBitmapEncoder PNG形式のエンコーダー
TiffBitmapEncoder TIFF形式のエンコーダー
  1. BitmapFrameクラスからビットマップフレームを作成して、4. で作成したエンコーダーのフレームに追加します。
  2. 最後に Streamクラスを使用して、画像をファイルに書き込みます。

 下記がキャンバスに描いた絵を画像ファイルとして保存する例です。

.InkSeriah2zedFormat 形式で保存/読み込みをする例
.InkSeriah2zedFormat 形式で保存/読み込みをする例
XAMLの例
<StackPanel Name="parentStack">
    <StackPanel Orientation="Horizontal" Name="menuStack">
        <Button Name="btnSave" Content="保存" />
    </StackPanel>
    <InkCanvas Name="InkCanvas1" EditingMode="Ink" />
</StackPanel>
VBの例
' [保存]ボタンクリック時の処理
Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnSave.Click
    Dim dlgSave As New Microsoft.Win32.SaveFileDialog()

    dlgSave.Filter = "ビットマップファイル(*.bmp)|*.bmp|" &
        "JPEGファイル(*.jpg)|*,jpg|" &
        "PNGファイル(*.png)|*.png"
    dlgSave.AddExtension = True

    If dlgSave.ShowDialog() Then
        '拡張子を取得する
        Dim extension As String =
            System.IO.Path.GetExtension(dlgSave.FileName).ToUpper()

        'ストロークが描画されている境界を取得
        Dim rectBounds As Rect = InkCanvas1.Strokes.GetBounds()

        '描画先を作成
        Dim dv As New DrawingVisual
        Dim dc As DrawingContext = dv.RenderOpen()
        '描画エリアの位置補正(補正しないと黒い部分ができてしまう)
        dc.PushTransform(New TranslateTransform(-rectBounds.X, -rectBounds.Y))

        '描画エリア(dc)に四角形を作成
        '四角形の大きさはストロークが描画されている枠サイズとし、
        '背景色はInkCanvasコントロールと同じにする
        dc.DrawRectangle(InkCanvas1.Background, Nothing, rectBounds)

        '上記で作成した描画エリアに(dc)にInkCanvasのストロークを描画
        InkCanvas1.Strokes.Draw(dc)
        dc.Close()

        'ビジュアルオブジェクトをビットマップに変換する
        Dim rtb As New RenderTargetBitmap(
            rectBounds.Width, rectBounds.Height,
            96, 96,
            PixelFormats.Default)
        rtb.Render(dv)

        'ビットマップエンコーダー変数の宣言
        Dim enc As BitmapEncoder = Nothing

        '画像のエンコーダーを作成(拡張子で判断)
        Select Case extension
            Case ".BMP"
                enc = New BmpBitmapEncoder()
            Case ".JPG"
                enc = New JpegBitmapEncoder()
            Case ".PNG"
                enc = New PngBitmapEncoder()
        End Select

        If Not IsNothing(enc) Then
            'ビットマップフレームを作成してエンコーダーにフレームを追加する
            enc.Frames.Add(BitmapFrame.Create(rtb))
            'ファイルに書き込む
            Dim stream As System.IO.Stream = System.IO.File.Create(dlgSave.FileName)
            enc.Save(stream)
            stream.Close()
        End If
    End If

End Sub
C#の例
// [保存]ボタンクリック時の処理
private void btnSave_Click(object sender, RoutedEventArgs e)
{
    Microsoft.Win32.SaveFileDialog dlgSave = new Microsoft.Win32.SaveFileDialog();

    dlgSave.Filter = "ビットマップファイル(*.bmp)|*.bmp|" +
    "JPEGファイル(*.jpg)|*,jpg|" +
    "PNGファイル(*.png)|*.png";
    dlgSave.AddExtension = true;

    if ((bool)dlgSave.ShowDialog())
    {
        // 拡張子を取得する
        string extension = System.IO.Path.GetExtension(dlgSave.FileName).ToUpper();

        // ストロークが描画されている境界を取得
        Rect rectBounds = inkCanvas1.Strokes.GetBounds();

        // 描画先を作成
        DrawingVisual dv = new DrawingVisual();
        DrawingContext dc = dv.RenderOpen();
        // 描画エリアの位置補正(補正しないと黒い部分ができてしまう)
        dc.PushTransform(new TranslateTransform(-rectBounds.X, -rectBounds.Y));

        // 描画エリア(dc)に四角形を作成
        // 四角形の大きさはストロークが描画されている枠サイズとし、
        // 背景色はInkCanvasコントロールと同じにする
        dc.DrawRectangle(inkCanvas1.Background, null, rectBounds);

        // 上記で作成した描画エリア(dc)にInkCanvasのストロークを描画
        inkCanvas1.Strokes.Draw(dc);
        dc.Close();

        // ビジュアルオブジェクトをビットマップに変換する
        RenderTargetBitmap rtb = new RenderTargetBitmap(
            (int)rectBounds.Width, (int)rectBounds.Height,
            96,96,
            PixelFormats.Default);
        rtb.Render(dv);

        // ビットマップエンコーダー変数の宣言
        BitmapEncoder enc = null;

        switch (extension)
        {
            case ".BMP":
                enc = new BmpBitmapEncoder();
                break;
            case ".JPG":
                enc = new JpegBitmapEncoder();
                break;
            case ".PNG":
                enc = new PngBitmapEncoder();
                break;
        }

        if (enc != null)
        {
            // ビットマップフレームを作成してエンコーダーにフレームを追加する
            enc.Frames.Add(BitmapFrame.Create(rtb));
            // ファイルに書き込む
            System.IO.Stream stream = System.IO.File.Create(dlgSave.FileName);
            enc.Save(stream);
            stream.Close();
        }

    }
}
ポイント

 InkCanvas へ描いた絵を画像ファイル(gif,jpg,pngなど)として保存するには、いったん新しく描画エリアを作成して、キャンバス上の画像を転送する。

 次に、任意のイメージ用エンコーダーを作成し、Streamクラスを使用して保存する。

12.InkSeriah2zedFormat 形式で保存/読み込みをする

 InkCanvas に描いたストロークは、InkSerializedFormat 形式(拡張子 ISF)と呼ばれる専用のファイルに保存したり読み込んだりすることが可能です。専用のファイルを利用することで、途中まで描いた絵を保存し、続きは後から描くといったように再利用を可能にします。

 ISF形式で保存するには FileStremを作成して、Strokes プロパティSaveメソッドを使用します。

 また、ISF形式のファイルを読み込んで InkCanvasに表示するには、FileStream で任意のファイルを開いて StrokeCollection クラスのインスタンスを作成し、 Strokes プロパティにセットします。

 下記は InkCanvas に描かれたストロークをISF形式で保存したり開いたりする例です。

InkSeriah2zedFormat 形式で保存/読み込みをする例
InkSeriah2zedFormat 形式で保存/読み込みをする例
XAMLの例
<StackPanel Name="parentStack">
    <StackPanel Orientation="Horizontal" Name="menuStack">
        <Button Name="btnSaveAsISF" Content="ISF形式で保存" />
        <Button Name="btnOpenISF" Content="ISF形式ファイルを開く" />
    </StackPanel>
    <InkCanvas Name="InkCanvas1" EditingMode="Ink" />
</StackPanel>
VBの例
' [ISF形式で保存する]ボタンクリック時の処理
Private Sub btnSaveAsISF_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnSaveAsISF.Click
    Dim dlgSave As New Microsoft.Win32.SaveFileDialog()

    dlgSave.Filter = "ISFファイル(*.isf)|*.isf"

    If dlgSave.ShowDialog() Then
        Using fs As New System.IO.FileStream(dlgSave.FileName, IO.FileMode.Create)
            InkCanvas1.Strokes.Save(fs)
        End Using

        MessageBox.Show("保存しました")
    End If
End Sub

' [ISF形式ファイルを開く]ボタンクリック時の処理
Private Sub btnOpenISF_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnOpenISF.Click
    Dim dlgOpen As New Microsoft.Win32.OpenFileDialog()

    dlgOpen.Filter = "ISFファイル(*.isf)|*.isf"

    If dlgOpen.ShowDialog() Then
        '現在のストロークをクリア
        InkCanvas1.Strokes.Clear()

        Using fs As New System.IO.FileStream(dlgOpen.FileName, IO.FileMode.Open)
            InkCanvas1.Strokes = New Ink.StrokeCollection(fs)
        End Using
    End If
End Sub
C#の例
// [ISF形式で保存する]ボタンクリック時の処理
private void btnSaveAsISF_Click(object sender, RoutedEventArgs e)
{
    Microsoft.Win32.SaveFileDialog dlgSave = new Microsoft.Win32.SaveFileDialog();

    dlgSave.Filter = "ISFファイル(*.isf)|*.isf";

    if ((bool)dlgSave.ShowDialog())
    {
        using ( System.IO.FileStream fs = 
            new System.IO.FileStream(dlgSave.FileName, System.IO.FileMode.Create))
        {
            inkCanvas1.Strokes.Save(fs);
        }

        MessageBox.Show("保存しました");
    }
}

// [ISF形式ファイルを開く]ボタンクリック時の処理
private void btnOpenISF_Click(object sender, RoutedEventArgs e)
{
    Microsoft.Win32.OpenFileDialog dlgOpen = new Microsoft.Win32.OpenFileDialog();

    dlgOpen.Filter = "ISFファイル(*.isf)|*.isf";

    if ((bool)dlgOpen.ShowDialog())
    {
        // 現在のストロークをクリア
        inkCanvas1.Strokes.Clear();

        using (System.IO.FileStream fs =
            new System.IO.FileStream(dlgOpen.FileName, System.IO.FileMode.Open))
        {
            inkCanvas1.Strokes = new System.Windows.Ink.StrokeCollection(fs);
        }
    }
}
ポイント

 キャンバスに描いた絵を InkSerializedFormat 形式で保存するには Strokes プロパティの Saveメソッド を使用する。

 また、InkSerializedFormat 形式のファイルを読み込んでキャンバスに表示するには StrokeCollection クラスを使用して InkCanvasのStrokesプロパティにセットする。

まとめ

 今回は、InkCanvasコントロールについて取り上げました。

 InkCanvasコントロールには多くのプロパティ、イベント、メソッドが備わっており、それ単体でも非常に強力なコントロールだということがお分かりいただけたかと思います。

 今回紹介した Tips を組み合わせるだけでもかなり高機能な「お絵かきソフト」が作成できると思いますので、是非挑戦してみて下さい。

 最後に、InkCanvas のMSDNリンクを下記に記しておきます

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
Silverlight/WPFで使える逆引きTips集連載記事一覧

もっと読む

この記事の著者

HIRO(ヒロ)

HIRO's.NETのHIROです。とある半導体工場のSEです。VB.NET, C#, PowerShellによるプログラミングを楽しんでいます。最近はBlog でPowerShellについて書いています。2008/07/07にPowerShell from Japan!!というサイトを立ち上げまし...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/5666 2011/01/13 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー