【JavaScript】html5-qrcodeでバーコード・QRコードリーダーを簡単実装

バーコード・QRコードスキャナー
スキャン結果

Webアプリケーションで、商品のバーコードを読み取ったり、イベント受付用のQRコードをスキャンしたりしたいと思ったことはありませんか? スマートフォンのネイティブアプリを使えば可能ですが、Webブラウザだけで完結できたらもっと手軽ですよね。

今回は、そんな願いを叶えるJavaScriptライブラリ「html5-qrcode」をご紹介します。このライブラリを使えば、特別なプラグインやアプリなしに、PCやスマートフォンのWebカメラを使って簡単にバーコード・QRコードリーダーを実装できます。

この記事では、html5-qrcodeの基本的な使い方と、簡単なサンプルコードを解説します。

html5-qrcodeとは?

html5-qrcode は、Webブラウザ上で動作するHTML5ベースのQRコードおよびバーコードスキャンライブラリです。主な特徴は以下の通りです。

  • 導入が簡単:CDN経由でライブラリを読み込むだけで、すぐに利用を開始できます。
  • カメラアクセス:デバイスのカメラにアクセスし、リアルタイムで映像を取得してコードをスキャンします。
  • 多様なフォーマットに対応:QRコードはもちろん、JANコード、Code 128など、多くの一般的な1次元・2次元バーコード形式に対応しています。
  • 柔軟な設定:スキャン頻度(FPS)やスキャン領域のサイズ、使用するカメラ(前面/背面)などをカスタマイズできます。
  • ファイルからの読み取り:カメラだけでなく、画像ファイルを選択してコードを読み取る機能も備えています。

サンプルコードのご紹介

まずは、今回解説するサンプルコードの全体像を見てみましょう。このコードは、Webカメラを使ってバーコードやQRコードをスキャンし、その結果をリスト表示するシンプルなリーダーです。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>バーコード・QRコードスキャナー</title>
    <style>
        body {
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            text-align: center;
            background-color: #f9f9f9;
        }

        #reader {
            width: 100%;
            max-width: 600px;
            margin: 0 auto;
            border: 2px solid #ddd;
            border-radius: 5px;
            overflow: hidden;
        }

        #result {
            margin-top: 20px;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 5px;
            background-color: #fff;
            min-height: 100px;
            text-align: left;
        }

        .result-item {
            margin-bottom: 10px;
            padding: 10px;
            background-color: #e9f7ef;
            border-radius: 5px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
        }

        .code-type {
            font-weight: bold;
            color: #007bff;
        }

        .code-data {
            word-break: break-all;
            margin-top: 5px;
        }

        .timestamp {
            font-size: 0.8em;
            color: #666;
            margin-top: 5px;
        }

        #controls {
            margin: 20px 0;
        }

        button {
            background-color: #007bff;
            color: white;
            border: none;
            padding: 10px 15px;
            border-radius: 5px;
            cursor: pointer;
            margin: 0 5px;
            font-size: 1em;
        }

        button:hover {
            background-color: #0056b3;
        }

        #clear-btn {
            background-color: #dc3545;
        }

        #clear-btn:hover {
            background-color: #c82333;
        }

    </style>
</head>
<body>
    <h1>バーコード・QRコードスキャナー</h1>
    
    <div id="reader"></div>
    
    <div id="controls">
        <button id="start-btn">スキャン開始</button>
        <button id="stop-btn" disabled>スキャン停止</button>
        <button id="clear-btn">結果クリア</button>
    </div>
    
    <div id="result">
        <h2>スキャン結果</h2>
        <div id="result-list"></div>
    </div>

    <!-- html5-qrcode ライブラリ -->
    <script src="https://unpkg.com/html5-qrcode" type="text/javascript"></script>
    
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const html5QrCode = new Html5Qrcode("reader");
            let scanning = false;
            
            const startBtn = document.getElementById('start-btn');
            const stopBtn = document.getElementById('stop-btn');
            const clearBtn = document.getElementById('clear-btn');
            const resultList = document.getElementById('result-list');

            // スキャン開始ボタンのイベントリスナー
            startBtn.addEventListener('click', function() {
                if (scanning) return;
                
                const qrCodeSuccessCallback = (decodedText, decodedResult) => {
                    const codeType = decodedResult.result.format.formatName;
                    addResultItem(codeType, decodedText);
                };
                
                const config = { 
                    fps: 1,    // 1秒間に何回スキャンするか
                    qrbox: { width: 250, height: 250 },
                    formatsToSupport: [
                        // 1次元コード
                        Html5QrcodeSupportedFormats.CODE_39,
                        Html5QrcodeSupportedFormats.CODE_93,
                        Html5QrcodeSupportedFormats.CODE_128,
                        Html5QrcodeSupportedFormats.EAN_13,
                        Html5QrcodeSupportedFormats.EAN_8,
                        Html5QrcodeSupportedFormats.UPC_A,
                        Html5QrcodeSupportedFormats.UPC_E,
                        Html5QrcodeSupportedFormats.ITF,
                        // 2次元コード
                        Html5QrcodeSupportedFormats.QR_CODE,
                        Html5QrcodeSupportedFormats.DATA_MATRIX,
                        Html5QrcodeSupportedFormats.AZTEC,
                        Html5QrcodeSupportedFormats.PDF_417
                    ]
                };
                
                html5QrCode.start(
                    { facingMode: "environment" }, 
                    config,
                    qrCodeSuccessCallback
                ).then(() => {
                    scanning = true;
                    startBtn.disabled = true;
                    stopBtn.disabled = false;
                    console.log("スキャンを開始しました");
                    
                }).catch(err => {
                    console.error("スキャン開始エラー:", err);
                    alert("カメラのアクセスに失敗しました: " + err);
                });
            });
            
            // スキャン停止ボタンのイベントリスナー
            stopBtn.addEventListener('click', function() {
                if (!scanning) return;
                
                html5QrCode.stop().then(() => {
                    scanning = false;
                    startBtn.disabled = false;
                    stopBtn.disabled = true;
                    console.log("スキャンを停止しました");
                }).catch(err => {
                    console.error("スキャン停止エラー:", err);
                });
            });
            
            // 結果クリアボタンのイベントリスナー
            clearBtn.addEventListener('click', function() {
                resultList.innerHTML = '';
            });
            
            // 結果を追加する関数
            function addResultItem(codeType, codeData) {
                const now = new Date();
                const timeStr = now.toLocaleTimeString();
                
                const resultItem = document.createElement('div');
                resultItem.className = 'result-item';
                resultItem.innerHTML = `
                    <div class="code-type">${codeType}</div>
                    <div class="code-data">${codeData}</div>
                    <div class="timestamp">${timeStr}</div>
                `;
                
                resultList.insertBefore(resultItem, resultList.firstChild);
                
                // 読み取り音を再生(オプション)
                playBeepSound();
            }
            
            // ビープ音を鳴らす関数
            function playBeepSound() {
                const context = new (window.AudioContext || window.webkitAudioContext)();
                const oscillator = context.createOscillator();
                const gainNode = context.createGain();
                
                oscillator.connect(gainNode);
                gainNode.connect(context.destination);
                
                oscillator.type = 'sine';
                oscillator.frequency.value = 1000; // 周波数
                gainNode.gain.value = 0.1; // 音量
                
                oscillator.start();
                oscillator.stop(context.currentTime + 0.1);
            }

            // ページアンロード時にスキャンを停止
            window.addEventListener('beforeunload', () => {
                if (html5QrCode.getState() === Html5QrcodeScannerState.SCANNING) {
                    html5QrCode.stop().then(() => {
                        console.log("ページ離脱時にスキャンを停止しました");
                    }).catch(err => {
                        console.error("ページ離脱時の停止エラー:", err);
                    });
                }
            });
        });
    </script>
</body>
</html>

コードのポイント解説

  1. ライブラリ読み込み
    <script src="https://unpkg.com/html5-qrcode" type="text/javascript"></script> でライブラリを読み込みます。これだけで準備OKです。
  2. インスタンス生成
    const html5QrCode = new Html5Qrcode("reader"); で、カメラ映像を表示するための div 要素( id="reader" )を指定してインスタンスを作成します。
  3. スキャン開始(startBtn クリック時)
    • html5QrCode.start() メソッドを呼び出してスキャンを開始します。
    • 第1引数 { facingMode: "environment" }:使用するカメラを指定します。"environment" は背面カメラ、"user" は前面カメラです。スマートフォンでの利用を想定し、背面カメラを指定しています。利用可能なカメラIDを直接指定することも可能です。
    • 第2引数 config:スキャンの詳細設定です。
      • fps:1秒あたりのスキャン試行回数。値を大きくすると認識率は上がる可能性がありますが、CPU負荷も高くなります。
      • qrbox:スキャンする領域(ビューファインダー)のサイズを指定します。この範囲内にコードが入るようにユーザーに促します。
      • formatsToSupport:読み取りたいバーコード・QRコードの種類を指定します。Html5QrcodeSupportedFormats オブジェクトに必要なフォーマットを配列で列挙します。これにより、不要なフォーマットの解析処理をスキップでき、パフォーマンス向上につながります。
    • 第3引数 qrCodeSuccessCallback:コードの読み取りに成功したときに呼び出される関数です。引数として decodedText(読み取った文字列データ)と decodedResult(フォーマット情報などを含む詳細結果)を受け取ります。この関数内で、読み取ったデータを画面に表示したり、サーバーに送信したりする処理を記述します。
    • 第4引数 (エラーコールバック): スキャン中にエラーが発生した場合に呼び出されます(省略可能)。
    • .then() / .catch()start()メソッドはPromiseを返すため、カメラの起動成功時や失敗時(パーミッション拒否など)の処理を記述できます。
  4. スキャン停止(stopBtn クリック時)
    • html5QrCode.stop() メソッドを呼び出して、カメラを解放しスキャンを停止します。これもPromiseを返すため、停止後の処理を .then() で記述できます。
  5. 結果表示(addResultItem 関数)
    • qrCodeSuccessCallback から呼び出され、読み取ったコードの種類(codeType)とデータ(codeData)、そして読み取り時刻を整形してHTML要素を作成し、結果リスト(#result-list)の先頭に追加しています。
  6. ビープ音(playBeepSound 関数)
    • Web Audio API を使って、読み取り成功時に簡単なビープ音を鳴らしています。ユーザーにフィードバックを与えるのに役立ちます。
  7. ページ離脱時の停止
    • beforeunload イベントリスナーを使って、ユーザーがページを閉じたり移動したりする際に、忘れずに html5QrCode.stop() を呼び出し、カメラリソースを解放するようにしています。

カスタマイズと応用

このサンプルコードは基本的なものですが、html5-qrcodeはさらに多くの機能を提供しています。

  • スキャン領域のカスタマイズqrbox のサイズだけでなく、枠線の色やスタイルなどをCSSで自由に変更できます。
  • 対応フォーマットの絞り込みformatsToSupport で必要なコード種類だけを指定することで、スキャンパフォーマンスを最適化できます。例えば、QRコードしか使わないなら [Html5QrcodeSupportedFormats.QR_CODE] のように指定します。
  • ファイルからのスキャン:カメラを使わず、<input type="file"> でユーザーに画像ファイルを選択させ、その画像を解析することも可能です(scanFile() メソッドを使用)。
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>バーコード画像認識プログラム</title>
    <style>
        #result {
            width: 90%;
            max-width: 800px;
            margin-top: 20px;
            padding: 15px;
            border: 1px solid #ddd;
            background-color: #fafafa;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <h1>バーコード画像認識プログラム</h1>
    <input type="file" id="file-input" accept="image/*">
    <div id="reader"></div>
    <div id="result">
        <h2>結果</h2>
        <div id="result-content">ここに結果が表示されます。</div>
    </div>

    <!-- html5-qrcode ライブラリ -->
    <script src="https://unpkg.com/html5-qrcode" type="text/javascript"></script>
    <script>
        const fileInput = document.getElementById('file-input');
        const resultContent = document.getElementById('result-content');
        const html5QrCode = new Html5Qrcode("reader");

        fileInput.addEventListener('change', async (event) => {
            const file = event.target.files[0];
            if (!file) return;
            // scanFile(file, showImage) の showImage は true でプレビュー表示可能(今回は false)
            html5QrCode.scanFile(file, false)
                .then(decodedText => {
                    resultContent.innerHTML = `<p>データ:${decodedText}</p>`;
                })
            .catch (err => {
                resultContent.innerHTML = `<p>デコードエラー: ${err}</p>`;
            });
        });
    </script>
</body>
</html>
  • 読み取り結果の活用qrCodeSuccessCallback で受け取った decodedText を使って、商品情報をAPIで検索したり、特定のURLにリダイレクトしたり、在庫管理システムと連携したりと、様々な応用が考えられます。

まとめ

html5-qrcodeを使えば、Webブラウザだけで動作する高機能なバーコード・QRコードリーダーを驚くほど簡単に実装できます。特別な環境構築も不要で、HTMLとJavaScriptの基本的な知識があればすぐに試すことができます。

今回ご紹介したサンプルコードを参考に、ぜひあなたのWebアプリケーションにコード読み取り機能を追加してみてください!

PR広告