Canvasの中にある画像として保存したい要素が回転や拡大など変形されていてもOKな方法
Private Sub Test2ImageFile(obj As FrameworkElement, parentPanel As Panel)
Dim gt As GeneralTransform = obj.TransformToVisual(parentPanel)
Dim r As Rect = gt.TransformBounds(New Rect(0, 0, obj.ActualWidth, obj.ActualHeight))
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 enc As New PngBitmapEncoder
enc.Frames.Add(BitmapFrame.Create(rtb))
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)
今回のアプリ
デザイン画面
ヤフーブログのかんたんモードにXAMLを書くと投稿エラーになるから画像で
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
Private Function GetRect(obj As FrameworkElement)
Return obj.TransformToVisual(MyCanvas).TransformBounds(New Rect(New Size(obj.ActualWidth, obj.ActualHeight)))
End Function
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
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
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
x,y=(10,20)の
Canvasの中に表示、回転はしていない
赤のBorder
(50,50)の
Canvasの中に表示、Borderを10度回転
紫のBorder
位置指定なしの
Canvasの中に表示、Borderを50度回転、位置は0,20
ピンクのBorder
位置120,20の
Canvasの中に表示、Borderを50度回転
水色のBorder
Canvasは無しでそのまま表示、Borderを120度回転、位置は20,20
ボタンで保存
それぞれのBorderやその一個上の
Canvasを画像として保存する
Save1ボタン
保存するBitmap作成をRenderTargetBitmapのRenderだけで行う方法
1番簡単だけど結果はイマイチでこうなる
回転していないオレンジだけ期待どおりで、それ以外は違う
Save2ボタン
Save1はBorderをRenderしていたけど
Save2はBorderの一個上の
CanvasをRenderしているだけでそれ以外は全く同じ
結果は期待はずれ
どうやら一番上のMyCanvasの左上を基準にBitmapが作成されているみたいで大幅にずれている
Save3
VisualBrushとDrawingVisualを使った方法
結果はOKな方法なので期待どおり
真ん中のピンクBorderが回転されていないのは、回転指定されているのはBorderじゃなくてその一個上の
Canvasだからで、
その一個上のCanvasを保存した左上のピンクBorderは正しく保存されている
参照したところ
この方法までたどり着くのに1ヶ月くらいかかった、取り掛かる前は1日でできると思っていたんだけどねえw
変形させなければ参照先の方法でいいんだけどPixtack紫陽花ではできていたことができなくなるのは嫌だからっていろいろ試していたら一ヶ月経っていたw
文字列の描画も少し試してみてこんな感じ
WindowsFormのPixtack紫陽花では縁取りがうまく書けなかったけど
WPFは縁取りの指定するところがあってあちこち見ながら試したらできた!
今回のコード
次は翌日