Clue Mediator

Barcode scanner in React

๐Ÿ“…June 13, 2021
๐Ÿ—ReactJS

Today we will show you how to implement a barcode scanner in React. In this example, we will use the quaggaJS in the ReactJS component.

What is QuaggaJS?

QuaggaJS is a barcode-scanner entirely written in JavaScript supporting real- time localization and decoding of various types of barcodes such as EAN, CODE 128, CODE 39, EAN 8, UPC-A, UPC-C, I2of5, 2of5, CODE 93 and CODABAR.

Checkout more articles on ReactJS

Demo Application

Barcode scanner in React - Clue Mediator

Barcode scanner in React - Clue Mediator

Steps to implement barcode scanner in React

  1. Create a react application
  2. Install quaggaJS package
  3. Add scanner functionality in react component
  4. Output

1. Create a react application

First of all, create a simple react application using the `create-react-app`. Run the following command to create an app.

npx create-react-app react-barcode-scanner

2. Install quaggaJS package

Run the following command to install quaggaJS to implement a barcode scanner.

npm install quagga

3. Add scanner functionality in react component

We have to initialize the Quagga JS to start the scanner and attach the function to read the code.

const _onDetected = res => {
  setBarcode(res.codeResult.code);
};

const startScanner = () => {
  Quagga.init(
    {
      inputStream: {
        type: 'LiveStream',
        target: document.querySelector('#scanner-container'),
        constraints: {
          facingMode: 'environment' // or user
        }
      },
      numOfWorkers: navigator.hardwareConcurrency,
      locate: true,
      frequency: 1,
      debug: {
        drawBoundingBox: true,
        showFrequency: true,
        drawScanline: true,
        showPattern: true
      },
      multiple: false,
      locator: {
        halfSample: false,
        patchSize: 'large', // x-small, small, medium, large, x-large
        debug: {
          showCanvas: false,
          showPatches: false,
          showFoundPatches: false,
          showSkeleton: false,
          showLabels: false,
          showPatchLabels: false,
          showRemainingPatchLabels: false,
          boxFromPatches: {
            showTransformed: false,
            showTransformedBox: false,
            showBB: false
          }
        }
      },
      decoder: {
        readers: [
          'code_128_reader',
          'ean_reader',
          'ean_8_reader',
          'code_39_reader',
          'code_39_vin_reader',
          'codabar_reader',
          'upc_reader',
          'upc_e_reader',
          'i2of5_reader',
          'i2of5_reader',
          '2of5_reader',
          'code_93_reader'
        ]
      }
    },
    err => {
      if (err) {
        return console.log(err);
      }
      Quagga.start();
    }
  );
  Quagga.onDetected(_onDetected);
};

Use the following function to draw an indicator on the canvas after the process is done.

Quagga.onProcessed(result => {
  let drawingCtx = Quagga.canvas.ctx.overlay,
    drawingCanvas = Quagga.canvas.dom.overlay;

  if (result) {
    if (result.boxes) {
      drawingCtx.clearRect(
        0,
        0,
        parseInt(drawingCanvas.getAttribute('width')),
        parseInt(drawingCanvas.getAttribute('height'))
      );
      result.boxes.filter(box => box !== result.box).forEach(box => {
        Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, {
          color: 'green',
          lineWidth: 2
        });
      });
    }

    if (result.box) {
      Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: '#00F', lineWidth: 2 });
    }

    if (result.codeResult && result.codeResult.code) {
      Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 });
    }
  }
});

To stop the scanner, use the following code.

const stopScanner = () => {
  Quagga.offProcessed();
  Quagga.offDetected();
  Quagga.stop();
};

At last, we have to add the HTML element to load the barcode scanner and add the CSS to align the indicator.

<div id="scanner-container">
</div>
#scanner-container {
  position: relative;
}

.drawingBuffer {
  position: absolute;
  left: 0;
  top: 0;
}

4. Output

Letโ€™s combine all the code together and see how it looks.

App.js

import React, { useEffect, useRef, useState } from 'react';
import Quagga from 'quagga';

const App = (props) => {

  const firstUpdate = useRef(true);
  const [isStart, setIsStart] = useState(false);
  const [barcode, setBarcode] = useState('');

  useEffect(() => {
    return () => {
      if (isStart) stopScanner();
    };
  }, []);

  useEffect(() => {
    if (firstUpdate.current) {
      firstUpdate.current = false;
      return;
    }

    if (isStart) startScanner();
    else stopScanner();
  }, [isStart]);

  const _onDetected = res => {
    // stopScanner();
    setBarcode(res.codeResult.code);
  };

  const startScanner = () => {
    Quagga.init(
      {
        inputStream: {
          type: 'LiveStream',
          target: document.querySelector('#scanner-container'),
          constraints: {
            facingMode: 'environment' // or user
          }
        },
        numOfWorkers: navigator.hardwareConcurrency,
        locate: true,
        frequency: 1,
        debug: {
          drawBoundingBox: true,
          showFrequency: true,
          drawScanline: true,
          showPattern: true
        },
        multiple: false,
        locator: {
          halfSample: false,
          patchSize: 'large', // x-small, small, medium, large, x-large
          debug: {
            showCanvas: false,
            showPatches: false,
            showFoundPatches: false,
            showSkeleton: false,
            showLabels: false,
            showPatchLabels: false,
            showRemainingPatchLabels: false,
            boxFromPatches: {
              showTransformed: false,
              showTransformedBox: false,
              showBB: false
            }
          }
        },
        decoder: {
          readers: [
            'code_128_reader',
            'ean_reader',
            'ean_8_reader',
            'code_39_reader',
            'code_39_vin_reader',
            'codabar_reader',
            'upc_reader',
            'upc_e_reader',
            'i2of5_reader',
            'i2of5_reader',
            '2of5_reader',
            'code_93_reader'
          ]
        }
      },
      err => {
        if (err) {
          return console.log(err);
        }
        Quagga.start();
      }
    );
    Quagga.onDetected(_onDetected);
    Quagga.onProcessed(result => {
      let drawingCtx = Quagga.canvas.ctx.overlay,
        drawingCanvas = Quagga.canvas.dom.overlay;

      if (result) {
        if (result.boxes) {
          drawingCtx.clearRect(
            0,
            0,
            parseInt(drawingCanvas.getAttribute('width')),
            parseInt(drawingCanvas.getAttribute('height'))
          );
          result.boxes.filter(box => box !== result.box).forEach(box => {
            Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, {
              color: 'green',
              lineWidth: 2
            });
          });
        }

        if (result.box) {
          Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: '#00F', lineWidth: 2 });
        }

        if (result.codeResult && result.codeResult.code) {
          Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 });
        }
      }
    });
  };

  const stopScanner = () => {
    Quagga.offProcessed();
    Quagga.offDetected();
    Quagga.stop();
  };

  return <div>
    <h3>Barcode scanner in React - <a href="https://www.cluemediator.com/" target="_blank" rel="noopener">Clue Mediator</a></h3>
    <button onclick="{()" ==""> setIsStart(prevStart => !prevStart)} style={{ marginBottom: 20 }}>{isStart ? 'Stop' : 'Start'}</button>
    {isStart && <react class="fragment">
      <div id="scanner-container">
      <span>Barcode: {barcode}</span>
    }
  </div>
}

export default App;
</react></div>

index.css

#scanner-container {
  position: relative;
}

.drawingBuffer {
  position: absolute;
  left: 0;
  top: 0;
}

Run the application and check the output in the browser.

I hope you find this article helpful.
Thank you for reading. Happy Coding..!! ๐Ÿ™‚

Demo & Source Code

GitHub Repository StackBlitz Project