p5.js で外部ライブラリ不要の QRコード検出：Barcode Detection API の利用（要対応ブラウザ）

以下のような QRコードからの情報取得を、p5.js で行ってみた話です。
QRコードの読み取りについては、ブラウザの API を利用することによって外部ライブラリを使わずに実現できています（※ ただし、現時点で対応ブラウザが限定的という状況）。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> ＋ 「Barcode Detection API」による、外部ライブラリを使わない QRコード読み取りの続き。<br>QRコードを 3個に増やしてみて、大きさや傾きを変化させたものを混ぜ込んでみました。<br><br>得られた結果は、良い感じです！ <a href="https://t.co/dqrlfWZY8t">pic.twitter.com/dqrlfWZY8t</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1441980027826962436?ref_src=twsrc%5Etfw">September 26, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

この後の例では、QRコードが 1個の場合で説明などを行っていきます。

QRコード読み取りの処理に用いた API について、具体的には以下の「Barcode Detection API」で、API としては「Shape Detection API」の中の 1つとなるようです。

●Barcode Detection API - Web APIs | MDN
　https://developer.mozilla.org/en-US/docs/Web/API/Barcode_Detection_API
●The Shape Detection API: a picture is worth a thousand words, faces, and barcodes
　https://web.dev/shape-detection/

この API の対応状況については、[上記の MDN のサイト下部にある表（※ 下に掲載した画像）](https://developer.mozilla.org/en-US/docs/Web/API/Barcode_Detection_API#browser_compatibility)を見ると実装されているブラウザが限定的で、PC用のブラウザだと一部が実装されている、という状況のものがあるようです。

| ![Barcode Detection API の対応状況](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/e7ad313d-22e7-c21a-24d2-223aa71d9daa.jpeg) |
|:--|


今回は、PC用の Chrome で進めていきます。

## Barcode Detection API を試す
### Barcode Detection API が対応しているバーコードについて
[MDN の Barcode Detection API のページの「Supported barcode formats」という部分](https://developer.mozilla.org/en-US/docs/Web/API/Barcode_Detection_API#supported_barcode_formats)に書かれているとおり、QRコード以外の 2次元バーコードにも対応していて、それ以外にも 1次元バーコードに対応しているようです。

個人的には、利用したことがない 2次元バーコードが気になりました。

今回の記事では、QRコード作成サイトで生成した QRコードを使って試します。

### ソースコード
この後に、今回用いたソースコードを掲載します。
[p5.js Web Editor](https://editor.p5js.org/) で開発していて、その中の sketch.js の内容を取り出したものです。

ソースコードの冒頭にある Base64エンコードされた画像は、「p5.js」というテキストを埋め込んだ QRコードです（当初、p5.js Web Editor でファイルから読み込む形にしたところ、読み取り処理で CORS 関連のエラーが出たっぽかったので、Base64エンコードした画像を使ってみました）。
以下に、エンコード前の画像を掲載しておきます。
![QRコード](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/fb92fb85-caad-0346-2efa-8dcc2d40ba24.png)
その他のソースコードに関する補足は、ソースコードを掲載した後ろに書いていきます。

```javascript
let barcodeDetector, qrImg;
const qrBase64 =
  "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAK4AAACuAQMAAACVwqStAAAABlBMVEX///8AAABVwtN+AAAAxklEQVRIie2VQQ4DIQhFSTgAR+LqHGkOQGIFxlTTJu3KPwvZiI+N+XyQ6MSJ/6JFWGQSmeNwnGIBxO4rCksBzaI9APfkEZhTKjDOpsUbv/RyKy4je1Q+/b0Vj2fqCjC4vysOaWFnHE55NIe7ce0bEK4dw5fy2rH9mFMnj8TahcR061RjPZkIgImGkfkiwuEa7i6SD9lQeHyMvaLTSCGw1PpvpZajcY6UTfbB4fgStb3XDAJn07qFV3MDcBk5dMqi4/CJE7/iBfn28bp7vjGHAAAAAElFTkSuQmCC";

function preload() {
  qrImg = createImg(qrBase64);
  qrImg.hide();
}

function setup() {
  noLoop();
  createCanvas(400, 400);
  background(220);

  if (!("BarcodeDetector" in window)) {
    console.log("Barcode Detector is not supported by this browser.");
  } else {
    console.log("Barcode Detector supported!");
    barcodeDetector = new BarcodeDetector();
  }
  BarcodeDetector.getSupportedFormats().then((supportedFormats) => {
    supportedFormats.forEach((format) => console.log(format));
  });

  barcodeDetector
    .detect(qrImg.elt)
    .then((barcodes) => {
      image(qrImg, 0, 0);

      barcodes.forEach((barcode) => {
        console.log(barcode.rawValue);
        console.log(barcode);

        stroke(100, 100, 255);
        strokeWeight(15);
        point(barcode.cornerPoints[0].x, barcode.cornerPoints[0].y);
        stroke(255, 100, 150);
        point(barcode.cornerPoints[1].x, barcode.cornerPoints[1].y);
        stroke(100, 200, 100);
        point(barcode.cornerPoints[2].x, barcode.cornerPoints[2].y);
        stroke(150, 150, 150);
        point(barcode.cornerPoints[3].x, barcode.cornerPoints[3].y);

        textSize(15);
        noStroke();
        fill(0, 100, 150);
        text(
          `デコード結果： ${barcode.rawValue}`,
          barcode.cornerPoints[3].x,
          barcode.cornerPoints[3].y + 50
        );
      });
    })
    .catch((err) => {
      console.log(err);
    });

  console.log("end of setup");
}

function draw() {}
```

#### ソースコードの補足
`preload()` の部分では、 [createImg()](https://p5js.org/reference/#/p5/createImg) を使って画像を読み込んでいます。

| ![createImg.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/2017b641-a978-547c-20b4-e69d783c5e34.jpeg) |
|:--|

`createImg()` を使っているのは、Barcode Detection API のデータ入力が img要素 になっていたためです。

| ![データの受け渡し形式](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/b61a52ac-bf76-1e45-7cda-4b5de062e2c5.jpeg) |
|:--|

`createImg()` で作ったものに `.elt` をつけると img要素 を取得することができます。

`BarcodeDetector.getSupportedFormats()` の部分は必須ではないですが、今後、ブラウザの対応フォーマットを確認したくなる時があるかもしれないと思い、処理を書いています。

p5.js での描画処理（ `point()` 、 `text()` を使っている部分）では、QRコードの読み取りで取得できた情報を使っています。
取得可能な情報は、QRコードの四隅の座標（x と y の値）と埋め込まれたテキストです。

### 実行結果
上記のプログラムを実行した結果を掲載します。
四隅に色違いの点が重畳され、読み取れたテキストが QRコードの下に表示されました。
![QRコードの読み取り結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/a73da8fb-bf7d-f765-888d-109416a2c6a6.jpeg)

## おわりに
p5.js の処理の中で、外部ライブラリを使わない QRコード検出が実現できました。

Barcode Detection API は対応ブラウザが限られているものの、実装されているブラウザでは便利に使えそうです。

## 【追記】 QRコード読み取りのデータフォーマットについて
QRコード読み取りの処理に渡すデータフォーマットについて、以下の記載がありました。
![入力可能なデータ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/dea59028-071a-7c1b-44aa-d518ac0ad93b.jpeg)

上記の文中にある、以下の 4つのフォーマットが利用できるようです。

- element
- Blob 
- ImageData
- CanvasImageSource