自宅の物の在庫管理アプリを作りたいと思ったとき、まず欲しくなるのが「商品のバーコードをスキャンして登録する」機能です。専用のハード?ネイティブアプリ?——実は、スマホのブラウザと JavaScript だけでバーコードリーダーが作れます。
使うのは QuaggaJS というライブラリです。Web カメラの映像をリアルタイムに解析して、検出したバーコードの位置に枠を描きながら、コードの数値を読み取ってくれます。ページを開くだけで動くので、アプリのインストールも不要。在庫管理・蔵書管理のようなツールと相性抜群です。
この記事では、カメラ映像を表示して JAN コード(商品バーコード)を読み取るところまでを作ります。
動くもの:HTML 一枚のバーコードリーダー
まずはコピペで動く形で全体を載せます。これを barcode.html として保存し、HTTPS のサーバー越しにスマホで開くと動きます(HTTPS が必要な理由は後述のハマりポイント参照)。
<!DOCTYPE html>
<html>
<head>
<style>
body, html {
margin: 0;
overflow: hidden;
}
#camera-view {
width: 100%;
height: auto;
}
.drawingBuffer {
position: absolute;
left: 0;
}
</style>
</head>
<body>
<p id="detected-code">-</p>
<div id="camera-view"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/quagga/0.12.1/quagga.min.js"
integrity="sha512-bCsBoYoW6zE0aja5xcIyoCDPfT27+cGr7AOCqelttLVRGay6EKGQbR6wm6SUcUGOMGXJpj+jrIpMS6i80+kZPw=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const elemCameraView = document.getElementById('camera-view');
const elemDetectedCode = document.getElementById('detected-code');
const config = {
locate: false,
frequency: 2,
inputStream: {
type: 'LiveStream',
target: elemCameraView,
constraints: {
frameRate: 10,
facingMode: 'environment', // 背面カメラを使う
},
area: { // 画面中央だけを解析対象にする
top: '20%',
right: '20%',
left: '20%',
bottom: '20%',
},
},
decoder: {
readers: ['ean_reader'], // JAN(EAN)コード用
multiple: false,
},
};
const OnInit = (error) => {
if (error) {
console.error(error);
return;
}
Quagga.start();
};
const OnProcessed = (result) => {
const drawingCtx = Quagga.canvas.ctx.overlay;
const drawingCanvas = Quagga.canvas.dom.overlay;
if (result) {
// 検出中の緑の線の枠
if (result.boxes) {
drawingCtx.clearRect(0, 0,
parseInt(drawingCanvas.getAttribute("width")),
parseInt(drawingCanvas.getAttribute("height")));
result.boxes.filter(function (box) {
return box !== result.box;
}).forEach(function (box) {
Quagga.ImageDebug.drawPath(box, {x: 0, y: 1}, drawingCtx, {color: "green", lineWidth: 2});
});
}
// 読込中の青枠
if (result.box) {
Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, drawingCtx, {color: "#00F", lineWidth: 2});
}
// 検出完了時の赤線
if (result.codeResult && result.codeResult.code) {
Quagga.ImageDebug.drawPath(result.line, {x: 'x', y: 'y'}, drawingCtx, {color: 'red', lineWidth: 3});
}
}
};
const OnDetected = (result) => {
let code = result.codeResult.code;
AddItem(code);
};
const AddItem = (code) => {
elemDetectedCode.textContent = code;
let msg = code + ' コードを登録しますか?';
if (!confirm(msg)) {
return;
}
// ここに検出したコードに対する処理を書く
// (在庫管理ならDB登録、蔵書管理なら書誌APIへの問い合わせなど)
};
Quagga.init(config, OnInit);
Quagga.onProcessed(OnProcessed);
Quagga.onDetected(OnDetected);
</script>
</body>
</html>
実行するとカメラ映像が表示され、バーコードにかざすと候補に緑枠 → 読み取り中に青枠 → 確定で赤線が描かれて、コードの数値が取れます。
コードの解説
config:読み取りの設定
動きを決めているのは config です。主な項目の意味は次のとおりです。
| 設定 | 意味 |
|---|---|
frequency: 2 | 1秒あたりの解析回数。上げると反応がよくなるが CPU 負荷も上がる |
facingMode: 'environment' | スマホの背面カメラを使う('user' だと自撮り側になる) |
area | 映像のうち解析する範囲。中央 60% だけに絞ることで、狙ったバーコード以外を拾いにくくし、処理も軽くする |
readers: ['ean_reader'] | 読み取るバーコードの種類。日本の商品バーコード(JAN コード)は EAN と同じ規格なのでこれで読める |
multiple: false | 1画面から複数のコードを同時検出しない |
readers には code_128_reader(物流ラベル等)や code_39_reader(工場・会員証等)なども指定できます。ただし種類を増やすほど誤読も増えるので、読みたい種類だけに絞るのが精度のコツです。
3つのコールバック
QuaggaJS は3つのイベントをフックして使います。
Quagga.init(config, OnInit): 初期化完了(またはエラー)。成功したらQuagga.start()で解析開始Quagga.onProcessed(OnProcessed): 毎フレーム呼ばれる。ここで検出枠のオーバーレイを描いている(見た目だけの処理なので、不要なら丸ごと削っても動作はする)Quagga.onDetected(OnDetected): コードが確定したときに呼ばれる本命。result.codeResult.codeに読み取った数値(JAN なら 13 桁)が入っている
読み取り後の処理は AddItem に書きます。在庫管理なら DB への登録、蔵書管理なら ISBN として書誌 API に問い合わせる、といった具合です。
ハマりポイント
- カメラが起動しない → HTTPS で開いているか確認
ブラウザのカメラ API(getUserMedia)は、セキュリティ上 HTTPS のページでしか動きません(
localhostだけは例外)。ファイルを直接開いたfile://やhttp://のページでは、エラーにすらならず沈黙することがあります - それでも起動しない → カメラの許可 初回アクセス時の許可ダイアログで「ブロック」してしまうと以後動きません。ブラウザのサイト設定からカメラ許可をリセットしてください
- 誤読がたまに起きる 1次元バーコードの宿命で、角度や照明によってたまに違う数値を返します。実用にするなら「同じコードが連続して N 回読めたら確定」にするか、JAN コードのチェックディジットを検証すると誤登録をほぼ防げます
- ピントが合わない 接写しすぎるとスマホカメラのピントが合いません。少し離してバーコードを画面中央の枠に収めるほうが早く読めます
おまけ:GAS(Google Apps Script)で使う場合
私はこれを GAS の Web アプリとして動かしていました。GAS では .css や .js の単独ファイルが作れないため、HTML ファイルを分割して次のように読み込む形になります。
<head>
<base target="_top">
<?!= include('css'); ?>
</head>
<body>
<p id="detected-code">-</p>
<div id="camera-view"></div>
<?!= include('script'); ?>
</body>
<?!= ... ?> は GAS 独自のテンプレート記法なので、普通の Web サーバーに置く場合は不要です(この記事の冒頭のコードのように1枚にまとめれば OK)。GAS を使うと無料でスプレッドシートを DB 代わりにできるので、「読み取ったコードをシートに記録する在庫管理」がサーバー代ゼロで作れます。
まとめ
- ブラウザ+ QuaggaJS だけで、スマホカメラのバーコードリーダーが作れる
- 日本の商品バーコード(JAN)は
ean_readerで読める。readersは必要な種類だけに絞る - カメラ API は HTTPS 必須(動かないときはまずここを疑う)
- 誤読対策は「連続 N 回一致で確定」かチェックディジット検証
- GAS に載せればスプレッドシートを DB にした在庫管理がサーバー代ゼロで作れる
読み取った後の処理(AddItem の中身)を書き足せば、在庫管理・蔵書管理・持ち物リストなど色々に化けるベースになります。「バーコードで管理したい」と思ったときの取っかかりになれば幸いです。