webview4delphi(WebView2)でブラウザのカメラ(WebCam)映像を取得する機能をDelphiから使用する
Delphi 11.3(Community Edition)でwebview4delphiを使ってブラウザのカメラ(WebCam)映像を取得する機能(navigator.mediaDevices.getUserMedia)を使用します。
(1)はじめに
Windows10の場合はMicrosoft WebView2 ランタイムのインストールを以下のURLを参照してインストールしてください。
https://mam-mam.net/delphi/tedgebrowser.html
「WebView2Loader.dll」も、
https://mam-mam.net/delphi/tedgebrowser.html
を参照してください。
webview4delphiのインストールは以下を参考にDelphiにインストールしてください
https://mam-mam.net/delphi/tedgebrowser_webview4delphi.html
(2)プロジェクトの作成と保存
Delphi IDEを起動し、「ファイル」⇒「Windows VCLアプリケーション -Delphi」をクリックします「ファイル」⇒「すべて保存 Ctrl+Shift+S」をクリックして、プロジェクト保存用フォルダを作成して ユニット(Unit1)とプロジェクト(Project1)を保存します
次に、「プロジェクト」⇒「Project1をビルト Shift+F9」をクリックして事前に一度コンパイルしておきます。(フォルダが生成される)
プロジェクトフォルダ内の「win32\degub」フォルダに「files」フォルダを作成します。
「win32\degub\files」フォルダ内に、以下のHTMLファイル「index.html」を作成してUTF-8で保存してください。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <script> let video,prev,prev_ctx,w,h,strm=null,isStart=false; window.addEventListener('load',function(event){ video=document.createElement('video'); video.setAttribute("autoplay",""); video.setAttribute("muted",""); video.setAttribute("playsinline",""); video.onloadedmetadata = function(e){video.play();}; prev=document.createElement("canvas"); prev_ctx=prev.getContext("2d", {willReadFrequently:true}); console.log("event:loaded"); }); function start(){ isStart=true; //カメラ使用の許可ダイアログが表示される navigator.mediaDevices.getUserMedia( //マイクはオフ, カメラの映像は前面カメラで640×480を希望する //背面カメラを希望する場合は "facingMode":"environment" //前面カメラを希望する場合は "facingMode":"user" {"audio":false,"video":{"facingMode":"user","width":640,"height":480}} ).then( //許可された場合 function(stream){ video.srcObject = stream; strm=stream; //0.5秒後にスキャンする setTimeout(Scan,500,true); } ).catch( //許可されなかった場合(Permission denied) function(err){ console.log("error:"+err.message);//■エラー } ); } function stop(){ isStart=false; if(strm!==null){ strm.getTracks().forEach(track => track.stop()); strm=null; } } function Scan(first){ if(first){ //選択された幅高さ w=video.videoWidth; h=video.videoHeight; //内部のサイズ prev.setAttribute("width",w); prev.setAttribute("height",h); } if(isStart){ prev_ctx.drawImage(video,0,0,w,h); let src=prev.toDataURL("image/png"); console.log("image:"+src); if(isStart){ setTimeout(Scan,100,false); } } } </script> </body> </html>
(3)フォームの設計
フォームにTButton×2個と、TMemo1×1個、TImage×1個、TWVBrowser×1個、TWVWindowParent×1個をドラッグ&ドロップします
(4)ソースコードの記述
フォームのButton1をダブルクリックしてソースコードを記述します。
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, uWVWinControl, uWVWindowParent, uWVBrowserBase, uWVBrowser, uWVTypes, uWVConstants, uWVTypeLibrary, uWVLoader, uWVInterfaces, uWVCoreWebView2Args, uWVLibFunctions, uWVCoreWebView2CookieList, uWVCoreWebView2Cookie, uWVCoreWebView2HttpRequestHeaders, uWVCoreWebView2, System.Json, Vcl.ExtCtrls, Vcl.Imaging.pngimage; type TForm1 = class(TForm) WVBrowser1: TWVBrowser; WVWindowParent1: TWVWindowParent; Button1: TButton; Memo1: TMemo; Button2: TButton; Image1: TImage; procedure FormCreate(Sender: TObject); procedure WVBrowser1AfterCreated(Sender: TObject); procedure WVBrowser1DevToolsProtocolEventReceived(Sender: TObject; const aWebView: ICoreWebView2; const aArgs: ICoreWebView2DevToolsProtocolEventReceivedEventArgs; const aEventName: wvstring; aEventID: Integer); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private 宣言 } png:TPngImage; strm:TMemoryStream; public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} uses System.NetEncoding, System.JSON.Serializers, System.IOUtils; procedure TForm1.Button1Click(Sender: TObject); begin Button1.Enabled:=False; Button2.Enabled:=True; //Javascriptのカメラ映像取得の開始 WVBrowser1.ExecuteScript('start()',1); Memo1.Lines.Add('開始'); end; procedure TForm1.Button2Click(Sender: TObject); begin Button1.Enabled:=True; Button2.Enabled:=False; //Javascriptの位置情報取得を開始する WVBrowser1.ExecuteScript('stop()',1); Memo1.Lines.Add('停止'); end; procedure TForm1.FormCreate(Sender: TObject); var ct:integer; begin Button1.Enabled:=False; Button2.Enabled:=False; Button1.Caption:='カメラ映像取得'; Button2.Caption:='停止'; Image1.Proportional:=True; Image1.Stretch:=True; Memo1.Lines.Clear; strm:=TMemoryStream.Create; png:=TPngImage.Create; WVWindowParent1.Browser:=WVBrowser1; if GlobalWebView2Loader.InitializationError then begin ShowMessage(GlobalWebView2Loader.ErrorMessage); end else begin ct:=0; while (ct<20) and (not GlobalWebView2Loader.Initialized) do begin sleep(500); Application.ProcessMessages; inc(ct); end; if GlobalWebView2Loader.Initialized then begin WVBrowser1.CreateBrowser(WVWindowParent1.Handle); //参考: //ユーザーエージェントをWebView以外に変更するとGoogleログインも可能 WVBrowser1.UserAgent:= 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'+ ' AppleWebKit/537.36 (KHTML, like Gecko)'+ ' Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53'; end else begin ShowMessage('WebView2初期化失敗'); end; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin strm.Free; png.Free; end; procedure TForm1.WVBrowser1AfterCreated(Sender: TObject); begin //以下必須 WVWindowParent1.UpdateSize; //ローカルの「files」ディレクトリを //「https://demo」に割り当てる WVBrowser1.CoreWebView2.SetVirtualHostNameToFolderMapping( 'demo', PWideChar(ExtractFilePath(Application.ExeName)+'files'), COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_ALLOW ); //コンソールの使用を申請する WVBrowser1.CallDevToolsProtocolMethod( 'Console.enable', '{}', 0 ); //コンソールにメッセージが出力された時に //[OnDevToolsProtocolEventReceived]イベントaEventID=1としてを発生させる WVBrowser1.SubscribeToDevToolsProtocolEvent('Console.messageAdded',1); //ローカルPCにある「.\files\index.html」を表示させる WVBrowser1.Navigate('https://demo/index.html'); end; procedure TForm1.WVBrowser1DevToolsProtocolEventReceived(Sender: TObject; const aWebView: ICoreWebView2; const aArgs: ICoreWebView2DevToolsProtocolEventReceivedEventArgs; const aEventName: wvstring; aEventID: Integer); type TJsonMsg=record column:Integer; level:String; line:Integer; source:String; text:String; url:String; end; TJsonMessage=record message:TJsonMsg; end; var pwc:PWideChar; s:TJsonSerializer; res:TJsonMessage; b:TBytes; begin if aEventID=1 then begin aArgs.Get_ParameterObjectAsJson(pwc); s:=TJsonSerializer.Create; res:=s.Deserialize<TJsonMessage>(pwc); if res.message.text='event:loaded' then begin Button1.Enabled:=True; end else if pos('error:',res.message.text,1)=1 then begin Memo1.Lines.Add('エラー:'+res.message.text.Substring(6)); Button1.Enabled:=True; end else if pos('image:',res.message.text,1)=1 then begin //Memo1.Lines.Add(res.message.text.Substring(28,30)); //Memo1.Lines.Add(res.message.text.Substring(6,30)); b:=TNetEncoding.Base64.DecodeStringToBytes(res.message.text.Substring(28)); strm.Size:=0; strm.Write(b,length(b)); strm.Position:=0; png.LoadFromStream(strm); //画面のちらつきを抑える処理 LockWindowUpdate(Self.Handle); Image1.Picture.Bitmap.Assign(png); LockWindowUpdate(0); //画面のちらつきを抑える処理の解除 end end; end; initialization var cachepath:string; begin cachepath:=ExtractFilePath(Application.ExeName) + 'cache'; //キャッシュを削除する if DirectoryExists(cachepath) then TDirectory.Delete(cachepath,true); // GlobalWebView2Loaderをロードして初期化 GlobalWebView2Loader := TWVLoader.Create(nil); //キャッシュやクッキー等の保存場所を指定する GlobalWebView2Loader.UserDataFolder := cachepath; GlobalWebView2Loader.StartWebView2; end; end.
(5)「WebView2Loader.dll」ファイルを実行ファイルと同じフォルダ内にコピーする
「C:\Program Files (x86)\Embarcadero\Studio\22.0\Redist\win32\WebView2Loader.dll」
ファイルを、実行ファイルと同じフォルダ内(プロジェクト保存フォルダ\Win32\Debug)にコピーします
(A)「Debug」ビルトで 「Windows 32ビット」 |
プロジェクト保存フォルダ\Win32\Debug |
(B)「Debug」ビルトで 「Windows 64ビット」 |
プロジェクト保存フォルダ\Win64\Debug |
(C)「Release」ビルトで 「Windows 32ビット」 |
プロジェクト保存フォルダ\Win32\Release |
(D)「Release」ビルトで 「Windows 64ビット」 |
プロジェクト保存フォルダ\Win64\Release |
(6)実行する
パソコンにカメラが搭載されていない場合は、パソコンにカメラを接続してください。
「実行」⇒「実行」をクリックすると実行します。
しばらく待つと「カメラ映像取得(Button1)」ボタンが有効になります。
「カメラ映像取得(Button1)」ボタンをクリックしてください。
カメラを使用するダイアログが表示された場合は「許可」をクリックしてください。