JSNow Logo Dark Theme
Technology Icon
04/08/21

Creating a Real-Time QR Code Scanner With Vanilla JavaScript — Part 1/2 (Creating The Scanner)

Creating a Real-Time QR Code Scanner With Vanilla JavaScript  Part Two Banner Image

What we will be making?

In this article, I'm going to show you how to create a Real-time QR code scanner with JavaScript using no libraries, frameworks, packages or node.js just plain vanilla JavaScript that runs on the browser. You can implement this into any framework you prefer using such as React, Vue, Angular and more.

See what we are making

How is it going to work?

We will be using the Barcode Detection API in JavaScript to make this possible if you have a quick look through the MDN documentation you'll see you are not just restricted to scanning QR codes.


Preview Of What We Are Creating

In this part of the article, we will be creating the scanning functionality and learning how to access the camera to detect barcodes & QR codes in realtime in the next part of this article we will be learning how to create the outline around the code we are detecting/scanning and creating a previously scanned section that uses custom web components and proxies.

This series will start quite basic and become more difficult towards the end having a good knowledge of JavaScript can help with understanding some parts of these articles as proxies and web components can be hard to wrap your head around at first.

All the code is on my GitHub you may want to reference it for CSS if you want to make a carbon copy of this project I will be going over some of the CSS that makes the outlines around the barcodes possible but that's about it for CSS as this is more focused on the JavaScript than the styling of the page.

Link to the code on GitHub

Link to the live example site

Link to Part 2 (In Development)


A Bit More about the Barcode Detection API

This section of the article is just some things that could be useful to know about the API all this information can be found on the MDN documentation.

These are some parts of the documentation that I believe could be helpful to know about before starting you can skip to the “Let's Start Coding” section of the article and come back to this later if you just want to start writing some code.

Supported codes offered by the barcode detection API

As of now in 2021, there are thirteen codes that you can choose to detect so you can choose any number of these codes for your scanner to scan. You also have the choice to make your scanner scan an array of different codes.

supported codes
This information could change in the future with more codes being added make sure to check the MDN documentation and make sure this info is still up to date. (Screenshot was taken May 2021)

Checking if the browser is compatible

As of now, the barcode detection API isn't supported by Firefox, Safari and by no surprise Internet Explorer, being that there are two big and very commonly used browsers that do not support this feature it would be best to first check if the users' browser supports it.

To check if the browser supports this we can check compatibility with a simple if statement.

if (!('BarcodeDetector' in window)) { /* Handle not compatible */ }

This will run if it is not supported, here is a browser compatibility table to see supported browsers.


Let's Start Coding!

Creating the basic HTML layout

The first thing we are going to do is very easy, creating the basic HTML all we are going to add for this example is a <video/> tag with an id and some other attributes, you can add more elements to make the layout more interesting we will be doing that in part 2 of this article.

index.js
<!DOCTYPE html>
<html>
<head>...</head>
  <body>
    <video id="video" width="640" height="480" autoplay></video>
    <!-- Dont for get to link your JavaScript -->
    <script src="./main.js" async></script>
  </body>
</html>

We are going to use the id to select the element with our JavaScript code later on. The width and height can be set to whatever you like for this example I'm setting them to 640px by 480px. The autoplay attribute is needed to play our stream nothing will happen without autoplay.

Creating the video stream

Now it's time to start writing some JavaScript, firstly we are going to select the video element from the page we just created then check if there is a camera available that we can stream from if there is then start streaming to the video element.

main.js
// Get the video element
const video = document.querySelector('#video')
// Check if device has camera
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
  // Use video without audio
  const constraints = { 
    video: true,
    audio: false
  }
  
  // Start video stream
  navigator.mediaDevices.getUserMedia(constraints).then(stream => video.srcObject = stream);
}

Now if you open the browser you should see a live stream from your webcam that we can use to scan barcodes and QR codes.

Creating the barcode scanner functionality

First, we need to create a new BarcodeDetector class and declare the barcodes that we want our barcode scanner to detect for this example I only want to scan QR codes so that's the only one I will add.

main.js
// Create new barcode detector
const barcodeDetector = new BarcodeDetector({ formats: ['qr_code'] });

You can go to the MDN docs or scroll to the top of the page to see what codes are supported if you would like to scan more than QR codes. If you want to use all supported formats you can use the getSupportedFormats function.

main.js
let formats;
// Save all formats to formats var 
BarcodeDetector.getSupportedFormats().then(arr => formats = arr);
// Create new barcode detector with all supported formats
const barcodeDetector = new BarcodeDetector({ formats });

Now that we have the barcodeDetactor class, we can start making the barcode detector function.

main.js
// Create new barcode detector
const barcodeDetector = new BarcodeDetector({ formats: ['qr_code'] });
 
// Detect code function 
const detectCode = () => {
  // Start detecting codes on to the video element
  barcodeDetector.detect(video).then(codes => {
    // If no codes exit function
    if (codes.length === 0) return;
 
    for (const barcode of codes)  {
      // Log the barcode to the console
      console.log(barcode);
    }
  }).catch(err => {
    // Log an error if one happens
    console.error(err);
  })
}

To start detecting barcodes we use the BarcodeDetector.detect() this method takes a parameter this can be a element, blob (type of image) or an ImageData object. Once the BarcodeDetector has detected a code we first check to see if the array is empty if it is we will leave the function then we log each code to the console. But before we can see our barcodes data getting returned to the console we need to run this function over and over again to get it in real-time we can do this really easily by using the setInterval method.

main.js
// Run detect code function every 100 milliseconds
setInterval(detectCode, 100);

Now you can start scanning barcodes and see that data is getting returned to the console. The data should look something like this.

{
  "boundingBox": {
      "x": 356.3738098144531,
      "y": 161.757080078125,
      "width": 284.4914245605469,
      "height": 269.2020568847656,
      "top": 161.757080078125,
      "right": 640.865234375,
      "bottom": 430.9591369628906,
      "left": 356.3738098144531
  },
  "cornerPoints": [
      {
          "x": 356.3738098144531,
          "y": 193.7646484375
      },
      {
          "x": 599.0592041015625,
          "y": 161.757080078125
      },
      {
          "x": 640.865234375,
          "y": 413.4244384765625
      },
      {
          "x": 372.65509033203125,
          "y": 430.9591369628906
      }
  ],
  "format": "qr_code",
  "rawValue": "https://google.com"
}

In this object, there are four properties boundingBox, cornerPoints, format and rawValue. The format and rawValue properties are easy to understand the formate is the formate of the code that was read in this case it was a QR code and the rawValue is the value/content of the barcode.

We also have the boundingBox and cornerPoints these both hold data on the shape and position of the barcode this data may look like they achieve the same thing but they do have differences and can change the shape they draw depending on the code you are scanning and how that code gets scanned.

Corner points

The cornerPoints array holds all four points of the scan area starting from the top left corner and continuing clockwise so cornerPoints[0] is equal to the top left then cornerPoints[1] is equal to the top right and so on. If we draw a line from each point it is unlikely that it will be a perfect square or rectangle due to the perspective of the code that the camera is looking from.

It is important to truly understand what the scan area is and what the result could be depending on the code you use for example QR, aztec, data matrix codes and other codes similar to them, this will outline the whole code because the scanner needs to be scan to the entire area to retrieve the raw value of the code.

While codes like ean 8/13, code 39/93/128, Codabar, and more like these don't need to scan the entire area of the code they just have to scan across the entire width and a small amount of the height of these codes. Here is an illustration to make this a bit easier to understand.

supported codes

Bounding box

The boundingBox holds data about the code dimensions and position we can use this data to draw around all codes regardless of what code we are scanning. The x and y properties are the value of the smallest x and y values in the cornerPoints array. top, bottom, left and right are the lengths of each side. The width and height are self-explanatory the height is the distance between the top and bottom and the width is the distance from the left to right.


Now that we have the functionality of the scanner complete we can start using this data to draw an outline of the Barcodes we are scanning in real-time and display the content and format of the barcodes. We can also use this data to create an outline of the scan area to see what the API is looking at the read the barcode.

In the next part of this article, we will be creating the outline of the QR codes and displaying the contents and formats of what we have scanned.

Buy Me A Coffee JSNow