QR コードを WebAssembly で読む

ブラウザ標準の読み取り機能は、まだ使える環境が限られる。C++ の ZXing を WebAssembly にして、画像とカメラから読み取る。

公開: 2026年9月17日 / 更新: 2026年9月17日 / 文: おたすけ

スマートフォンのカメラアプリは、QR コードにかざすだけで中身を読んでくれる。パソコンのブラウザでも同じことができてよさそうだが、実際に作ろうとすると、ブラウザには QR コードを読むための共通の機能がまだ揃っていない。

QR コード読み取り は、画像ファイル、貼り付けたスクリーンショット、カメラの映像から QR コードを読むツールである。読み取りはブラウザの中で行い、画像も映像もサーバーには送らない。そのために、C++ で書かれた読み取りライブラリを WebAssembly にして、ブラウザに持ち込んでいる。

ブラウザ標準の読み取り機能は、使える環境が限られる

ブラウザには、画像からバーコードを見つける BarcodeDetector という機能が提案されている(MDN の解説)。使えればいちばん手軽である。

開発前の 2026年9月15日に対応状況を調べたところ、問題なく使えるのは Android の Chrome だけだった。パソコンの Chrome と Edge は部分的な対応、Safari は標準では無効、Firefox は未対応である。パソコンで使うことを主に想定したツールなので、これを頼りにはできない。

残る道は、読み取りの処理そのものをページに持ち込むことである。JavaScript だけで書かれた読み取りライブラリもあるが、このツールは ZXing-C++(zxing-cpp)を選んだ。Shift_JIS で書き込まれた日本語の QR コードに対応していること、開発が続いていることが理由である。

WebAssembly とは

ZXing-C++ は、名前のとおり C++ で書かれている。ブラウザは C++ のプログラムをそのままでは実行できない。

WebAssembly(WASM)は、ブラウザが JavaScript とは別に実行できる、機械語に近い形式のプログラムである(MDN の解説)。C++ や Rust などのプログラムを、専用のコンパイラでこの形式に変換できる。変換済みの ZXing-C++ は zxing-wasm というパッケージとして公開されていて、このツールはそれを使っている。

読み取りに必要な部分だけを含む WASM ファイルは 953,527 バイト、gzip で圧縮すると 412,114 バイトになる。ページを開いた時点では読み込まず、最初に読み取りを始めたときにダウンロードする。QR コードを作るページは別の入口に分けてあり、こちらはこのファイルを読み込まない。

WASM を動かすには、ページの側にも許可が要る。このサイトは CSP(Content Security Policy、ページで実行してよいものをブラウザに伝えるヘッダー)で実行できるスクリプトを絞っていて、WASM の実行には 'wasm-unsafe-eval' という指定を足す必要がある。これがないと、Chrome は WASM の読み込みを止める。

画像から文字列が出てくるまで

QR コードを読む処理は、大きく分けると、写っている位置を探す、白黒の升目を読み取る、壊れた部分を補う、という流れになる。四隅のうち三つにある大きな四角(位置検出パターン)を手がかりにコードを見つけ、傾きや歪みを補正して升目を一つずつ白か黒かに判定する。QR コードには、汚れや欠けがあっても元のデータを復元できるよう、誤り訂正のための冗長なデータが含まれている。

zxing-wasm には、画像ファイルをそのまま渡すことも、画素の並びにして渡すこともできる。ツールはまずファイルのまま渡す。読めなかった場合は、ブラウザで画像を描き直して長辺を 1,600 ピクセル以内に縮め、画素の並びを取り出してもう一度渡す。

読み取りの設定では、傾いたコード、白黒が反転したコードも探すようにしてある。1 枚の画像に複数のコードが写っていれば、最大 10 個まで読み、同じ内容のものは一つにまとめる。

カメラの映像は、250 ミリ秒ごとの静止画として読む

カメラの映像は、ブラウザの getUserMedia で受け取る。背面カメラがあればそちらを優先する。

映像を動画のまま解析するわけではない。250 ミリ秒ごとに、映像の今のコマを画面には出さない描画領域に写し、長辺 1,024 ピクセル以内の静止画として読み取りにかける。読み取りが終わってから次の 250 ミリ秒を待つので、処理が詰まることはない。一つでも読めたら、その時点でカメラを止める。

ここでは BarcodeDetector も使っている。使える環境ではまずそちらを試し、使えない環境や、途中で失敗した環境では zxing-wasm に切り替える。標準の機能を主役にはできないが、Android の Chrome のように使える環境では使う、という位置づけである。

読み取りは、画面の描画や操作の受け付けと同じスレッド(メインスレッド)で動かしている。重い処理は Web Worker という別のスレッドに移して画面を止めないようにするのが一般的だが、zxing-wasm の読み取りは 1 枚あたり数十ミリ秒で終わり、250 ミリ秒の間隔に収まると判断した。

読めた文字列を、すぐには開かない

QR コードから出てくるのは、ただの文字列である。URL のこともあれば、Wi-Fi の接続情報(WIFI:S:ネットワーク名;T:WPA;P:パスワード;; のような形式)や、連絡先のこともある。ツールは先頭の書式を見て種類を見分け、項目ごとに表示する。

URL だった場合も、自動では開かない。貼り紙の上から偽の QR コードを貼り重ねて、本物そっくりの決済画面へ誘導する手口があるからである。ツールは接続先のホスト名と URL の全文を先に表示し、開くかどうかは利用者が決める。

開くボタンを出すのは http:https: の URL だけである。javascript: のように、押すとスクリプトを実行させる形式が出てきたら、リンクにせず警告を出す。Wi-Fi のパスワードは伏せ字で表示し、必要なときだけ表示に切り替える。

作る側に、有効期限がない理由

このツールは QR コードの作成もできる。作成ページは、有効期限がないことを特長として書いている。

QR コードの作成サービスには、コードに目的の URL ではなく、サービス自身の短い URL を書き込む方式(動的 QR コードと呼ばれる)がある。読み取った人はまずサービスのサーバーに行き、そこから本来の URL へ転送される。転送先をあとから変えたり読み取り回数を数えたりできる代わりに、サービスが転送をやめればコードは使えなくなる。無料のプランに期限を設けているサービスもある。

このツールが作るのは、中身の文字列をそのままコードに書き込んだ QR コードである。読み取りにこのサイトのサーバーは関わらないので、このサイトがなくなってもコードは読める。もちろん、書き込んだ URL の先のページが消えれば、開いても何も表示されない。

作成にも読み取りにも、このツールのサーバーは関わらない。サーバーが配るのは HTML と JavaScript、それに約 950 KB の WASM ファイルだけである。