How to Create a React Barcode and QR Code Scanning Library

In the previous article, we’ve built a React camera component. In this article, we are going to extend the camera component to create a React barcode and QR code scanning library using Dynamsoft Barcode Reader.

Create a React Barcode and QR Code Scanning Library

We are going to create a React barcode and QR code scanning component using Typescript.

New project

  1. Init a new npm project.

    npm init
    
  2. Install dev dependencies.

    npm install --save-dev typescript @types/react react react-dom
    
  3. Install dependencies.

    npm install dynamsoft-javascript-barcode react-vision-camera
    

Create the entry file and the component

  1. Create a component named src/BarcodeScanner.tsx with the basic content:

    import React from 'react';
    
    const BarcodeScanner = (): React.ReactElement => {
      return (
        <div>
          Barcode Scanner
        </div>
      )
    }
    
    export default BarcodeScanner;
    
  2. Create an entry file named src/index.js with the following content:

    import BarcodeScanner from './BarcodeScanner'
    export * from "./BarcodeScanner"
    
    export {
      BarcodeScanner
    };
    

TypeScript configuration

  1. Create a tsconfig.json file with the following content:

    {
      "compilerOptions": {
        "target": "es2015",
        "lib": [
          "dom",
          "dom.iterable",
          "esnext"
        ],
        "allowJs": true,
        "baseUrl": ".",
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "jsx": "react",
        "module": "commonjs",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "skipLibCheck": true,
        "strict": true,
        "declaration": true,
        "strictNullChecks": false,
        "outDir": "dist",
        "rootDir": "src"
      },
      "exclude": [
        "node_modules",
        "cypress"
      ],
      "include": [
        "src/**/*"
      ]
    }
    
  2. Update the package.json file to add a build script.

    "scripts": {
      "build": "tsc"
    }
    

Now, we can run npm run build to build the library.

Create an example project to test the component

We can create a new project to test the component.

  1. New project with Create React App in the component project’s folder.

    npx create-react-app example --template typescript
    
  2. Install the component.

    npm install ../
    
  3. Use npm link to use the React in the component project’s node_modules.

    npm link ../node_modules/react
    npm link ../node_modules/react-dom
    
  4. Update App.tsx to use the barcode scanner component.

    import React from 'react';
    import {BarcodeScanner} from 'react-barcode-qrcode-scanner';
    
    function App() {
      return (
        <div>
          <BarcodeScanner></BarcodeScanner>
        </div>
      );
    }
    
    export default App;
    
  5. We can now run the example project to test the component.

    npm run start
    

Implement the barcode scanner component

Define props for the component

Extend the camera component’s props to add the following props.

export interface ScannerProps extends CameraProps{
  runtimeSettings?: string;
  license?: string;
  interval?:number;
  drawOverlay?: boolean;
  onInitialized?: (reader:BarcodeReader) => void;
  onScanned?: (results:TextResult[]) => void;
  onClicked?: (result:TextResult) => void;
}
  • runtimeSettings: runtime settings in JSON format which is used to update the barcode reader’s runtime settings, like specifying a barcode format.
  • license: license for Dynamsoft Barcode Reader. You can apply for a trial license here.
  • interval: scan interval in milliseconds.
  • drawOverlay: whether to draw barcode overlay in SVG.
  • onScanned: event triggered when a frame is processed.
  • onInitialized: event triggered when Dynamsoft Barcode Reader is initialized.
  • onClicked: event triggered when a barcode overlay is clicked.

Add the camera component

  1. Update the JSX with the following:

    return (
      <VisionCamera
        isActive={props.isActive}
        isPause={props.isPause}
        facingMode={props.facingMode}
        desiredCamera={props.desiredCamera}
        desiredResolution={props.desiredResolution}
        onOpened={onOpened}
        onClosed={onClosed}
        onDeviceListLoaded={props.onDeviceListLoaded}
      >
        {props.children}
      </VisionCamera>
    )
    
  2. The onOpened and onClosed events are intercepted for further usage.

    const camera = React.useRef(null);
    const onOpened = (cam:HTMLVideoElement,camLbl:string) => {
      camera.current = cam;
      if (props.onOpened) {
        props.onOpened(cam,camLbl);
      }
    }
    
    const onClosed = () => {
      if (props.onClosed) {
        props.onClosed();
      }
    }
    

Initialize Dynamsoft Barcode Reader

When the component is mounted, initialize Dynamsoft Barcode Reader with a license and update the runtime settings if the runtimeSettings props exists.

const reader = React.useRef(null);
const mounted = React.useRef(false);
React.useEffect(()=>{
  const init = async () => {
    if (props.license) {
      BarcodeReader.license = props.license;
    }else{
      BarcodeReader.license = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ=="; // public trial license
    }
    BarcodeReader.engineResourcePath = "https://unpkg.com/dynamsoft-javascript-barcode@9.0.2/dist/";
    reader.current = await BarcodeReader.createInstance();
    if (props.runtimeSettings) {
      await (reader.current as BarcodeReader).initRuntimeSettingsWithString(props.runtimeSettings);
    }
    if (props.onInitialized) {
      props.onInitialized(reader.current);
    }
  }
  init();
  mounted.current = true;
},[])

Manage runtime settings

When the runtimeSettings props is changed, update the runtime settings as well.

React.useEffect(()=>{
  if (props.runtimeSettings && reader.current) {
    (reader.current as BarcodeReader).initRuntimeSettingsWithString(props.runtimeSettings);
  }
},[props.runtimeSettings])

Start scanning barcodes when the camera is opened

Here is the code:

const interval = React.useRef(null);
const startScanning = () => {
  const decode = async () => {
    if (decoding.current === false && reader.current && camera.current) {
      decoding.current = true;
      const results = await reader.current.decode(camera.current);
      setBarcodeResults(results);
      if (props.onScanned) {
        props.onScanned(results);
      }
      decoding.current = false;
    }
  }
  if (props.interval) {
    interval.current = setInterval(decode,props.interval);
  }else{
    interval.current = setInterval(decode,40);
  }
}

const onOpened = (cam:HTMLVideoElement,camLbl:string) => {
  camera.current = cam;
  startScanning();
  if (props.onOpened) {
    props.onOpened(cam,camLbl);
  }
}

Stop scanning barcodes if the camera is closed

Here is the code:

const stopScanning = () => {
  clearInterval(interval.current);
}

const onClosed = () => {
  stopScanning();
  if (props.onClosed) {
    props.onClosed();
  }
}

Draw barcode overlays

We can highlight scanned barcodes and QR codes using SVG. Here is the code to do this. You can learn more about SVG in this article.

const [viewBox, setViewBox] = React.useState("0 0 1280 720");
const renderSVGOverlay = () => {
  if (props.drawOverlay === true && barcodeResults.length>0) {
    return (
      <svg 
      preserveAspectRatio="xMidYMid slice"
      viewBox={viewBox}
      xmlns="<http://www.w3.org/2000/svg>"
      style={{
        position:'absolute',
        top: 0,
        left: 0,
        width:'100%',
        height:'100%'}}>
      {barcodeResults.map((result,idx) => (
        <polygon key={"poly-"+idx} xmlns="<http://www.w3.org/2000/svg>"
        points={getPointsData(result)}
        onClick={() => onPolygonClicked(result)}
        style={{
          fill:"rgba(85,240,40,0.5)",
          stroke: "green",
          strokeWidth: 1
        }}
        />
      ))}
      {barcodeResults.map((result,idx) => (
        <text key={"text-"+idx} xmlns="<http://www.w3.org/2000/svg>"
        x={result.localizationResult.x1}
        y={result.localizationResult.y1}
        fill="red"
        fontSize="20"
        >{result.barcodeText}</text>
      ))}
    </svg>
    )
  }
}

const onOpened = (cam:HTMLVideoElement,camLbl:string) => {
  setViewBox("0 0 "+cam.videoWidth+" "+cam.videoHeight);
}

Then add it in the JSX:

return (
  <VisionCamera
    isActive={props.isActive}
    isPause={props.isPause}
    facingMode={props.facingMode}
    desiredCamera={props.desiredCamera}
    desiredResolution={props.desiredResolution}
    onOpened={onOpened}
    onClosed={onClosed}
    onDeviceListLoaded={props.onDeviceListLoaded}
  >
    {props.children}
+   {renderSVGOverlay()}
  </VisionCamera>
)

Update the example to use the barcode and QR code scanner component

Now, we can use the component in the example project to open the camera and start scanning barcodes and QR codes.

<div className="vision-camera">
  <BarcodeScanner 
    isActive={true}
    desiredCamera="back"
    desiredResolution={{width:1280,height:720}}
    onScanned={onScanned}
  >
  </BarcodeScanner>
</div>

You can check out the online demo to have a try.

Source Code

https://github.com/xulihang/react-barcode-qrcode-scanner