LoginSignup
48
40

More than 3 years have passed since last update.

【JavaScript】ブラウザ上でQRコードを生成/解析

Last updated at Posted at 2019-09-27

ブラウザでQRコードが弄れるらしいので、試してみました。

QR解析

カメラやマイクなどの入力デバイスを扱えるMediaDevicesインターフェイスを使用し、カメラから静止画を取得します。
そして静止画をjsQRというQR解析ライブラリへ通すことで、QRコードを読み取ることができます。

function qrParse(video){
    const canvas = new OffscreenCanvas(240, 320);
    const render = canvas.getContext("2d");

    return new Promise((res)=>{
        const loop = setInterval(()=>{
            render.drawImage(video, 0, 0, canvas.width, canvas.height);

            const img = render.getImageData(0, 0, canvas.width, canvas.height);
            const result = jsQR(img.data, img.width, img.height);

            if(result){
                clearInterval(loop);
                return res(result.data);
            }
        }, 100);
    });
}

まず、このメソッドの引数としてHTMLVideoElementを受け取ります。
そして、映像から定期的に静止画を抽出する必要があるため、1秒間に10回の間隔でHTMLVideoElementOffscreanCanvasへ流し込みスナップショットを作成します。

スナップショットからImageDataを出力し、解析メソッドjsQR()へ渡します。
解析結果が存在したら、繰り返し処理の解除を行い、QRデータを解決します。

QR生成

qrcodeという、いかにもという名前のQRコード生成ライブラリを使用します。

function qrGenerate(data){
    const canvas = new OffscreenCanvas(1, 1);

    return new Promise((res, rej) => QRCode.toCanvas(canvas, data, {}, err => !err ? res(canvas) : rej(err)));
}

QRのバージョン、誤り訂正レベル、モードなどは、入力されるデータによってライブラリが自動で決定してくれます。

ライブラリがコールバック仕様なので、利便性のためにPromiseでラップしています。

サンプルHTML

qr.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">

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

        <title>QR</title>
    </head>

    <body>
        <video id="video" width="320" height="480" autoplay></video>
        <textarea id="result" readonly></textarea>
        <canvas id="canvas" width="240" height="240"></canvas>
        <textarea id="data"></textarea>
    </body>

    <script>
        function qrParse(video){
            const canvas = new OffscreenCanvas(240, 320);
            const render = canvas.getContext("2d");

            return new Promise((res)=>{
                const loop = setInterval(()=>{
                    render.drawImage(video, 0, 0, canvas.width, canvas.height);

                    const img = render.getImageData(0, 0, canvas.width, canvas.height);
                    const result = jsQR(img.data, img.width, img.height);

                    if(result){
                        clearInterval(loop);
                        return res(result.data);
                    }
                }, 100);
            });
        }

        function qrGenerate(data){
            const canvas = new OffscreenCanvas(1, 1);

            return new Promise((res, rej) => QRCode.toCanvas(canvas, data, {}, err => !err ? res(canvas) : rej(err)));
        }

        document.getElementById("data").addEventListener("change", async({target})=>{
            document.getElementById("canvas").getContext("bitmaprenderer").transferFromImageBitmap((await qrGenerate(target.value)).transferToImageBitmap());
        });

        (async()=>{
            const video = document.getElementById("video");
            video.srcObject = await navigator.mediaDevices.getUserMedia({
                audio: false,
                video: {
                    facingMode: "environment"
                }
            });

            document.getElementById("result").value = await qrParse(video);
        })();
    </script>
</html>

私のGitHub Pagesで試せます。

48
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
48
40