F#でWPF --- UI画像キャプチャ
今回は、表示されているWPFコントロールを画像として保存する方法を書いていきます。
F#でWPFを利用する方法は下記記事を参照してください。
F#でWPF --- ウィンドウ表示 - 何でもプログラミング
作成するアプリケーション
キャプチャボタンを押すと、Gridの内部がpngで保存されるアプリケーションを作成します。
SaveImageAction
今回はTriggerActionを利用して実装していきます。
TargetにバインドされたFrameworkElementをPNG画像として出力します。
FrameworkElementからBitmapにするにはRenderTargetBitmapを利用します。
Measure、Arrange、UpdateLayoutを呼んでコントロールを希望のサイズに更新します。場合によって全部呼ぶ必要がないケースもありますが、セットにして記述しておく方が楽です。
BitmapをPNGで保存するにはPngBitmapEncoder利用します。
open System.IO open System.Windows open System.Windows.Media open System.Windows.Media.Imaging open System.Windows.Interactivity open Microsoft.Win32 open Microsoft.FSharp.Linq.NullableOperators type SaveImageAction() = inherit TriggerAction<FrameworkElement>() static member val TargetProperty = DependencyProperty.Register("Target", typeof<FrameworkElement>, typeof<SaveImageAction>) member this.Target with get() = this.GetValue(SaveImageAction.TargetProperty) :?> FrameworkElement and set(x:FrameworkElement) = this.SetValue(SaveImageAction.TargetProperty, x) override this.Invoke _ = let dialog = SaveFileDialog(Filter = "PNGファイル|*.png") if this.Target <> null && dialog.ShowDialog() ?= true then let width = this.Target.ActualWidth let height = this.Target.ActualHeight let bmp = RenderTargetBitmap(int width, int height, 96.0, 96.0, PixelFormats.Pbgra32) this.Target.Measure(Size(width, height)) this.Target.Arrange(Rect(0.0, 0.0, width, height)) this.Target.UpdateLayout() bmp.Render(this.Target) let pngEncoder = PngBitmapEncoder() pngEncoder.Frames.Add(BitmapFrame.Create(bmp)) use writer = new StreamWriter(dialog.FileName) pngEncoder.Save(writer.BaseStream)
アプリケーションコード
BindingでPathを設定しないと、コントロールそのものを渡すことができます。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:local="clr-namespace:Actions;assembly=SaveWpfImage" Title="MainWindow" Height="100" Width="200"> <Grid x:Name="grid" Background="CornflowerBlue"> <Button Content="キャプチャ" HorizontalAlignment="Left" Margin="55,20,0,0" VerticalAlignment="Top" Width="75"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <local:SaveImageAction Target="{Binding ElementName=grid}" /> </i:EventTrigger> </i:Interaction.Triggers> </Button> </Grid> </Window>
F#
open System open System.Windows [<STAThread>] [<EntryPoint>] let main argv = let window = Application.LoadComponent(Uri("MainWindow.xaml", UriKind.Relative)) :?> Window Application().Run(window) |> ignore 0