Canvasの中にある画像として保存したい要素が回転や拡大など変形されていてもOKな方法
Private Sub Test2ImageFile(obj As FrameworkElement, parentPanel As Panel)
'変形した要素がぴったり収まるRectを取得
Dim gt As GeneralTransform = obj.TransformToVisual(parentPanel)
Dim r As Rect = gt.TransformBounds(New Rect(0, 0, obj.ActualWidth, obj.ActualHeight))
'要素のVisualBrush(ブラシ)作成、引き伸ばしされないようにStretch.Noneを指定
Dim vb As New VisualBrush(obj) With {.Stretch = Stretch.None}
'四角枠にブラシを使って塗る
Dim dv As New DrawingVisual
Using dc As DrawingContext = dv.RenderOpen
dc.DrawRectangle(vb, Nothing, New Rect(New Size(r.Width, r.Height)))
End Using
'Bitmap作成してRender
Dim rtb As New RenderTargetBitmap(r.Width, r.Height, 96, 96, PixelFormats.Pbgra32)
rtb.Render(dv)
'Bitmapをpng形式の画像で保存
Dim enc As New PngBitmapEncoder
enc.Frames.Add(BitmapFrame.Create(rtb))
'Using fs As New IO.FileStream("testImage.png", IO.FileMode.Create)
Using fs As New IO.FileStream(obj.Name & ".png", IO.FileMode.Create)
enc.Save(fs)
End Using
End Sub
MyCanvas(Canvas)に表示しているMyCyanBorder(Border)を画像として保存するときは
Call Test2ImageFile(MyCyanBorder, MyCanvas)
ってするとpng形式の画像で保存される
保存された画像(MyCyanBorder)
デザイン画面
ヤフーブログのかんたんモードにXAMLを書くと投稿エラーになるから画像で
VBコード
Class MainWindow
'現在日時を文字列にして取得
Private Function GetNowString() As String
Dim str As String = Now.ToString
str = Replace(str, "/", "")
str = Replace(str, ":", "")
str = Replace(str, " ", "_")
Return str
End Function
'対象がぴったり収まるRect取得
Private Function GetRect(obj As FrameworkElement)
Return obj.TransformToVisual(MyCanvas).TransformBounds(New Rect(New Size(obj.ActualWidth, obj.ActualHeight)))
End Function
'Bitmapをpng画像で保存
Private Sub Bitmap2pngFile(bmp As BitmapSource, filePath As String)
Dim enc As New PngBitmapEncoder
enc.Frames.Add(BitmapFrame.Create(bmp))
Using fs As New IO.FileStream(filePath, IO.FileMode.Create)
enc.Save(fs)
End Using
End Sub
'RenderTargetBitmapを使って対象をBitmapにして保存
Private Sub SaveImage(obj As FrameworkElement)
Dim r As Rect = GetRect(obj)
Dim rtb As New RenderTargetBitmap(r.Width, r.Height, 96, 96, PixelFormats.Pbgra32)
rtb.Render(obj)
Dim str As String = GetNowString() & obj.Name & ".png"
Call Bitmap2pngFile(rtb, str)
End Sub
'VisualBrushとRenderTargetBitmapを使って対象をBitmapにして保存
Private Sub SaveImageVisualBrush(obj As FrameworkElement)
Dim r As Rect = GetRect(obj)
Dim vb As New VisualBrush(obj) With {.Stretch = Stretch.None}
Dim dv As New DrawingVisual
Using dc As DrawingContext = dv.RenderOpen
dc.DrawRectangle(vb, Nothing, New Rect(New Size(r.Width, r.Height)))
End Using
Dim rtb As New RenderTargetBitmap(r.Width, r.Height, 96, 96, PixelFormats.Pbgra32)
rtb.Render(dv)
Dim str As String = GetNowString() & obj.Name & ".png"
Call Bitmap2pngFile(rtb, str)
End Sub
Private Sub TestSave1()
Call SaveImage(MyOrangeBorder)
Call SaveImage(MyRedBorder)
Call SaveImage(MyPurpleBorder)
Call SaveImage(MyPinkBorder)
Call SaveImage(MyCyanBorder)
End Sub
Private Sub TestSave2()
Dim r As Rect = GetRect(MyOrangeBorder)
Dim rtb As New RenderTargetBitmap(r.Width, r.Height, 96, 96, PixelFormats.Pbgra32)
rtb.Render(MyOrangeCanvas)
Dim str As String = GetNowString() & "MyOrangeBorder.png"
Call Bitmap2pngFile(rtb, str)
r = GetRect(MyRedBorder)
rtb = New RenderTargetBitmap(r.Width, r.Height, 96, 96, PixelFormats.Pbgra32)
rtb.Render(MyRedCanvas)
str = GetNowString() & "MyRedborder.png"
Call Bitmap2pngFile(rtb, str)
r = GetRect(MyPurpleBorder)
rtb = New RenderTargetBitmap(r.Width, r.Height, 96, 96, PixelFormats.Pbgra32)
rtb.Render(MyPurpleCanvas)
str = GetNowString() & "MyPurpleborder.png"
Call Bitmap2pngFile(rtb, str)
r = GetRect(MyPinkBorder)
rtb = New RenderTargetBitmap(r.Width, r.Height, 96, 96, PixelFormats.Pbgra32)
rtb.Render(MyPinkCanvas)
str = GetNowString() & "MyPinkborder.png"
Call Bitmap2pngFile(rtb, str)
End Sub
Private Sub TestSave3()
Call SaveImageVisualBrush(MyOrangeBorder)
Call SaveImageVisualBrush(MyRedBorder)
Call SaveImageVisualBrush(MyPurpleBorder)
Call SaveImageVisualBrush(MyPinkBorder)
Call SaveImageVisualBrush(MyCyanBorder)
Call SaveImageVisualBrush(MyPinkCanvas)
End Sub
Private Sub MainWindow_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
AddHandler btnSave1.Click, AddressOf TestSave1
AddHandler btnSave2.Click, AddressOf TestSave2
AddHandler btnSave3.Click, AddressOf TestSave3
End Sub
End Class
右半分に背景色ベージュのCanvasに5つのBorderを回転表示している
それぞれのBorderの表示を変えていて
オレンジのBorder
赤のBorder
紫のBorder
ピンクのBorder
水色のBorder
ボタンで保存
それぞれのBorderやその一個上のCanvasを画像として保存する
Save1ボタン
保存するBitmap作成をRenderTargetBitmapのRenderだけで行う方法
1番簡単だけど結果はイマイチでこうなるSave2ボタン
Save1はBorderをRenderしていたけど
Save2はBorderの一個上のCanvasをRenderしているだけでそれ以外は全く同じ
結果は期待はずれ
Save3
VisualBrushとDrawingVisualを使った方法
結果はOKな方法なので期待どおり
参照したところ
Nine Works WPFで要素を画像として保存するありがとうございます
http://nineworks2.blog.fc2.com/blog-entry-13.html
WPF - CanvasをBitmapに変換して画像ファイルとして保存する - Qiita
http://qiita.com/hugo-sb/items/894914f6bbe224a45d49
UWP で UIElement の外観をそのまま画像化して PNG ファイルに保存したい - しっぽを追いかけて
http://matatabi-ux.hateblo.jp/entry/2015/10/07/120000
この方法までたどり着くのに1ヶ月くらいかかった、取り掛かる前は1日でできると思っていたんだけどねえw
変形させなければ参照先の方法でいいんだけどPixtack紫陽花ではできていたことができなくなるのは嫌だからっていろいろ試していたら一ヶ月経っていたw
文字列の描画も少し試してみてこんな感じ
今回のコード
前回のVB.NET、WPFの記事
画像をくっきり表示させたい(ぼやけるのがイヤな)とき、EdgeModeとScalingMode、WPF ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/14912530.html