我々の生活にQRコードが浸透してから何年経ったでしょうか。QRコードの読み取り機能はOS標準で可能になり、もはや「QRコードアプリ」すら不要な時代になりました。
一方でブラウザにおけるQRコードの取り扱いは、全くサポートされていませんでした。今まではゼロから実装した有志のライブラリを使ってQRコードの読み取りを実装していました。
しかしBarcode Detection APIの実装で、そういったライブラリも不要になるかもしれません。
Shape Detection API
近年になって、ブラウザにShape Detection APIというAPIの策定・実装が始まっています。
Shape Detection APIは現在以下の2つのAPIから構成されています。
- Barcode Detection API
- Face Detection API
また、「親戚」として、OCRを実現するText Detection APIというものも存在します。
Barcode Detection APIはバーコードや二次元コードを読み取るためのAPIです。画像データさえ渡せばあとは自動でデータを検出してくれます。
Face Detection APIはその名の通り顔を検出するためのAPIです。Barcode Detection APIと同様に画像を渡すだけで動作します。
このうちBarcode Detection APIがChrome 83からはフラグなしでの使用が可能になるため、ここで紹介したいと思います。
ブラウザ対応状況
ブラウザの対応状況は以下のとおりです。
-
Chrome
- Barcode Detection API(Chrome 83)
- Face Detection API(フラグ付き)
- Text Detection API(フラグ付き)
-
Firefox
- 未対応
-
Safari
- 未対応
Barcode Detection APIの使い方
Barcode Detection APIを使って、QRコードを読み込んでみましょう。Barcode Detection APIを使用するには、ページがlocalhostまたはhttpsで通信している必要があります。
Barcode Detection APIの使い方は簡単です。windowオブジェクト直下に BarcodeDetector
が追加されているので、まずはサポートされているバーコードフォーマットを調べます。
(async function main() {
// 対応フォーマットの取得
const formats = await BarcodeDetector.getSupportedFormats();
console.log(formats);
})();
BarcodeDetector.getSupportedFormats
メソッドはサポートされているバーコードフォーマットの文字列配列として解決するPromiseを返します。PC上で実行している場合などは空配列が返ってくるかもしれません。空配列の場合はバーコード検出はサポートされていないということになります。そういった場合はAndroidなどで実行してみましょう。
返ってきた配列の中に "qr_code"
が存在すればQRコードを読み込むことができます。あとは BarcodeDetector
のインスタンスを作り、 detect
メソッドを呼び出すだけです。
例えば以下のようにします:
(async function main() {
// 対応フォーマットの取得
const formats = await BarcodeDetector.getSupportedFormats();
if(!formats.includes('qr_code')) {
throw new Error('QRコードがサポートされていません…');
}
// 画像の読み込み(qr.jpgというファイルを読むこむ場合)
const img = await fetch('./qr.jpg').then((res) => res.blob());
// 検出
const detector = new BarcodeDetector();
const detectionList = await detector.detect(img);
console.log(detectionList);
})();
detect
の対象にできるのは現時点では以下のものです:
- img要素
- video要素
- canvas要素
- Blob
- ImageData
- ImageBitmap
- OffscreenCanvas
detect
メソッドを実行することで検出オブジェクトの配列として解決するPromiseを得ることができます。何も検出できなかった場合は空の配列になります。
配列には検出オブジェクトの情報が入っています。以下のような形式です:
const detection = {
boundingBox: {
x: 0,
y: 0,
width: 100,
height: 100,
top: 10,
right: 10,
bottom: 10,
left: 10
},
rawValue: "QRコードに書き込まれた文字列",
format: "qr_code",
cornerPoints: [
{x: 40, y: 40},
{x: 250, y: 40},
{x: 250, y: 250},
{x: 40, y: 250}
]
};
boundingBox
はQRコードが含まれている範囲の矩形です。rawValue
はQRコードの値がそのまま入っています。format
はバーコードのフォーマットで、QRコードを読み込んだ場合は "qr_code"
になります。cornerPoints
にはQRコードの各頂点の座標が左上・右上・右下・左下の順番で入っています。
detect
メソッドから得られた検出オブジェクト配列をfor文などで回せば、欲しいデータを得ることができます。
(async function main() {
// 対応フォーマットの取得
const formats = await BarcodeDetector.getSupportedFormats();
if(!formats.includes('qr_code')) {
throw new Error('QRコードがサポートされていません…');
}
// 画像の読み込み(qr.jpgというファイルを読みこむ場合)
const img = await fetch('./qr.jpg').then((res) => res.blob());
// 検出
const detector = new BarcodeDetector();
const detectionList = await detector.detect(img);
// 検出できたオブジェクトの配列をforで回す
for(const detected of detectionList) {
console.log(detected.rawValue);
}
})();
検出フォーマットの限定
BarcodeDetector
はデフォルトでは、サポートされている全てのフォーマットを検出しようとします。これはときにパフォーマンスに悪影響を与えます。
検出フォーマットを限定したい場合、たとえばQRコードのみを検出する場合、コンストラクタにオプションを渡します。
const detector = new BarcodeDetector({
formats: ['qr_code']
});
カメラとの連動
QRコードを読み込むときは、一般にカメラが使用されると思います。カメラ映像と共に使用する例を紹介します。
(async function main() {
// 対応フォーマットの取得
const formats = await BarcodeDetector.getSupportedFormats();
if(!formats.includes('qr_code')) {
throw new Error('QRコードがサポートされていません…');
}
// 背面カメラへアクセスする
const stream = await navigator.mediaDevices.getUserMedia({
video: {
facingMode: { exact: "environment" }
}
});
// カメラをvideo要素と結びつける
const video = document.createElement('video');
video.srcObject = stream;
// 画面にvideo要素を追加する(確認用)
video.width = 720;
video.height = 480;
document.body.appendChild(video);
// 再生を開始する
await video.play();
// 検出をQRコードのみに限定する
const detector = new BarcodeDetector({
formats: ['qr_code']
});
// 一定時間ごと(ここでは500ミリ秒間隔)に
// QRコードの検出を試みる
setInterval(async () => {
const detectionList = await detector.detect(video);
for(const detected of detectionList) {
console.log(detected.rawValue);
}
}, 500);
})();
まとめ
今まではQRコードの検出に有志のライブラリを用いていましたが、これからは標準のAPIのみで検出できるようになるかもしれません。Barcode Detection APIは実質的にAndroidのみの対応となっていますが、他のプラットフォームやブラウザでも対応されれば嬉しいですね。
また、Face Detection APIやText Detection APIについてもほぼ同様の方法で使用できます。こちらも機会があれば紹介したいと思います。