午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

WPFとVBでアプリ作る準備その6、Canvas内に表示している複数画像を1枚の画像にして保存

前回は昨日の

gogowaten.hatenablog.com

続き

 

 

Canvas内に表示されている画像を保存

 
イメージ 1
保存ボタンをクリックで

f:id:gogowaten:20191025104448p:plain

保存ダイアログ表示
イメージ 3
ファイル名を付けて画像形式を選択して保存ボタンクリックで保存される
 
png画像形式
イメージ 5
空白の部分は透明になるけど写真画像だとファイルサイズが大きくなる
画像保存時に画質劣化は基本的にない
jpg、Jpeg画像形式
イメージ 4
半透明や透明ができないので空白部分は黒くなるか指定した色になるけど
写真画像向き、保存時に画質劣化するけど画質(QualityLevel)を指定できる
 
デザイン画面とXAML

f:id:gogowaten:20191025104502p:plain

保存ボタンを付け加えた、名前はsaveにした
 
ExImageクラス

f:id:gogowaten:20191025104513p:plain

前回から変化なし
 
MainWindow

f:id:gogowaten:20191025104528p:plain

赤いところが今回書き加えたところ
'画像ファイルとして保存

'      キャンバスに描いた絵を画像ファイルとして保存する | HIRO's.NET Blog
'http://blog.hiros-dot.net/?page_id=3802
'Daizen Ikehara : [WPF] XamQRCodeBarcode を画像として保存 [Tips]
'http://blogs.jp.infragistics.com/blogs/dikehara/archive/2014/02/12/wpf-xamqrcodebarcode-tips.aspx
'  RenderTargetBitmap tips - Jaime Rodriguez - Site Home - MSDN Blogs
'http://blogs.msdn.com/b/jaimer/archive/2009/07/03/rendertargetbitmap-tips.aspx

Private Sub SaveAllImage()
    If CollectionExImage.Count = 0 Then Return '画像がなければ何もしない

   'ダイアログ設定
    Dim dialogSave As New Microsoft.Win32.SaveFileDialog
    With dialogSave
        .Filter = "*.png|*.png|*.jpg|*.jpg;*.jpeg|*.bmp|*.bmp|*.gif|*.gif|*tiff|*.tiff"
        .AddExtension = True
    End With

   'ダイアログ表示
    If dialogSave.ShowDialog Then
       '保存画像サイズ取得
        Dim canvasRect As Rect = GetUnion(CollectionExImage)

       '描画先を作成
        Dim dv As New DrawingVisual
        Using dc As DrawingContext = dv.RenderOpen
            Dim vb As New VisualBrush(canvas1) 'Canvas内に表示されているもの自体を使ってVisualBrush作成
            dc.DrawRectangle(vb, Nothing, canvasRect) '四角形にブラシで塗り
        End Using

       '描画
        Dim rtb As New RenderTargetBitmap(canvasRect.Width, canvasRect.Height, 96, 96, PixelFormats.Pbgra32)
        rtb.Render(dv)

       '画像エンコーダ選択
        Dim enc As BitmapEncoder = Nothing
        Select Case dialogSave.FilterIndex
            Case 1
                enc = New PngBitmapEncoder
            Case 2
                Dim je As New JpegBitmapEncoder
                je.QualityLevel = 97 '1-100 初期値は75
                enc = je
            Case 3
                enc = New BmpBitmapEncoder
            Case 4
                enc = New GifBitmapEncoder
            Case 5
                enc = New TiffBitmapEncoder
        End Select

       'エンコーダに画像フレームを渡す
        Dim bf As BitmapFrame = BitmapFrame.Create(rtb)
        enc.Frames.Add(bf)

       'ファイルとして保存
        Using fs As New FileStream(dialogSave.FileName, FileMode.Create)
            enc.Save(fs)
        End Using
    End If
End Sub

'画像ファイルとして保存
Private Sub save_Click(sender As Object, e As RoutedEventArgs) Handles save.Click
    Call SaveAllImage()
End Sub
 
canvas1に表示されている画像を保存するメソッド
SaveAllimage
イメージ 9
セーブダイアログ作成
New Microsoft.Win32.SaveFileDialog
 
141:
.Filter = "*.png|*.png|*.jpg|*.jpg;*.jpeg|*.bmp|*.bmp|*.gif|*.gif|*tiff|*.tiff"
これが画像形式(ファイルの種類)を選択するところになる
イメージ 10
142:AddExtension=True
ファイル名に自動で拡張子をつける
 
描画関係、この辺はよくわかっていない
イメージ 11
ExImage(画像)を表示してあるcanvas1自体を使ってVisualBrushを作成して
そのブラシを使ってDrawingContextの四角形に塗っている?のが154行目
そのあと、158行目でRenderTargetBitmapを作成して
159行目でそこにまた塗っている?
なんか冗長な感じがするw
でもこれでBitmapができたっぽい
 
エンコーダ選択して作成
イメージ 12
さっきのファイルの種類の設定で指定したFilterは順番に1から始まるインデックスが
付けられているのでそのインデックスからそれぞれの形式のエンコーダを作成
2番のJpegだけは画質設定ができたので97に指定してみた
この辺りもWindowフォームアプリのときに比べるとWPFはかなりラクになっている
 
エンコーダにBitmapを渡して保存
イメージ 13
159行目でできあがったBitmapを使ってBitmapFrameを作って
エンコーダのFramesに追加
ファイルストリームを使ってエンコーダのSaveメソッドで保存
やっとできた
 
Dim vb As New VisualBrush(canvas1)
っていうこれだけでcanvas1のブラシが作れるのはスゴイ便利な気がする
試しにこのcanvas1部分をGridのgrid1に変更して
Dim vb As New VisualBrush(grid1)
 
イメージ 14
この状態で保存した画像が
これ↓
イメージ 15
サイズが違うけどしっかりgrid1にあるものが描画されている
148            Dim canvasRect As Rect = GetUnion(CollectionExImage)
149            canvasRect = New Rect(grid1.RenderSize)
こうして保存したら
イメージ 16
こうなったw
画像自体は簡単に取得できる
 
半透明の画像
イメージ 18
これをpng形式で保存すると
 
イメージ 17
こうなる
WPFの自動透過処理は素晴らしい

 
予定しているテスト
  • ドラッグ移動時に指定ピクセル数ごとに移動
  • 指定した画像の表示を消す(削除)
  • 指定した色を透明にする
  • レイアウト
 
完了したテスト
  • 画像ファイルドロップで画像表示
  • 画像をマウスドラッグで移動
  • 表示画像のレイヤー間の移動(入れ替え)ZOrder指定
  • 表示画像すべてを画像ファイルとして保存←New

WindowフォームアプリのPixtack紫陽花と比べるとかなりあっさりで
コード量だと5倍くらい違うかも
Pixtack紫陽花は最終的に3万行を超えて手がつけられなくなったw
Pixtack紫陽花は初めて作ったアプリだったせいもあるけど
やっぱりWPFの機能がすごいからラクにできる部分が大きい
 
 
参照したところは
キャンバスに描いた絵を画像ファイルとして保存する | HIRO's.NET Blog
    http://blog.hiros-dot.net/?page_id=3802

Daizen Ikehara : [WPF] XamQRCodeBarcode を画像として保存 [Tips]
    http://blogs.jp.infragistics.com/blogs/dikehara/archive/2014/02/12/wpf-xamqrcodebarcode-tips.aspx

RenderTargetBitmap tips - Jaime Rodriguez - Site Home - MSDN Blogs
    http://blogs.msdn.com/b/jaimer/archive/2009/07/03/rendertargetbitmap-tips.aspx
 
今回の記事の続き

gogowaten.hatenablog.com

 
WPFVBでアプリ作る準備その7、指定した間隔ごとにコントロールをマウスドラッグ移動 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/13924059.html