BarcodeDetectorとは?
一部のブラウザ(AndroidのChrome等)に標準搭載されている1次元/2次元(QRコード)のバーコード読み取り機能です。
現時点では"Experimental"(実験的な機能)との事です。
今の所で使えそうなのはAndroidな感じですね。
※対応ブラウザ等、詳しくは下記のMDNの解説ページをご確認下さい。
・MDNのBarcodeDetectorページ
前提条件
要HTTPSです。
使い方?
const detector = new window.BarcodeDetector();
const list = await detector.detect(imagedata, canvas.width, canvas.height);
まずwindowからBarcodeDetectorを生成して...
ですが、TypeScriptではBarcodeDetector()部分がエラーとなります。
#正式な機能になったらサポートされるんですよね? きっと...
"手っ取り早く"使えるようにする!
windowに存在しないBarcodeDetector()を、とりあえず存在する事にしましょう。
という訳で同じソースファイル上に、
//windowにBarcodeDetectorを生やす
declare global {
interface Window {
BarcodeDetector: any;
}
}
...を追加します。
ここは"手っ取り早く"なのでanyでお茶を濁します!
するとBarcodeDetector()のエラーが消えました!
※DevelopersIOの解説記事が大変参考になりました!
今回は記事中の"パターン4"の方法になります。
もしご自身の環境で上手く行かないヨという場合は、他パターンに代えてお試し下さい m(__)m
・TypeScript で window 直下にいろいろ生やしたりグローバル変数を定義する
改めて使い方!
//BarcodeDetector生成
const detector = new window.BarcodeDetector();
//BarcodeDetectorでimagedataを認識させる
//(imagedata,戻り値については上記MDNページのメソッド"detect()"を参照して下さい)
const list = await detector.detect(imagedata, canvas.width, canvas.height);
//認識できた場合、listに要素が入ります
//(ここではバーコードの内容をアラートで表示)
for (const detected of list) {
alert(`${detected.rawValue}`);
}
ReactのApp.tsx全文
videoを回して200ms毎に判定させて居ます。
"終了はブラウザを閉じる"、"エラー処理なし"という動く環境でしか動かない適当コードですがご参考まで...(それでもチョット長い)
←クリックで展開(長いので畳みました)
import React, { useRef, useEffect, useCallback } from 'react';
import './App.css';
//windowにBarcodeDetectorを生やす
declare global {
interface Window {
BarcodeDetector: any;
}
}
//横・縦幅(てきとう)
const width = 300;
const height = 300;
function App() {
const videoRef = useRef<HTMLVideoElement>(null);
async function checkImage() {
let canvas = document.createElement("canvas");
if (videoRef === null || videoRef.current === null) {
return null;
}
const { videoWidth, videoHeight } = videoRef.current;
canvas.width = videoWidth;
canvas.height = videoHeight;
const context = canvas.getContext("2d");
if (context === null || videoRef.current === null) {
return null;
}
context.drawImage(videoRef.current, 0, 0, canvas.width, canvas.height);
if (canvas.width === 0) {
setTimeout(() => { checkImage() }, 200);
return null;
}
const imagedata = context.getImageData(0, 0, canvas.width, canvas.height);
const detector = new window.BarcodeDetector();
const list = await detector.detect(imagedata, canvas.width, canvas.height);
let cnt = 0;
//認識できた場合、listに要素が入ります
//(ここではバーコードの内容をアラートで表示)
for (const detected of list) {
cnt++;
alert(`[${cnt}/${list.length}]${detected.rawValue}`);
}
setTimeout(() => { checkImage() }, 200);
}
useEffect(() => {
checkImage();
}, []);
//カメラのstreamを取得して返すメソッド
const getStream = useCallback(async () => {
const aspectRatio = width / height;
return await navigator.mediaDevices.getUserMedia({
video: {
facingMode: "environment",
width: {
ideal: 1024
},
aspectRatio
},
audio: false
});
}, [width, height]);
useEffect(() => {
let stream: MediaStream | null = null;
let video = videoRef.current;
//取得したstreamをvideo要素に流す
const setVideo = async () => {
stream = await getStream();
if (video === null || !stream) {
return;
}
video.srcObject = stream;
video.play();
};
setVideo();
//streamを停止させる
const cleanupVideo = () => {
if (!stream) {
return;
}
stream.getTracks().forEach((track) => track.stop());
if (video === null) {
return;
}
video.srcObject = null;
};
return cleanupVideo
}, [getStream]);
return (
<div className="App">
<body>
<video ref={videoRef} playsInline width={width} height={height} />
</body>
</div>
);
}
export default App;
使ってみた感想
手元にあったLenovoやTECLASTのタブレットやMotorolaのスマホで試しましたが、反応は中々良いと思いました。
またタブレットの箱に貼ってあった1次元、QRコード合計5個を画面に収まるように入れて読ませた所、上手く解像するタイミングでは5個を一括で認識しました。
環境は限られますが、現時点でも遊べる印象です。
"実験的"では仕事では採用できないとは思いますが、引き続き注目して行きたいと思います。
早く"Experimental"が取れて、環境を気にせず使えるようになって欲しいです!
※個人の感想です。
参考(本文に登場しない分)
videoタグの使い方について、
dashi296さんの
・Reactでカメラを使って画像を撮影するダイアログを実装してみた
ブラウザでのバーコード読み取りについて、
@kan_dai(TAM)さんの
・Webの技術だけで作るQRコードリーダー、
・続・Webの技術だけで作るQRコードリーダー
...その他、色々な情報を参考にさせて頂きました m(__)m