2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

webView2コントロールの画面キャプチャをしたくて

Last updated at Posted at 2021-10-08

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
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?