Help us understand the problem. What is going on with this article?

JavaScriptでQRコードを生成・解析

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

Reader

入力デバイスを提供するMediaDevicesインターフェイスを使い、カメラから画像を読み取り、QR解析ライブラリを使用してデコードします。

HTML

reader.html
<script src="https://cdn.jsdelivr.net/npm/jsqr@latest/dist/jsQR.min.js"></script>
<video id="cap" width="320" height="240" autoplay></video>

<textarea id="res" readonly></textarea>

ここで指定するwidthheightは、表示領域の解像度です。
autoplayは無いとキャプチャはされていても映像ストリームが表示されません。

JavaScript

reader.js
function readQr(video){
    return navigator.mediaDevices.getUserMedia({
        audio: false,
        video: {
            width: {
                exact: 320
            },
            height: {
                exact: 480
            },
            facingMode: {
                exact: "environment"
            }
        }
    })
    .then((stream)=>{
        return new Promise((res)=>{
            video.addEventListener("loadedmetadata", ev => res(ev));
            video.srcObject = stream;
        });
    })
    .then(({target})=>{
        return new Promise((res)=>{
            const loop = setInterval(()=>{
                const canvas = document.createElement("canvas").getContext("2d");
                canvas.drawImage(target, 0, 0, target.videoWidth, target.videoHeight);
                const img = canvas.getImageData(0, 0, target.videoWidth, target.videoHeight);
                const data = jsQR(img.data, img.width, img.height);
                if(data){
                    clearInterval(loop);
                    target.srcObject.getTracks()[0].stop();
                    target.srcObject = null;
                    res(data);
                }
            }, 100);
        });
    });
}

ビデオキャプチャ初期化

まずnavigator.mediaDevices.getUserMedia()でカメラデバイスにアクセスします。

この時いくつかの初期化オプションを渡します。
まず解像度ですが、ここで指定する解像度はキャプチャ解像度になります。
私の環境では、これ以上高くすると読み取れませんでした。

facingModeは、スマートフォンなどの場合にリアカメラ・フロントカメラを指定できます。
リアカメラを起動したい場合は"environment"で、フロントカメラを起動したい場合は"user"を代入します。

いずれもexactプロパティに代入する事で、必ずその値で初期化されるよう指定します。

そしてブラウザからカメラ試用許可を要求されます。
許可すると、映像ストリームオブジェクトが返されるので<video>要素に紐付けます。

ここまでがビデオキャプチャの初期化で、次からがQRコードリーダーの中身になります。

QR解析

まずtargetは、映像ストリームのメタデータの読込が完了したときに解決されるEventTargetで、対象の<video>要素です。

実体はreadQr()引数videoと同一ですが、精神衛生上こちらを使いました😂

QR解析にはImageData型の静止画が必要なので、映像ストリームから定期的に静止画を抽出する必要があります。

setInterval()で1秒間に10回、映像ストリームをcanvas仮想要素に静止画として流し込み、ピクセルデータをImageData型で出力し、ライブラリの解析メソッドjsQR()へ渡します。

解析結果が存在したら、繰り返し処理の解除と映像ストリームの終了を行います。

使う

HowToUse
readQr(document.getElementById("cap"))
.then(({data}) => document.getElementById("res").value = data);

Writer

めちゃめちゃ簡単です😁
QR生成はライブラリを使います。

HTML

writer.html
<script src="https://cdn.jsdelivr.net/npm/qrcode@latest/build/qrcode.min.js"></script>
<canvas id="qr"></canvas>

特にこれといった事はしていません。

JavaScript

writer.js
function writeQr(canvas, data){
    return new Promise((res, rej)=>{
        QRCode.toCanvas(canvas, data, {
            margin: 2,
            scale: 2
        }, (err, tg) => !err ? res(tg) : rej(err));
    });
}

既存の<canvas>要素に紐付けて、そこに書き込みます。

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

ライブラリがコールバック仕様なので、利便性のためPromiseでラップしています。
解決されるtgEventTargetで対象の<canvas>要素ですが、これも実体はwriteQr()引数canvasと同一なので、特に使う必要はありません。

なお、メソッド内でcreateElement("canvas")をして<canvas>仮想要素へ出力する場合は、最終的にDOMへ挿入する場合などに使います。

使う

HowToUse
writeQr(document.getElementById("qr"), "ほげほげ");

サンプル

GitHub Gistに載せました。
https://gist.github.com/dojyorin/89ffa8fdb7cd14f47e9646ffc42adf6a

Gist Previewで試せます。
https://gistpreview.github.io/?89ffa8fdb7cd14f47e9646ffc42adf6a

dojyorin
野生のどじょう。 趣味と業務効率化の一環でC#, JS, Arduinoをかじる。
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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした