Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9541

Blazor(Mobile Blazor Bindings)でWebViewの描画範囲だけスクショする方法 (Windows WPFの場合)

$
0
0

敗北から勝利までのメモ

何がしたかった

  • アプリケーションのUI部分を除いたキャプチャがしたかった (タイトルバーとかのUIを除いたWebViewだけキャプチャしたかった)

  • アプリケーション全体画像
    HoloViewer.png

宣伝

C#とBlazorでホロライブファン向けの動画ビューワー『ホロビューワー』を開発しました

結論

Windowsでは WebView2 CoreクラスのCapturePreviewメソッドを使用する。

以下PNGフォーマットで保存する場合のコード

<ContentView><StackLayout>// 省略<StackLayoutOrientation="StackOrientation.Horizontal"><ButtonText="Capture"OnClick="CaptureSingle"/></StackLayout><GridHorizontalOptions="LayoutOptions.FillAndExpand"VerticalOptions="LayoutOptions.FillAndExpand"><StackLayout><BlazorWebView@ref="BlazorWebViews"VerticalOptions="LayoutOptions.FillAndExpand"><HoloViewer.WebUI.App/></BlazorWebView></StackLayout></Grid>// 省略</StackLayout></ContentView>@code{privateList<BlazorWebView>blazorWebViews=newList<BlazorWebView>();publicBlazorWebViewBlazorWebViews{set{blazorWebViews.Add(value);}}voidCaptureSingle(){DependencyService.Get<IScreenCapture>().CaptureSingle(blazorWebViews.First());}}
  • Sharedコード (DependencyService定義)
usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingMicrosoft.MobileBlazorBindings.Elements;namespaceHoloViewer{publicinterfaceIScreenCapture{protectedconststringCaptureFileNameFormat="yyyyMMdd_HHmmss";protectedconststringCaptureFileExtension=".png";voidCaptureSingle(BlazorWebViewblazorWebView);}}
  • Windows WPF側のコード
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Windows;usingSystem.Windows.Media;usingSystem.Windows.Media.Imaging;usingSystem.IO;usingMicrosoft.MobileBlazorBindings.Elements;usingXamarin.Forms.Platform.WPF;[assembly:Xamarin.Forms.Dependency(typeof(HoloViewer.Windows.ScreenCapture))]namespaceHoloViewer.Windows{classScreenCapture:IScreenCapture{privateasyncvoidCapture(BlazorWebViewblazorWebView){using(varfileStream=newFileStream(DateTime.Now.ToString(IScreenCapture.CaptureFileNameFormat)+IScreenCapture.CaptureFileExtension,FileMode.Create)){awaitWebView.CastWebView(blazorWebView).CoreWebView2.CapturePreviewAsync(Microsoft.Web.WebView2.Core.CoreWebView2CapturePreviewImageFormat.Png,fileStream);}}publicvoidCaptureSingle(BlazorWebViewblazorWebView){Capture(blazorWebView);}}}
  • BlazorWebViewからWebView2への変換処理のコード
    • WebView2本体はアクセス範囲がpublicじゃないのでリフレクションでアクセスする。
    • この辺はデバッガで変数の中身をしらみつぶしにして探した。
usingSystem.Reflection;usingMicrosoft.MobileBlazorBindings.Elements;usingMicrosoft.MobileBlazorBindings.WebView.Elements;usingMicrosoft.Web.WebView2.Wpf;namespaceHoloViewer.Windows{classWebView{publicstaticWebView2CastWebView(BlazorWebViewblazorWebView){varcontent=((Microsoft.MobileBlazorBindings.WebView.Elements.MobileBlazorBindingsBlazorWebView)blazorWebView.NativeControl).Content;vartype=content.GetType();return(WebView2)type.GetProperty("RetainedNativeControl").GetValue(content);}}}
  • 成功例 (画像だけだと加工できるし、うまくいってるかわからんな これ) Sucucess.png

勝利に至るまでの経過

  • 敗北その1

    • WPFだしMainWindowをキャプチャして必要なところだけ切り出せばいいと思って試したら、そもそもWebViewのUIキャプチャできていない。
    • 敗北その1の結果 Fail1.png
RenderTargetBitmapを使用するパターン
privatevoidCapture(){varmainWindow=Application.Current.MainWindow;varrenderTargetBitmap=newRenderTargetBitmap((int)mainWindow.Width,(int)mainWindow.Height,96,96,PixelFormats.Pbgra32);renderTargetBitmap.Render(mainWindow);varpngBitmapEncoder=newPngBitmapEncoder();pngBitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));using(varfileStream=newFileStream(DateTime.Now.ToString(IScreenCapture.CaptureFileNameFormat)+IScreenCapture.CaptureFileExtension,FileMode.Create)){pngBitmapEncoder.Save(fileStream);}}
  • 敗北その1の原因 (推測)
    • タスクマネージャーでプロセスを見てみると別のプロセスでWebView2が動作している。
    • よってMainWindow(画像だと無名になっているプロセス)だけをキャプチャしてもWebViewの箇所が表示されない。 (と推測しています)
    • WebView2のプロセスが複数ある理由は正直わかっていません。

WebView2Process.png

  • 敗北その2
    • CapturePreviewAsyncメソッドを await しないと0バイトのPNG画像が生成される。
    • そもそもawaitしていなかったり、Wait関数で待っても0バイトのPNG画像が生成されてダメなので注意
await忘れパターン
privatevoidCapture(BlazorWebViewblazorWebView){using(varfileStream=newFileStream(DateTime.Now.ToString(IScreenCapture.CaptureFileNameFormat)+IScreenCapture.CaptureFileExtension,FileMode.Create)){WebView.CastWebView(blazorWebView).CoreWebView2.CapturePreviewAsync(Microsoft.Web.WebView2.Core.CoreWebView2CapturePreviewImageFormat.Png,fileStream);}}
  • 敗北その2の結果 Fail2.png

まとめ

  • Windows版はこの調子で機能を実装すれば勝てそう
  • WebView2がMacには対応していないためMac版は別の地獄がまっているはず

Viewing all articles
Browse latest Browse all 9541

Trending Articles