Quantcast
Channel: 午後わてんのブログ
Viewing all articles
Browse latest Browse all 420

WPF、Canvasの中に画像として保存したい要素が回転や拡大など変形されていてもOKな方法

$
0
0

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


イメージ 2

MyCanvas(Canvas)に表示しているMyCyanBorder(Border)を画像として保存するときは
Call Test2ImageFile(MyCyanBorder, MyCanvas)
ってするとpng形式の画像で保存される
イメージ 1
保存された画像(MyCyanBorder)


イメージ 3



デザイン画面
ヤフーブログのかんたんモードにXAMLを書くと投稿エラーになるから画像で
イメージ 4


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


イメージ 5
右半分に背景色ベージュのCanvasに5つのBorderを回転表示している
それぞれのBorderの表示を変えていて
オレンジのBorder
イメージ 6
x,y=(10,20)のCanvasの中に表示、回転はしていない

赤のBorder
イメージ 7
(50,50)のCanvasの中に表示、Borderを10度回転

紫のBorder
イメージ 8
位置指定なしのCanvasの中に表示、Borderを50度回転、位置は0,20

ピンクのBorder
イメージ 9
位置120,20のCanvasの中に表示、Borderを50度回転

水色のBorder
イメージ 10
Canvasは無しでそのまま表示、Borderを120度回転、位置は20,20



ボタンで保存
それぞれのBorderやその一個上のCanvasを画像として保存する
Save1ボタン
イメージ 11
保存するBitmap作成をRenderTargetBitmapのRenderだけで行う方法
1番簡単だけど結果はイマイチでこうなる
イメージ 12
回転していないオレンジだけ期待どおりで、それ以外は違う


Save2ボタン
イメージ 13
Save1はBorderをRenderしていたけど
Save2はBorderの一個上のCanvasをRenderしているだけでそれ以外は全く同じ
結果は期待はずれ
イメージ 14
どうやら一番上のMyCanvasの左上を基準にBitmapが作成されているみたいで大幅にずれている


Save3
イメージ 15
このページの一番上に書いたOKな方法と同じ
VisualBrushとDrawingVisualを使った方法
結果はOKな方法なので期待どおり
イメージ 16
真ん中のピンクBorderが回転されていないのは、回転指定されているのはBorderじゃなくてその一個上のCanvasだからで、その一個上のCanvasを保存した左上のピンクBorderは正しく保存されている


参照したところ
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

文字列の描画も少し試してみてこんな感じ
イメージ 17
WindowsFormのPixtack紫陽花では縁取りがうまく書けなかったけどWPFは縁取りの指定するところがあってあちこち見ながら試したらできた!


今回のコード


前回のVB.NET、WPFの記事
画像をくっきり表示させたい(ぼやけるのがイヤな)とき、EdgeModeとScalingMode、WPF ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/14912530.html






Viewing all articles
Browse latest Browse all 420

Trending Articles