WEB画面を取り込んでいろいろやろうと思っている
個人開発しているソフトがあるのだけど…
最近のサイトはie未対応でvb.netに付属しているWebBrowserコントロールで読み込んでも、まともに表示されないものが増えてきた。
そこで「WebView2コントロールというのを使用するとそういうサイトも表示はできるらしい」と知ったので試してみた。
WebView2コントロールを使えば今までエラーになっていたサイトの表示はできる。
うん、”表示はだけは”できるんだ。
でも、こいつがvb.netの普通の手段では画面キャプチャできない。
こまった。
なので調べて、出来るようにしてみた。
webのロード部分などの説明は省くが最初に試したのはDrawToBitmapメソッドだ。
他のコントロールにも実装されている標準的なコントロールの表示イメージを画像にするだけのメソッド。
こいつを WebView2.DrawToBitmap() のように呼び出してみる
そして得られたイメージを保存してみる。
うん、真っ白けだ。
画面イメージが取れてない。
なもんで、他になんかないのか?
と探してみたところ「CapturePreviewAsync」というメソッドがある。
このように使うらしい。
Dim imageType As Integer = 1 ' 1:jpeg / 2:png
Dim ts As Task = WebView2.CoreWebView2.CapturePreviewAsync(imageType, ms)
試しに、このようにしてみた。
Dim imageType As Integer = 1 ' 1:jpeg / 2:png
Dim ts As Task = WebView2.CoreWebView2.CapturePreviewAsync(imageType, ms)
Dim img As Image = Image.FromStream(ms)
Me.PictureBox1.Image = img
するとうまくいかない。
どうやらCapturePreviewAsyncメソッドが非同期で動くため
イメージがメモリーストリームに書き込まれる前にFromStreamで変換しているからだめらしい
多分WebView2コントロールでイベント処理をしないと画像が生成されないんだろう。
なもんで、こんな風にしてみた。
Public Function webCapture(WebView2 As WinForms.WebView2) As Image
'イメージ取得用のメモリーストリーム
Dim ms As New MemoryStream()
'WebView2の非同期画面キャプチャを実行
Dim imageType As Integer = 1 ' 1:jpeg / 2:png
Dim ts As Task = WebView2.CoreWebView2.CapturePreviewAsync(imageType, ms)
'試行回数
Dim retry As Integer = 100
'待機時間
Dim timeout As Integer = 100
' (待機時間)100ms * (試行回数)100回で最大10秒待つ
For i = 1 To retry
' スリープ処理
System.Threading.Thread.Sleep(timeout)
' イベントを処理させる
System.Windows.Forms.Application.DoEvents()
' CapturePreviewAsyncの非同期タスクが終了したか確認する
If ts.Status = TaskStatus.RanToCompletion Then
' CapturePreviewAsyncの結果ストリームからイメージを習得
Return Image.FromStream(ms)
End If
Next
' タイムアウト:イメージが取得できない
Return Nothing
End Function
上記のwebCapture関数をこう呼び出してimageを取得します。
'WebView2ブラウザコントロールで表示しているイメージ取得
Dim img As Image = webCapture(WebView21)
'取得したイメージ表示
Me.PictureBox1.Image = img
webCapture関数のポイントとしては
試行回数まで回しtaskスレッドのStatusが完了になるまでDoEventsをしながらループさせることにある。
おそらくWebView2コントロールにCapturePreviewAsyncを投げてもWebView2側で処理するイベントが終わらない限りイメージをメモリーストリームに生成できないのだろう。
だからWebView2コントロール側でイメージメモリーストリームを生成できるようにDoEventsを仕込んだループでイベントを処理する余地を与えてあげるのね。
そんで適当な時間同期できるようにSleepもしてやる。
こちらで確認した限りでは試行回数のループは1~2回程度で処理できているようだ。
同期処理的に画像ファイルを取得できるのが良い。
もし、非同期的に処理したいならtaskスレッドのStatusが完了になるまでタイマーとかで監視してもいいし、別スレッドで非同期に処理させてもいいんじゃないかな。
僕が作っているソフトの関係では同期的に画像がイメージが取得できる、この関数が非常に都合がいいのだけど。
多少、強引な気はするけど一応の目的は達成できたのでヨシとする。
本当は非同期で実行とかやるべきなんだろうけども(笑)
少し書き直したのがこちら
Public Function webCapture(WebView2 As Microsoft.Web.WebView2.WinForms.WebView2) As Image
Try
Dim ms As New System.IO.MemoryStream() 'イメージ取得用のメモリーストリーム
'WebView2の非同期画面キャプチャを実行
Dim ts As Task = WebView2.CoreWebView2.CapturePreviewAsync(Microsoft.Web.WebView2.Core.CoreWebView2CapturePreviewImageFormat.Png, ms)
'メモリーストリームに書き込み完了するまで待つ
Do While ms.Length = 0
System.Threading.Thread.Sleep(100) ' スリープ処理
System.Windows.Forms.Application.DoEvents() ' イベントを処理させる
Loop
Return Image.FromStream(ms) ' 結果ストリームからイメージを習得
Catch ex As Exception
End Try
Return Nothing ' イメージが取得できない
End Function