トップへ(mam-mam.net/)

Webview4Delphi(WebView2)でブラウザのカメラ(WebCam)映像を取得する機能をDelphiから使用する ~Delphiソースコード集

検索:

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)」ボタンをクリックしてください。
カメラを使用するダイアログが表示された場合は「許可」をクリックしてください。

カメラを使用するダイアログ
カメラ映像が表示されます