勉強したことのメモ

Webエンジニア / プログラマが勉強したことのメモ。

JavaScriptでWebカメラやスマホカメラを利用してQRコードを読み取りURLを返す方法

   2024/04/25  JavaScript

JavaScriptのjsQRというライブラリで簡単にWebページ版QRコードリーダーを作れるらしい。具体的にはPCのWebカメラやスマートフォンカメラでQRコードを読み取り、URLを返してくれるというもの。おもしろそうだったので以下に実装方法とサンプルをメモ。

 

jsQR

公式サイト

https://github.com/cozmo/jsQR

CDN

CDNで使う場合は以下を記述する。

<script src=" https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js "></script>

異なるバージョンを利用したい場合は以下から探す。

https://www.jsdelivr.com/package/npm/jsqr

 

サンプル

https://taitan916.info/sample/jsQR/

 

ソースコード

<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>jsQRのテスト</title>
<meta name="viewport" content=”width=device-width,initial-scale=1″>
<style>
body {
    color: #333;
    max-width: 640px;
    margin: 0 auto;
    position: relative;
}
#loadingMessage {
    text-align: center;
    padding: 40px;
    background-color: #eee;
}
#canvas {
    width: 100%;
}
#output {
    margin-top: 20px;
    background: #eee;
    padding: 10px;
    padding-bottom: 0;
}
#output div {
    padding-bottom: 10px;
    word-wrap: break-word;
}
#noQRFound {
    text-align: center;
}
</style>
</head>
<body>
    <div id="loadingMessage">
        ビデオストリームにアクセスできません(Webカメラが有効になっていることを確認してください)
    </div>
    <canvas id="canvas" hidden></canvas>
    <div id="output" hidden>
        <div id="outputMessage">QRコードが検出されませんでした</div>
        <div hidden><b>Data:</b> <span id="outputData"></span></div>
    </div>
    <script src=" https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js "></script>
    <script>
        var video = document.createElement("video");
        var canvasElement = document.getElementById("canvas");
        var canvas = canvasElement.getContext("2d");
        var loadingMessage = document.getElementById("loadingMessage");
        var outputContainer = document.getElementById("output");
        var outputMessage = document.getElementById("outputMessage");
        var outputData = document.getElementById("outputData");

        function drawLine(begin, end, color) {
            canvas.beginPath();
            canvas.moveTo(begin.x, begin.y);
            canvas.lineTo(end.x, end.y);
            canvas.lineWidth = 4;
            canvas.strokeStyle = color;
            canvas.stroke();
        }

        navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } }).then(function(stream) {
            video.srcObject = stream;
            video.setAttribute("playsinline", true);
            video.play();
            requestAnimationFrame(tick);
        });

        function tick() {
            loadingMessage.innerText = "Loading video..."
            if (video.readyState === video.HAVE_ENOUGH_DATA) {
                loadingMessage.hidden = true;
                canvasElement.hidden = false;
                outputContainer.hidden = false;

                canvasElement.height = video.videoHeight;
                canvasElement.width = video.videoWidth;
                canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
                var imageData = canvas.getImageData(0, 0, canvasElement.width, canvasElement.height);
                var code = jsQR(imageData.data, imageData.width, imageData.height, {
                    inversionAttempts: "dontInvert",
                });
                if (code) {
                    drawLine(code.location.topLeftCorner, code.location.topRightCorner, "#FF3B58");
                    drawLine(code.location.topRightCorner, code.location.bottomRightCorner, "#FF3B58");
                    drawLine(code.location.bottomRightCorner, code.location.bottomLeftCorner, "#FF3B58");
                    drawLine(code.location.bottomLeftCorner, code.location.topLeftCorner, "#FF3B58");
                    outputMessage.hidden = true;
                    outputData.parentElement.hidden = false;
                    outputData.innerText = code.data;
                } else {
                    outputMessage.hidden = false;
                    outputData.parentElement.hidden = true;
                }
            }
            requestAnimationFrame(tick);
        }
    </script>
</body>
</html>

ソースコードはデモサイトのものをほぼ流用。

 

考えられる使いどころ

スマホでQRコードを読み込ませてブラウザで開いたりクリップボードにコピーしたりというのは通常のアプリの方が良いので、それ以外の部分で使うことになる。

具体的にはURLをスプレッドシートやデータベースに書き込むとか。例えば書籍とかチラシとかでたまにQRコードが載っており「できればPCで閲覧したいんだけど……」といった時に通常のアプリだと「読み取り→何らかの方法でURLをPCに送信→PC側のブラウザで開く」となるが、スプレッドシートに自動で書き込んだ場合「何らかの方法でPCに送信」部分が不要になる。

無理やりひねり出した感があり実用性にはかけそう。

 

所感

JavaScriptでQRコードを読み取れる、というのは面白いんだけど、QRコードは通常のスマホアプリである程度問題無いため使いどころが難しく感じた。

尚、QuaggaJSというライブラリだと通常のバーコードが読み込めるらしく、こちらならもうちょっと使いどころがありそう。その内試してみたいところ。

 - JavaScript

  関連記事

サイトをダークモード対応させる「Darkmode.js」ライブラリの利用方法

サイトをダークモード対応させる場合、CSSで色々指定しないといけないと思っていた ...

JavaScriptでランダムなカラーコードを生成する「RandomColor」ライブラリの利用方法

先日PHPでランダムなカラーコードを生成する「RandomColor.php」ラ ...

JavaScriptのHTTPクライアントライブラリ「AXIOS」の使い方

あるサイトのソースコードを拝見しているとAXIOSというJSファイルをCDN呼び ...

JavaScriptライブラリChart.jsでグラフの描写する方法

JavaScriptでグラフを描写する必要があり、普段はHighchartを使用 ...

JavaScriptのマップ用ライブラリ「MapLibre GL JS」の利用方法

あるサイトをWappalyzerで調査していた際に「MapLibre GL JS ...