QR コードが好きな気がする zaru です。今回は暇だったので QR コードを連続で読み取れたら良いな〜と思ったので、QR コードを連続で読み取れる Web アプリを作りました。たぶん QR コードを読み取る仕事をしている人や、趣味の人には役に立つと思います。
- DEMO app https://lightning-qr.zaru.dev/
- GitHub repository https://github.com/zaru/lightning-qr-reader
カメラ機能のついているブラウザでアクセスしてみてください。

ブラウザでカメラにつなげる

MediaDevices.getUserMedia()
API を使うとブラウザからカメラに接続することができます。
_getStream(): Promise<MediaStream> {
const config = {
video: {
audio: false,
facingMode: { exact: 'environment' }
}
}
return navigator.mediaDevices.getUserMedia(config)
}
facingMode
オプションでカメラの前面・背面を決められます。 facingMode: "user"
で前面に facingMode: { exact: "environment" } }
で背面になります。

ここで取得したカメラを <video>
タグに出力することで画面上にカメラの映像を映すことができます。
// this.video = this.document.getElementById('video') as HTMLVideoElement
async showStream(): Promise<void> {
this.video.srcObject = await this._getStream()
this.video.addEventListener('loadedmetadata', () => {
this.video.play()
})
}
カメラの映像を画像にして QR コードを解析する

QR コードの解析は jsQR にお任せします。そのために <video>
の映像を画像として渡してあげる必要がありますので、<canvas>
に渡して画像に変換してあげます。
_syncCanvas(): void {
this.ctx.drawImage(this.video, 0, 0, this.video.videoWidth, this.video.videoHeight)
const data = this.ctx.getImageData(0, 0, this.video.videoWidth, this.video.videoHeight).data
const code = jsQR(data, this.video.videoWidth, this.video.videoHeight)
}
画像を常に抽出するのに requestAnimationFrame
を使うといい感じのパフォーマンスでブラウザがやってくれます。全体のコードはこちらを参照してください。
this.window.requestAnimationFrame(() => this._syncCanvas())

これでもうほぼ完成です。getUserMedia
楽しくて良いですね。