WPFのインク機能②

2013年11月28日

LINEで送る

今回は、InkCanvasに描画した内容をISF(Ink Serialized Format)形式・画像ファイルで保存する方法について紹介します。

ISF (Ink Serialized Format) 形式はマイクロソフトが策定したインク情報を保存するためのデータ形式です。
WPF 以外のマイクロソフト技術でも利用することができます。
InkCanvasはISF形式の保存・読み込みを標準でサポートしており、簡単に保存・読み込みを行うことが可能です。

画像ファイルについては、標準でサポートはしていませんが、書き込みは実装することが可能です。
ただし、画像ファイルからの読み込みはサポートしていません。

1. 保存・読み込みボタンの設置
前回設置したボタンの下に保存・読み込みのボタンを設置します。

<StackPanel Orientation="Vertical" Background="Gray" Grid.Column="1">
    <Button x:Name="eraseByPointBtn" Content="EraseByPoint" Click="eraseByPointBtn_Click"/>
    <Button x:Name="eraseByStrokeBtn" Content="EraseByStroke" Click="eraseByStrokeBtn_Click"/>
    <Button x:Name="gestureOnlyBtn" Content="GestureOnly" Click="gestureOnlyBtn_Click"/>
    <Button x:Name="inkBtn" Content="Ink" Click="inkBtn_Click"/>
    <Button x:Name="inkAndGestureBtn" Content="InkAndGesture" Click="inkAndGestureBtn_Click"/>
    <Button x:Name="noneBtn" Content="None" Click="noneBtn_Click"/>
    <Button x:Name="selectBtn" Content="Select" Click="selectBtn_Click"/>
    <!-- 保存機能 -->
    <Button x:Name="saveBtn" Content="Save" Margin="0,10,0,0" Click="saveBtn_Click"/>
    <Button x:Name="openBtn" Content="Open" Click="openBtn_Click"/>
</StackPanel>

2. 保存処理の追加
保存するファイル名の拡張子から、ISF・Bitmap・PNG・JPEG形式で保存できるようにしました。
ISF形式はStrokes.Saveを実行するだけで、保存することが可能です。
画像ファイルの場合はDrawingContextに対し、Strokes.Drawを実行することでInkCanvasに描画されているストロークが描画されます。
あとは、保存したい画像のエンコーダを指定し、ファイルに保存することで画像ファイルとして保存することができます。
今回はBitmap・PNG・JPEGについて紹介しておりますが、他のフォーマットにも対応していますので、
どのような画像フォーマットに対応しているかはMSDNのBitmapEncoderクラスのページを参照してください。

// 保存処理
private void saveBtn_Click(object sender, RoutedEventArgs e)
{
    SaveFileDialog fileDialog = new SaveFileDialog();

    fileDialog.Filter = "Ink Serialization Format(.isf)|*.isf" +
        "|ビットマップファイル(.bmp)|*.bmp|PNGファイル(.png)|*.png|JPEGファイル(.jpg)|*.jpg";
    fileDialog.DefaultExt = "isf";

    Nullable<bool> result = fileDialog.ShowDialog();
    if (result == true)
    {
        string fileName = fileDialog.FileName;

        // 拡張子から保存フォーマットを決定する
        string ext = System.IO.Path.GetExtension(fileName).ToLower();
        if (ext == ".isf")
        {
            // ISF形式で保存する
            FileStream fs = new FileStream(fileName, FileMode.Create);
            inkCanvas.Strokes.Save(fs);
            fs.Close();
        }
        else
        {
            // 画像フォーマットを指定して保存する

            // Width・Heightにはサイズが設定されていないのでActualWidth・ActualHeightを利用する
            Rect rect = new Rect(0, 0, inkCanvas.ActualWidth, inkCanvas.ActualHeight);

            // 描画先の作成
            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext context = drawingVisual.RenderOpen();
                    
            // inkCanvasの背景色で塗りつぶし
            context.DrawRectangle(inkCanvas.Background, null, rect);
            // inkCanvasのストロークを描画する
            inkCanvas.Strokes.Draw(context);
                    
            context.Close();

            // drawingVisualをビットマップに変更する
            RenderTargetBitmap rtb = new RenderTargetBitmap(
                (int)rect.Width, (int)rect.Height,
                96, 96,
                PixelFormats.Default);
            rtb.Render(drawingVisual);

            // 拡張子によってエンコーダーを変更する
            BitmapEncoder enc = null;
            switch (ext)
            {
                case ".png":
                    // PNG
                    enc = new PngBitmapEncoder();
                    break;
                case ".jpg":
                    // JPEG
                    enc = new JpegBitmapEncoder();
                    break;
                default:
                    // Bitmap
                    enc = new BmpBitmapEncoder();
                    break;
            }
            enc.Frames.Add(BitmapFrame.Create(rtb));

            // ファイルへ保存
            FileStream fs = new FileStream(fileName, FileMode.Create);
            enc.Save(fs);
            fs.Close();
        }
    }
}

3. 読み込み処理の追加
InkCanvasは画像からストロークを読み込むことができませんので、ISF形式からの読み込みとなります。

// 読み込み処理(ISF形式のみ)
private void openBtn_Click(object sender, RoutedEventArgs e)
{
    OpenFileDialog fileDialog = new OpenFileDialog();

    fileDialog.Filter = "Ink Serialization Format(.isf)|*.isf";
    fileDialog.CheckFileExists = true;

    Nullable<bool> result = fileDialog.ShowDialog();
    if (result == true)
    {
        string fileName = fileDialog.FileName;

        // 読み込んだストロークを反映する
        FileStream fs = new FileStream(fileName, FileMode.Open);
        inkCanvas.Strokes = new StrokeCollection(fs);
        fs.Close();
    }
}

以上で実装は完了です。
実際にアプリケーションを実行します。
InkCanvasに線を描画した後に、SaveボタンからISF形式や画像ファイルで保存することができるようになります。
ISF形式のみ読み込みが可能なので、保存したISF形式のファイルからInkCanvasに読み込みができることも確認してみてください。

サンプルソースはこちらにアップしてありますので、興味のある方は実際に試して頂ければと思います。

次回は、InkCanvasに描画したストロークから文字を認識する方法を紹介します。

Top