Angular で jsQR を使ってQRCodeを読み取る

はじめに

Angular で jsQR を使ってQRCodeを読み取る方法をまとめます。
この記事はAngular 2019アドベントカレンダーの記事です。

2019年に自分のメモ用に始めたこのblogですが「作ってみた」とか「このライブラリ試してみた」といった記事ばかりで他のアドベントカレンダーを見てると凹んできました。。。

2020年はもう少しフレームワーク自体のコードを読んでいきたいです。

今回の記事とは関係ないですがReactiveFormとHttpClientが好きで記事を書いているので貼っておきます。

AngularのHttpClientのエラー制御 - nananao blog

Angular formArray と仲良くなる - nananao blog

jsQR

jsQR は Typescript で書かれたQR code readerです。
以前 ZXing という QR code reader を Angular との併用で試して挫折した経験があったのですが jsQR のimport はとても簡単でした。

github.com

なぜ急にQRコードかというと以下の記事に触発されたからです。
私もiOSのPWAでもカメラが使える様になる日を夢見ているうちの一人です。

qiita.com

Angular から QRCode を読み取る

まずはインストールです。

$ npm install jsqr --save

videoタグから取得した動画をcanvasに描画し、getImageDataしてImageData.data: Uint8ClampedArrayを取得しjsQRに食わせています。

...
@ViewChild('video', {static: true}) videoElm: ElementRef;
@ViewChild('canvas', {static: true}) canvasElm: ElementRef;
...
const ctx = this.canvasElm.nativeElement.getContext('2d') as CanvasRenderingContext2D;

// videoタグから取得した動画をcanvasに描画
ctx.drawImage(this.videoElm.nativeElement, 0, 0, WIDTH, HEIGHT)
// getImageDataしてImageData.data: Uint8ClampedArrayを取得
const imageData = ctx.getImageData(0, 0, WIDTH, HEIGHT)
// jsQRに食わせる
const code = jsQR(imageData.data, imageData.width, imageData.height, { inversionAttempts: "dontInvert" })

if (code) {
    // qrcodeが検知されたらdialogをopenする。afterClosedで再びcheckImage()をよんで再開
    this.openDialog(code);
} else {
    // qrcodeが検知されないときは0.1秒間隔でcheckImage()をよぶ
    setTimeout(() => { this.checkImage(); }, 100)
}
...

作ったもののstackblitzを貼っておきます。
が、埋め込みの状態では permission deny となってしまうので stackblitz の画面に遷移して試して見てください。

stackblitz.com

まとめ

Angular で jsQR を使ってQRCodeを読み取る方法をまとめました。
手元でPWAにして iOS で開こうとしましたがやはりカメラが起動しませんでした。

明日は@shuheiさんです。