JavaScriptでQR Codeのencode / decodeと、これを試してJavaScriptの画像周りで気づいたこと

Ruby で QR Code を作るのは以前からやってるんだけど、

これを JavaScript でやってみたらどうなるか実験。

特に scanner 部分を独自アプリで作り込むと独自ルールを仕込むことができて便利1なので、生成された QR コードのチェックを目視に頼り切る必要がなくなるし、scanner を UI と融合させやすいのが JavaScript の強み。

気づいたこと

encodeは「見える」が最優先で画像化は後回し

Ruby の場合は

  1. QR Code のパターンを生成
  2. これを内部で保持しつつどのフォーマットで出力するか

を考えるだけでよかった。上の rqrcode_png_bin で言うと、もともとは rqrcode がパターンを保持し、rqrcode_png が rqrcode と chunky_png をミックスして PNG 出力できるもので、rqrcode_png_bin はそれに CLI のガワを被せただけのものだ。

ところが JavaScript の場合はそもそもブラウザ上でならそのまま見える状態にすぐ持っていけるので、それを目指す場合が多い。具体的には HTML タグだったり Canvas 要素だったり。

ところが HTML タグも Canvas 要素も Node.js 環境ではそのままで使えない。少なくとも「画像ファイル」としてそのまま取り出すことはできない。UI と融合させてブラウザで一つ一つ手作りする分にはこれでよいが、画像として取り出してデータとして活用したい場合にはもう一工夫必要になるし、同じ生成処理を使って一括生成したい場合にもこのままでは使えない。

具体的には流れとしては以下のようになるようだ。

  1. dataURL にする
  2. dataURL を Buffer に変換する
  3. Buffer をファイルに出力する

ブラウザであれば 1 の dataURL を img 要素に与えればおしまい。画像ファイル化も、右クリックして保存すればおしまいである。Node.js であれば 2 以降を実装することで自動的に画像ファイルを生成することができる。

※ ただしこの際、画像の縦横のサイズが指定通りにぴったり同じになるかどうかは実装による。そもそも QR コードはピクセルでなく「モジュール」が基本単位であり、ピクセルは基本単位ではない。QR コードのパターンをそのまま dataURL に変換した img を生成した場合、基本的には指定サイズより小さいものができあがる。Canvas 上に描く場合は Canvas 側で先に指定サイズにしたがって要素ができあがり、その上に描画するので大きさが足りない場合は単に余白が大きくなる。

画像の取り込みはArrayBufferを作るところから

  • 画像フォーマットに左右されずにピクセル情報を取り扱うには Canvas の ImageData を利用する
  • ImageData.data は ArrayBuffer なので
  • Scanner は ArrayBuffer を解釈すれば ok

実際、以下のライブラリは第1引数に imageData と書かれているが、これは ImagaData() そのものではなく ArrayBuffer を受け取る。

cozmo/jsQR: A pure javascript QR code reading library. This library takes in raw images and will locate, extract and parse any QR code found within.

これを前提にすると、ついでに FileReader API も .readAsArrayBuffer() を使えば ArrayBuffer を返すので、

Camera -> getUserMedia() -> Canvas Context -> ImageData  -> ArrayBuffer
       -> input type="file"                -> FileReader -> ArrayBuffer

の両方のルートでカメラから ArrayBuffer を経由して QR コードリーダーを実装できることが分かった。

カメラ画像の取り込みはデバイスとブラウザの特性によって選び分けた方がよさそうという話もあるけど、そこはまた今度。

※ ちなみに昨日の https サーバの話はこの video 要素の取り回しがきっかけ。

cf.

使うとよさげなライブラリ

Accelerated Shape Detection in Images によると WICG で扱ってて Barcode Detection も standard な機能になりそうなんすね…。

  1. 例えばNGワードとか 

More