🔰

jsQR+αであっさりQRコードリーダ/メーカ

2021/11/09に公開

QRコードリーダ/メーカを作る

2つのライブラリを同時に使い、QRコードリーダ/メーカを作ってみます。
今回は、"localhost"環境での実働テストを試してみます。

ライブラリ 用途
jsQR QRコードを検出します
qrcode QRコードを生成します

実際にインターネットに公開する場合、"https"環境が整っているサーバーが必要になりますので注意しましょう。

QRコードリーダーを作る

jsQRを利用する事で、とても簡単にQRコードリーダーを作る事ができます。

ライブラリのダウンロード

jsQRを、GitHubからダウンロードします。

jsQR

ダウンロードした圧縮ファイルを解凍します。
解凍したフォルダ中にある"jsQR.js"がライブラリ本体です。

プロジェクトを作る

次の様にプロジェクトを作ります。

MyProject01/
 ├ custom.css (スタイルを記述するファイルです)
 ├ index.html (プログラムを起動するファイルです)
 ├ main.js (メインのプログラムを記述するファイルです)
 ├ jsQR.js (ライブラリの本体ファイルです)

HTMLファイルを用意する

では、作っていきましょう。
HTMLファイルを用意して、下記コードを記述します。

index.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<!-- CSS -->
		<link rel="stylesheet" href="./style.css"/>
		<!-- JavaScript -->
		<script src="./jsQR.js" defer></script>
		<script src="./main.js" defer></script>
	</head>
	<body>
		<h1>jsQR</h1>
		<div id="wrapper">
			<div id="msg">Unable to access video stream.</div>
			<canvas id="canvas"></canvas>
		</div>
	</body>
</html>

"msg"エレメントには検出されたQRコードの内容を表示します。
そして、"canvas"エレメントには、Webカメラの画像が描画されます。

CSSファイルを用意する

次はCSSファイルです。
こちらは特に説明することはありませんね。

style.css
/* CSS */
body{
	background-color: gray;
}

h1{
	text-align: center;
}

#wrapper{
	margin: 0px auto 0px auto;
	width: 320px; height: auto;
}

#msg{
	margin: 0px; padding: 10px;
	background-color: lightgray;
	text-align: center;
}

#canvas{
	width: 100%; height: auto;
	background-color: silver;
}

JavaScriptファイルを用意する

メインのプログラムを作っていきます。
全体の流れは次の通りです。

  1. Webカメラを起動する
  2. キャンバスに描画する
  3. QRコードを判定する

Webカメラを起動する

Webカメラを起動します。
Webカメラへのアクセスは、"getUserMedia"関数を実行します。

Webカメラの起動に成功すると、"then"関数が実行されます。
カメラの準備が出来たタイミングで、"startTick"関数を実行して次の処理に進みます。

main.js
// 省略

const userMedia = {video: {facingMode: "environment"}};
navigator.mediaDevices.getUserMedia(userMedia).then((stream)=>{
	video.srcObject = stream;
	video.setAttribute("playsinline", true);
	video.play();
	startTick();
});

// 省略

キャンバスに描画する

"drawImage"関数を実行し、Webカメラからのデータをキャンバスに描画します。
引数には"video"オブジェクト、そして描画エリアの開始点と終了点の座標を指定します。

main.js
// 省略

function startTick(){
	msg.innerText = "Loading video...";
	if(video.readyState === video.HAVE_ENOUGH_DATA){
		canvas.height = video.videoHeight;
		canvas.width = video.videoWidth;
		ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
		// このタイミングでQRコードを判定します
	}
	setTimeout(startTick, 250);
}

// 省略

QRコードを判定する

いよいよQRコードの判定処理です。
判定対象であるイメージデータは、"getImageData"関数を使って取得します。
その後、取得したイメージデータを"jsQR"関数に渡します。

"jsQR"関数の実行結果が"null"でなければ、検出が成功している状態です。
"null"だった場合は検出失敗(未検出)になります。

検出成功時、"code.location"には、検出された座標データが、
"code.data"には、QRコードで取得した文字列データが格納されています。
具体的には次の様な記述になります。

main.js
// 省略

let img = ctx.getImageData(0, 0, canvas.width, canvas.height);
let code = jsQR(img.data, img.width, img.height, {inversionAttempts: "dontInvert"});
if(code){
	drawRect(code.location);// 検出されたQRコードの位置を描画します
	msg.innerText = code.data;// 検出されたQRコードの文字列データを表示します
}else{
	msg.innerText = "Detecting QR-Code...";
}

// 省略

全体のコード

ここまでのコードを載せておきますね。

main.js
window.onload = (e)=>{

	let video  = document.createElement("video");
	let canvas = document.getElementById("canvas");
	let ctx    = canvas.getContext("2d");
	let msg    = document.getElementById("msg");

	const userMedia = {video: {facingMode: "environment"}};
	navigator.mediaDevices.getUserMedia(userMedia).then((stream)=>{
		video.srcObject = stream;
		video.setAttribute("playsinline", true);
		video.play();
		startTick();
	});

	function startTick(){
		msg.innerText = "Loading video...";
		if(video.readyState === video.HAVE_ENOUGH_DATA){
			canvas.height = video.videoHeight;
			canvas.width = video.videoWidth;
			ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
			let img = ctx.getImageData(0, 0, canvas.width, canvas.height);
			let code = jsQR(img.data, img.width, img.height, {inversionAttempts: "dontInvert"});
			if(code){
				drawRect(code.location);// Rect
				msg.innerText = code.data;// Data
			}else{
				msg.innerText = "Detecting QR-Code...";
			}
		}
		setTimeout(startTick, 250);
	}

	function drawRect(location){
		drawLine(location.topLeftCorner,     location.topRightCorner);
		drawLine(location.topRightCorner,    location.bottomRightCorner);
		drawLine(location.bottomRightCorner, location.bottomLeftCorner);
		drawLine(location.bottomLeftCorner,  location.topLeftCorner);
	}

	function drawLine(begin, end){
		ctx.lineWidth = 4;
		ctx.strokeStyle = "#FF3B58";
		ctx.beginPath();
		ctx.moveTo(begin.x, begin.y);
		ctx.lineTo(end.x, end.y);
		ctx.stroke();
	}
}

これだけでQRコードリーダーができてしまいます。(やりました!!)

QRコードメーカーを作る

公式サイトよりライブラリをダウンロードし、解凍したフォルダにある"qrcode.js"をプロジェクトに追加します。

qrcode

プロジェクトは次の様になります。

MyProject01/
 ├ custom.css (スタイルを記述するファイルです)
 ├ index.html (プログラムを起動するファイルです)
 ├ main.js (メインのプログラムを記述するファイルです)
 ├ jsQR.js (ライブラリの本体ファイルです)
 ├ qrcode.js (ライブラリの本体ファイルです)

HTMLファイルを編集する

先程のHTMLに、QRコードを表示するエリアを用意します。
"qrcode.js"ライブラリの読み込みと、idが"qrcode"となっている"div"タグを追加します。

index.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<!-- CSS -->
		<link rel="stylesheet" href="./style.css"/>
		<!-- JavaScript -->
		<script src="./jsQR.js" defer></script>
		<script src="./qrcode.js" defer></script>
		<script src="./js/main.js" defer></script>
	</head>
	<body>
		<h1>jsQR</h1>
		<div id="wrapper">
			<div id="msg">Unable to access video stream.</div>
			<canvas id="canvas"></canvas>
			<div id="qrcode"></div>
		</div>
	</body>
</html>

JavaScriptファイルを編集する

QRコードを生成するパターンは次の通りです。
次のコードを見てもらうとわかる通り、とてもシンプルに記述する事ができます。
第一引数の"qrcode"は、HTMLの表示先のidです。

main.js
let qrcode = new QRCode("qrcode", {
	text: text,
	width: 128, height: 128,// QRコードの幅と高さ
	colorDark: "#000000",
	colorLight: "#ffffff",
	correctLevel: QRCode.CorrectLevel.H
});

全体のコード

最後に全体のコードを載せておきますね。

main.js
window.onload = (e)=>{

	let video  = document.createElement("video");
	let canvas = document.getElementById("canvas");
	let ctx    = canvas.getContext("2d");
	let msg    = document.getElementById("msg");

	const userMedia = {video: {facingMode: "environment"}};
	navigator.mediaDevices.getUserMedia(userMedia).then((stream)=>{
		video.srcObject = stream;
		video.setAttribute("playsinline", true);
		video.play();
		startTick();
	});

	function startTick(){
		msg.innerText = "Loading video...";
		if(video.readyState === video.HAVE_ENOUGH_DATA){
			canvas.height = video.videoHeight;
			canvas.width = video.videoWidth;
			ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
			let img = ctx.getImageData(0, 0, canvas.width, canvas.height);
			let code = jsQR(img.data, img.width, img.height, {inversionAttempts: "dontInvert"});
			if(code){
				drawRect(code.location);// Rect
				msg.innerText = code.data;// Data
				makeQR(code.data);// QRCode
			}else{
				msg.innerText = "Detecting QR-Code...";
			}
		}
		setTimeout(startTick, 250);
	}

	function drawRect(location){
		drawLine(location.topLeftCorner,     location.topRightCorner);
		drawLine(location.topRightCorner,    location.bottomRightCorner);
		drawLine(location.bottomRightCorner, location.bottomLeftCorner);
		drawLine(location.bottomLeftCorner,  location.topLeftCorner);
	}

	function drawLine(begin, end){
		ctx.lineWidth = 4;
		ctx.strokeStyle = "#FF3B58";
		ctx.beginPath();
		ctx.moveTo(begin.x, begin.y);
		ctx.lineTo(end.x, end.y);
		ctx.stroke();
	}

	function makeQR(text){
		document.getElementById("qrcode").innerHTML = "";// Clear
		let qrcode = new QRCode("qrcode", {
			text: text,
			width: 128, height: 128,
			colorDark: "#000000",
			colorLight: "#ffffff",
			correctLevel: QRCode.CorrectLevel.H
		});
	}
}

判別したQRコードをそのまま生成できている事が確認できます。(やりました!!)

最後に

簡単にQRコードリーダーが出来る事が伝わったかと思います。
QRコード自体は昔からある見慣れた存在ですが、改めて見直してみるとアイデアが出るかもしれませんね。
繰り返しになりますが、インターネット上での利用には"https"環境でのサーバーが必要になりますのでご注意くださいませ。
ここまで読んでいただき有難うございました。

Discussion