Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
32
Help us understand the problem. What is going on with this article?
@dojyorin

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

ブラウザで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で試せます。

32
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
dojyorin
独学でJavaScriptとC++やってます。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
32
Help us understand the problem. What is going on with this article?