QR (Quick Response) codes have become an integral part of our lives. From advertising to product packaging, QR codes are used to provide users with quick access to information. A QR scanner can be used to scan these codes, read the information encoded in them, and display it to the user.
In this tutorial, we will build a QR scanner using jsQR
library in JavaScript. jsQR
is a JavaScript library that provides an easy-to-use interface for decoding QR codes from image data. We will explore how to set up jsQR
and how to use it to decode QR codes from the device camera feed.
Setting Up jsQR
Library
First, we need to include the jsQR
library in our HTML file. We can do this by adding the following script tag to the head section of our HTML file:
<script src="https://cdn.jsdelivr.net/npm/jsqr@2.0.5/dist/jsQR.min.js"></script>
This will load the latest version of jsQR
from the jsDelivr
CDN.
Using the Device Camera
Next, we need to access the device camera and capture video frames from it. We can do this using the getUserMedia
method provided by the navigator.mediaDevices
object. This method returns a Promise that resolves to a MediaStream
object representing the video stream from the camera.
const constraints = { video: { facingMode: 'environment' } };
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
// code to display video stream in a video element
})
.catch(function(error) {
console.error(error);
});
In the above code, we pass a constraints
object to the getUserMedia
method to specify the constraints for the video stream. In this case, we set facingMode
to 'environment'
to use the rear-facing camera. We then use the then
method to handle the success case, and the catch
method to handle errors.
Once we have access to the video stream, we can display it in a video element and capture frames from it.
const video = document.getElementById('video');
video.srcObject = stream;
video.setAttribute('playsinline', true);
video.play();
In the above code, we set the srcObject
property of the video element to the MediaStream
object we obtained from getUserMedia
. We also set the playsinline
attribute to true
to allow the video to play inline on mobile devices. Finally, we call the play
method to start playing the video.
Capturing Frames and Decoding QR Codes
To capture frames from the video stream, we need to create a canvas element and draw the video frames on it. We can then use the jsQR
library to decode the QR codes from the canvas image data.
const canvas = document.createElement('canvas');const outputDiv = document.getElementById('output');function tick() {if (video.readyState === video.HAVE_ENOUGH_DATA) {canvas.width = video.videoWidth;canvas.height = video.videoHeight;const ctx = canvas.getContext('2d');ctx.drawImage(video, 0, 0, canvas.width, canvas.height);const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);const code = jsQR(imageData.data, imageData.width, imageData.height);if (code) {outputDiv.innerHTML = code.data;}}requestAnimationFrame(tick);}
In the above code, we create a canvas element and an output div element to display the decoded QR code data. We then define a `tick` function that will be called repeatedly to capture frames from the video stream and decode QR codes. Inside the `tick` function, we check if the video has enough data to play by checking the `readyState` property. If it does, we set the width and height of the canvas to the width and height of the video, and draw the current video frame on the canvas using the `drawImage` method of the `CanvasRenderingContext2D` interface. We then get the image data from the canvas using the `getImageData` method, and pass it to the `jsQR` function along with the width and height of the image. The `jsQR` function returns an object representing the decoded QR code if one is found, or `null` otherwise. If a QR code is found, we display its data in the output div element. Finally, we call the `requestAnimationFrame` method to schedule the next call to the `tick` function.
Here is the Full Code:
<!DOCTYPE html><html><head><title>QR Code Scanner</title><script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js"></script></head><body><video id="video" width="300" height="200"></video><canvas id="canvas" style="display: none;"></canvas><div id="output"></div><script>const video = document.getElementById('video');const canvas = document.getElementById('canvas');const outputDiv = document.getElementById('output');const constraints = { video: { facingMode: 'environment' } };navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {video.srcObject = stream;video.setAttribute('playsinline', true);video.play();requestAnimationFrame(tick);}).catch(function(error) {console.error(error);});function tick() {if (video.readyState === video.HAVE_ENOUGH_DATA) {canvas.width = video.videoWidth;canvas.height = video.videoHeight;const ctx = canvas.getContext('2d');ctx.drawImage(video, 0, 0, canvas.width, canvas.height);const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);const code = jsQR(imageData.data, imageData.width, imageData.height);if (code) {outputDiv.innerHTML = code.data;}}requestAnimationFrame(tick);}</script></body></html>