Vueはブラウザ側のコードスキャン機能を実装します

Vueはブラウザ側のコードスキャン機能を実装します

背景

少し前にブラウザカメラの取得とスキャンコード認識の機能を作りました。その際の知識ポイントと具体的なコード実装を整理して記事の内容にまとめました。

この記事では主に、 vueテクノロジースタックに基づくフロントエンド開発技術を使用して、ブラウザ側でカメラ📷を呼び出し、コードのスキャンと認識を行い、認識したQRコードに対してジャンプやその他の操作を行う方法について紹介します。この記事の内容は、背景紹介、実装効果、技術紹介、コード実装、要約などの部分に分かれています。

成果を達成する

この例では、ホームページと QR コードスキャンページの 2 つのメインページがあります。具体的な実装効果は、次の図に示されています。

  • ホームページ: SCAN QRCODEボタンをクリックすると、QR コード スキャン ページに入ります。
  • コード ページをスキャン: 初めて入力すると、獲取攝像頭訪問權限的系統提示框が表示される場合があります。[アクセスを許可] をクリックします。ページでカメラ データの読み込みと QR コードのキャプチャが開始されます。QR コードがキャプチャされると、QR コードが解析されます。解析が成功すると、認識が成功したことを示すポップアップ ウィンドウが表示されます。

オンライン体験: https://dragonir.github.io/h5-scan-qrcode

ヒント: カメラデバイスを備えたブラウザで縦向きモードでアクセスする必要があります。携帯電話の横画面と縦画面の検出に関するその他のヒントについては、私の別の記事「Gokudō ゲームにおけるフロントエンドの知識」をご覧ください。

技術紹介

WebRTC API

WebRTC (Web Real-Time Communications) は、ネットワーク アプリケーションまたはサイトが、仲介者の助けを借りずにブラウザー間で點對點(Peer-to-Peer)接続を確立し、ビデオ ストリームやオーディオ ストリーム、またはその他のデータの送信を実現できるようにするリアルタイム通信テクノロジです。 WebRTCに含まれる標準により、ユーザーはプラグインやサードパーティのソフトウェアをインストールせずに點對點(Peer-to-Peer)データ共有や電話会議を作成できるようになります。

3 つの主なインターフェース:

  • MediaStream : デバイスのカメラとマイクを介して同期されたビデオとオーディオのストリームを取得できます。
  • RTCPeerConnection : ピア間の安定した効率的なストリーミング伝送を構築するためにWebRTCで使用されるコンポーネントです。
  • RTCDataChannel : 任意のデータを送信するために、ブラウザ間で高スループット、低レイテンシのチャネルを確立できるようにします。

🔗詳しい学習についてはMDNをご覧ください: WebRTC_API

WebRTC アダプター

WebRTC仕様は比較的健全で安定していますが、すべてのブラウザがその機能をすべて実装しているわけではありません。一部のブラウザではWebRTC APIにプレフィックスを追加する必要があります。

WebRTC組織は、さまざまなブラウザでWebRTCを実装する際の互換性の問題を解決するために、 githubWebRTC適配器(WebRTC adapter)を提供しています。このアダプタは、 WebRTCサポートするすべてのブラウザでプレフィックスやその他の互換性回避策を記述することなく、 WebRTC仕様で説明されているとおりにコードを記述できるJavaScript墊片です。

🔗 MDNさらに詳しく学ぶ: WebRTC アダプター

コア API navigator.mediaDevices.getUserMedia

Web ページは、カメラを呼び出すためにgetUserMedia APIを呼び出す必要があります。MediaDevices.getUserMedia MediaDevices.getUserMedia()は、ユーザーにメディア入力の使用許可を求めます。メディア入力は、要求されたメディア タイプのトラックを含むMediaStreamを生成します。このストリームには、ビデオ トラック (カメラ、ビデオ キャプチャ デバイス、画面共有サービスなどのハードウェアまたは仮想ビデオ ソースから)、オーディオ トラック (マイク、 A/D轉換器などのハードウェアまたは仮想オーディオ ソースから)、およびその他のトラック タイプを含めることができます。

これはPromiseオブジェクトを返します。このオブジェクトは、成功した場合はMediaStream對象resolveてコールバックします。ユーザーが使用許可を拒否した場合、または必要なメディア ソースが利用できない場合は、 promise reject PermissionDeniedErrorまたはNotFoundErrorコールバックします。 (返されたpromise對象は、ユーザーが必ずしも Promise を許可するか拒否するかを選択する必要がないため、 resolvereject場合があります。)

MediaDevices通常、 navigator.mediaDevicesを使用して取得できます。次に例を示します。

navigator.mediaDevices.getUserMedia(制約)
  .then(関数(ストリーム) {
    // このストリームを使用する
  })
  .catch(関数(エラー) {
    // エラーを処理する
  })

🔗詳しい情報についてはMDNをご覧ください: navigator.mediaDevices.getUserMedia

QRコード解析ライブラリJSQR

jsQR 、生の画像またはカメラ フィードを読み取り、その中のQR碼検索、抽出、解析する純粋なJavaScript QR コード解析ライブラリです。

jsQRを使用してウェブカメラ ストリームをスキャンする場合は、ビデオ ストリームからImageDataを抽出し、それをjsQRに渡す必要があります。

jsQR 、デコードされた圖像數據、およびスキャン動作をさらに構成するため可選的對象4パラメータを受け入れるメソッドをエクスポートします。

imageData : Uint8ClampedArray( 8位無符號整型固定數組) [r0, g0, b0, a0, r1, g1, b1, a1, ...]rgbaピクセル値。

const code = jsQR(imageData, 幅, 高さ, オプション);
if (コード) {
  console.log('QRコードが見つかりました!', code);
}

🔗詳細についてはgithubをご覧ください: jsQR

コードの実装

プロセス

コードスキャンのプロセス全体を下図に示します。ページが初期化され、まずブラウザがmediaDevices関連APIをサポートしているかどうかが確認され、ブラウザがカメラを呼び出します。呼び出しが失敗した場合は、失敗コールバックが実行されます。呼び出しが成功した場合は、ビデオ ストリームがキャプチャされ、次にコードがスキャンされて認識されます。認識可能な QR コードがスキャンされない場合は、スキャンが続行されます。コードが正常にスキャンされると、スキャン成功パターンが描画され、成功コールバックが実行されます。

以下の内容はプロセスを分割し、それぞれ対応する機能を実装します。

Scaner

ページ構造

まず、主に4部分で構成されるページ構造を見てみましょう。

  • プロンプトボックス。
  • コードボックスをスキャンします。
  • video : カメラでキャプチャされたビデオ ストリームを表示します。
  • canvas : QR コード認識用のビデオ フレームを描画します。
<テンプレート>
  <div class="スキャナー" ref="スキャナー">
    <!-- プロンプト ボックス: 互換性のないブラウザでプロンプトを表示するために使用されます-->
    <div class="banner" v-if="showBanner">
      <i class="close_icon" @click="() => showBanner = false"></i>
      <p class="text">現在のブラウザでコードをスキャンできない場合は、別のブラウザに切り替えてお試しください</p>
    </div>
    <!-- スキャンコードボックス: スキャンコードアニメーションを表示します-->
    <div class="カバー">
      <p class="line"></p>
      <span class="square 左上"></span>
      <span class="square 右上"></span>
      <span class="square 右下"></span>
      <span class="square 左下"></span>
      <p class="tips">QR コードをボックスに入れると自動的にスキャンされます</p>
    </div>
    <!-- ビデオ ストリームの表示 -->
    <ビデオ
      v-show="showPlay"
      クラス="ソース"
      ref="ビデオ"
      :width="ビデオWH.width"
      :height="ビデオWH.height"
      コントロール
    </ビデオ>
    <canvas v-show="!showPlay" ref="canvas" />
    <button v-show="showPlay" @click="run">開始</button>
  </div>
</テンプレート>

方法: 描画

  • 線を引きます。
  • 画像フレーム (コードのスキャンに成功した後に長方形を描くために使用します)。

// 線を描く drawLine (begin, end) {
  パスの開始位置を指定します。
  this.canvas.moveTo(begin.x, begin.y);
  this.canvas.lineTo(終了x、終了y);
  キャンバスの線幅を設定します。
  this.canvas.strokeStyle = this.lineColor;
  キャンバスのストローク
},
// 描画ボックス (場所) {
  if (this.drawOnfound) {
    this.drawLine(location.topLeftCorner、location.topRightCorner);
    this.drawLine(location.topRightCorner, location.bottomRightCorner);
    this.drawLine(location.bottomRightCorner, location.bottomLeftCorner);
    this.drawLine(location.bottomLeftCorner、location.topLeftCorner);
  }
},

方法: 初期化

  • サポートされているかどうかを確認してください。
  • カメラをオンにします。
  • 成功と失敗の処理。

// 初期化セットアップ () {
  // ブラウザが MediaDevices.getUserMedia() に搭載されたメソッドをサポートしているかどうかを判定します if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    this.previousCode = null;
    this.parity = 0;
    this.active = true;
    this.canvas = this.$refs.canvas.getContext("2d");
    // カメラモードを取得します。デフォルト設定は背面カメラです。const facingMode = this.useBackCamera ? { exact: 'environment' } : 'user';
    // カメラビデオ処理 const handleSuccess = stream => {
       if (this.$refs.video.srcObject !== 未定義) {
        this.$refs.video.srcObject = ストリーム;
      } そうでない場合 (window.videoEl.mozSrcObject !== 未定義) {
        this.$refs.video.mozSrcObject = ストリーム;
      } それ以外の場合 (window.URL.createObjectURL) {
        this.$refs.video.src = window.URL.createObjectURL(ストリーム);
      } それ以外の場合 (window.webkitURL) {
        this.$refs.video.src = window.webkitURL.createObjectURL(ストリーム);
      } それ以外 {
        this.$refs.video.src = ストリーム;
      }
      // ユーザーにプログレス バーをドラッグさせたくない場合は、playsinline 属性を直接使用できます。webkit-playsinline attribute this.$refs.video.playsInline = true;
      const playPromise = this.$refs.video.play();
      再生Promise.catch(() => (this.showPlay = true));
      // ビデオの再生が開始されたら、識別のためにコードを定期的にスキャンします。playPromise.then(this.run);
    };
    // ビデオストリームをキャプチャするnavigator.mediaDevices
      .getUserMedia({ ビデオ: { 向きモード } })
      .then(ハンドル成功)
      .catch(() => {
        ナビゲーター.メディアデバイス
          .getUserMedia({ビデオ: true })
          .then(ハンドル成功)
          .catch(エラー => {
            this.$emit("error-captured", error);
          });
      });
  }
},

方法: 定期スキャン

走る () {
  アクティブの場合
    // ブラウザは、次の再描画の前にループ内でスキャン メソッド requestAnimationFrame(this.tick) を呼び出します。
  }
},

メソッド: 成功コールバック

// QRコード認識成功イベント処理が見つかりました(コード){
  if (this.previousCode !== コード) {
    this.previousCode = コード;
  } それ以外の場合 (this.previousCode === code) {
    this.parity += 1;
  }
  (このパリティ>2)の場合{
    this.active = this.stopOnScanned ? false の場合、 true;
    this.parity = 0;
    this.$emit("code-scanned", コード);
  }
},

方法: 停止

// 終止符 fullStop () {
  (this.$refs.video && this.$refs.video.srcObject) の場合 {
    // ビデオ ストリーム シーケンス トラックを停止します。this.$refs.video.srcObject.getTracks().forEach(t => t.stop());
  }
}

方法: スキャン

  • ビデオフレームを描画します。
  • 識別のためにQRコードをスキャンします。

// 定期的なコードスキャンと認識 tick () {
  // ビデオは準備段階にあり、十分なデータが読み込まれています if (this.$refs.video && this.$refs.video.readyState === this.$refs.video.HAVE_ENOUGH_DATA) {
    // キャンバスにビデオの描画を開始します。this.$refs.canvas.height = this.videoWH.height;
    this.$refs.canvas.width = this.videoWH.width;
    this.canvas.drawImage(this.$refs.video, 0, 0, this.$refs.canvas.width, this.$refs.canvas.height);
    // getImageData() はキャンバス上の指定された四角形のピクセル データをコピーします。const imageData = this.canvas.getImageData(0, 0, this.$refs.canvas.width, this.$refs.canvas.height);
    code = false とします。
    試す {
      // QR コードを認識する code = jsQR(imageData.data, imageData.width, imageData.height);
    } キャッチ (e) {
      コンソールエラー(e);
    }
    // QRコードが認識された場合、長方形のボックスを描画します if (code) {
      this.drawBox(コードの場所);
      // 成功したイベント処理を識別します this.found(code.data);
    }
  }
  これを実行してください。
},

親コンポーネント

Scanerの親コンポーネントは主にページを読み込み、 Scanerスキャン結果のコールバックを表示します。

ページ構造

<テンプレート>
  <div class="scan">
    <!-- ページナビゲーションバー-->
    <div class="nav">
      <a class="close" @click="() => $router.go(-1)"></a>
      <p class="title">QR コードをスキャン</p>
    </div>
    <div class="スクロールコンテナ">
      <!-- スキャンコードサブコンポーネント-->
      <スキャナー
        v-on:code-scanned="コードスキャン済み"
        v-on:error-captured="エラーキャプチャ済み"
        :スキャン時に停止="true"
        :draw-on-found="true"
        :responsive="false"
      />
    </div>
  </div>
</テンプレート>

親コンポーネントメソッド

Scaner を '../components/Scaner' からインポートします。

エクスポートデフォルト{
  名前: 'スキャン'、
  コンポーネント:
    スキャナー
  },
  データ () {
    戻る {
      エラーメッセージ: "",
      スキャン済み: ""
    }
  },
  メソッド: {
    コードスキャン済み(コード) {
      this.scanned = コード;
      タイムアウトを設定する(() => {
        alert(`コードをスキャンして解析に成功しました: $[code]`);
      }, 200)
    },
    errorCaptured(エラー) {
      スイッチ (エラー.name) {
        ケース「NotAllowedError」:
          this.errorMessage = "カメラの許可が拒否されました。";
          壊す;
        「NotFoundError」の場合:
          this.errorMessage = "接続されたカメラがありません。";
          壊す;
        ケース「NotSupportedError」:
          this.errorMessage =
            「このページは安全でないコンテキストで提供されているようです。」;
          壊す;
        ケース「NotReadableError」:
          this.errorMessage =
            「カメラにアクセスできませんでした。すでに使用されていますか?」;
          壊す;
        ケース「OverconstrainedError」:
          this.errorMessage = "制約はインストールされているカメラと一致しません。";
          壊す;
        デフォルト:
          this.errorMessage = "不明なエラー: " + error.message;
      }
      コンソールエラー(このエラーメッセージ);
     alert('カメラの呼び出しに失敗しました');
    }
  },
  マウントされた(){
    var str = navigator.userAgent.toLowerCase();
    var ver = str.match(/cpu iphone os (.*?) like mac os/);
    // テストの結果、iOS 10.3.3未満のシステムではカメラを正常に呼び出すことができません if (ver && ver[1].replace(/_/g,".") < '10.3.3') {
     alert('カメラの呼び出しに失敗しました');
    }
  }

完全なコード

🔗 github: https://github.com/dragonir/h5-scan-qrcode

要約する

アプリケーション拡張機能

ブラウザ経由でカメラを呼び出してスキャン・識別することで、以下のような機能が実現できると思います。 ブラウザ側のコードをスキャンすることで、他にどんな很哇塞🌟機能やアプリケーションが実現できると思いますか😂

  • リンクジャンプ。
  • 価格のお問い合わせ。
  • ログイン認証。
  • ファイルのダウンロード。

互換性

  • adapterを使用しても、一部のブラウザではgetUserMedia APIがサポートされません。
  • バージョンのブラウザ( iOS 10.3未満など)およびAndroidニッチブラウザ( IQOO組み込みブラウザなど)は互換性がありません。
  • QQ微信の内蔵ブラウザは呼び出せません。

参考文献

[1] WebRTCで静止画を撮影する

[2] mediaDevices APIを使用してJavaScriptでカメラを選択する

[3] JavaScriptを使用してデバイスの前面カメラと背面カメラにアクセスする方法

著者: dragonir 記事URL: https://www.cnblogs.com/dragonir/p/15405141.html

Vue のブラウザ側コードスキャン機能の実装に関するこの記事はこれで終わりです。より関連性の高い vue ブラウザコードスキャンのコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。皆様、今後とも 123WORDPRESS.COM を応援してください。

以下もご興味があるかもしれません:
  • Vue プロジェクトでのスキャンコード決済の実装例 (デモ付き)
  • Vue は QR コード スキャン機能を実装します (スタイル付き)
  • Vueはコードスキャン機能を実装
  • Vue+abp WeChat スキャンコード ログイン実装コード例
  • vue WeChat スキャンコード ログイン (カスタム スタイル)

<<:  docker に openjdk をインストールして jar パッケージを実行する方法

>>:  HTML テーブル マークアップ チュートリアル (29): セルのライト境界線の色属性 BORDERCOLORLIGHT

推薦する

iframeをカプセル化するvueコンポーネントを開発する

目次1. コンポーネントの紹介2. コンポーネントの内部構造とロジック1. コード組織構造2. マッ...

シェルスクリプトによるDockerコンテナの起動順序の制御の詳細な説明

1. 遭遇した問題分散プロジェクトの展開プロセスでは、サーバーの再起動後にアプリケーション(データベ...

HTML/CSS での空白処理とページ内の空白を保持する方法

HTML の空白ルールHTML では、コンテンツ内の複数のスペースは通常 1 つとみなされ、連続する...

Vueは書籍ショッピングカートの機能を実現

この記事の例では、書籍ショッピングカート機能を実現するためのVueの具体的なコードを参考までに共有し...

Vue の proto ファイルの関数呼び出しのグラフィカルな説明

1. protoをコンパイルするすべての .proto ファイルを保存するために、src フォルダー...

Docker 実行時にユーザーとグループを管理する方法

Docker はプロセスを中核としてシステムリソースを分離する管理ツールです。分離は、オペレーティン...

CSS 背景と境界タグの例の詳細な説明

1. CSS背景タグ1.背景色を設定するbackground-ground-color プロパティは...

CentOS/RHEL システムで VLAN タグ付きイーサネット カードを使用する方法

シナリオによっては、Linux サーバー (CentOS/RHEL) の同じイーサネット カード (...

jQuery の CSS スタイル属性 css() と width() の完全ガイド

目次1. css() の基本的な使用法: 1.1 CSSプロパティを取得する1.2 CSSプロパティ...

SecureCRT に基づくリモート Linux ホストへのファイルのアップロードとダウンロードのグラフィカルな手順

wget や curl ツールを使用して、Linux サーバーで大規模なネットワーク ファイルを直接...

入力が完了したことを検出し、次のコンテンツを自動的に入力する HTML を実装する方法

前回の記事では、入力完了の簡単な検出を実現しましたが、今回はさらに一歩進んで、入力が完了した後に次の...

海外でダウンロードできる25個の新鮮で便利なアイコンセット

1. Eコマースアイコン2. アイコンスイーツ2 3. 携帯電話アイコンパック4. 旗アイコンセット...

Vue の基本的な手順の例のグラフィック説明

目次1. v-on指令1. 基本的な使い方2. 糖衣構文3. イベントパラメータ4. イベント修飾子...

jQuery はラブエフェクトをクリックする

この記事では、jQueryのクリック時のラブエフェクトの具体的なコードを参考までに共有します。具体的...

JavaScript プロトタイプチェーンを理解するための 2 つの図

目次1. プロトタイプの関係2. プロトタイプチェーン3. 結論序文:前回の記事では、JavaScr...