How to Build a React Native App to Scan DotCode

DotCode is a two-dimensional (2D) matrix barcode mainly used in the tobacco industry with advantages like the ability to apply the barcode by high-speed industrial printers and other methods like laser engraving.

Below is a pack of cigarettes with a DotCode representing its unique identifier.

cigarette pack

In this article, we are going to build a React Native app to scan DotCode using Dynamsoft Barcode Reader.

Demo video:

Prerequisites

Get your trial key.

New React Native Project

Create a new React Native project with a specific version:

npx @react-native-community/cli init DotCodeScanner --version 0.75.2

Add Dynamsoft Barcode Reader

Install the Dynamsoft Capture Vision package which has Dynamsoft Barcode Reader included:

npm install dynamsoft-capture-vision-react-native

Set the License

Set the license in App.tsx when the app starts.

useEffect(()=>{
  LicenseManager.initLicense('LICENSE-KEY')
  .then(()=>{/*Init license successfully.*/})
  .catch(error => console.error('Init License failed.', error));
},[]);

Request Camera Permission

  1. Declare the camera usage for iOS by adding the following lines to Info.plist.

    <key>NSCameraUsageDescription</key>
    <string>For barcode scanning</string>
    
  2. When the app starts, request camera permission.

    useEffect(()=>{
      CameraEnhancer.requestCameraPermission();
    },[]);
    

Create a DotCode Scanning Component

  1. Create a new file under components/BarcodeScanner.tsx with the following template:

    import React, {useEffect, useRef} from 'react';
    import {DecodedBarcodesResult} from 'dynamsoft-capture-vision-react-native';
    import { StyleSheet } from 'react-native';
    
    export interface ScannerProps{
      onScanned?: (result:DecodedBarcodesResult) => void;
    }
    
    export function BarcodeScanner(props:ScannerProps) {
      return (
        <></>
      );
    }
    const styles = StyleSheet.create({
      container: {
        flex:1,
      },
    });
    
  2. Add a CameraView component.

    export function BarcodeScanner(props:ScannerProps) {
       const cameraView = useRef<CameraView>(null);
       return (
         <CameraView style={styles.container} ref={cameraView} />
       );
    }
    
  3. Get the instance of Camera to open the camera and display the camera preview in the CameraView component.

    export function BarcodeScanner(props:ScannerProps) {
      const cameraView = useRef<CameraView>(null);
      const camera = CameraEnhancer.getInstance();
      useEffect(() => {
        camera.setCameraView(cameraView.current!!);
        camera.open();
        return () => {
          //close the camera when the component is going to be unmounted
          camera.close();
        };
      }, [camera, cameraView, props]);
    
      return (
        <CameraView style={styles.container} ref={cameraView} />
      );
    }
    
  4. Set up a scan region so that only part of the camera frame will be processed to improve the location and recognition of DotCode.

    setTimeout(()=>{
      camera.setScanRegion({
        left: 0,
        top: 0.4,
        right: 1,
        bottom: 0.6,
        measuredInPercentage: true,
      });
    },500)
    
  5. Get the instance of Capture Vision Router to call the Barcode Reader to read the barcodes from the camera frames.

    export function BarcodeScanner(props:ScannerProps) {
      const router = CaptureVisionRouter.getInstance();
      useEffect(() => {
        //...
        router.initSettings(dotcodeTemplate);
        router.setInput(camera);
        let resultReceiver = router.addResultReceiver({
          onDecodedBarcodesReceived: (result: DecodedBarcodesResult) =>  {
            console.log('scanned');
            if (props.onScanned) {
              props.onScanned(result);
            }
          },
        });
           
        router.startCapturing('Dotcode');
           
        return () => {
          //...
          router.removeResultReceiver(resultReceiver!);
        };
      }, [camera, router, cameraView, props]);
    }
    
  6. We have to use a JSON template to update the settings for reading DotCode.

    The template:

    {
      "CaptureVisionTemplates": [
        {
          "Name": "Dotcode",
          "ImageROIProcessingNameArray": [
            "roi_read_dotcode"
          ],
          "Timeout": 700,
          "MaxParallelTasks":0
        }
      ],
      "TargetROIDefOptions": [
        {
          "Name": "roi_read_dotcode",
          "TaskSettingNameArray": [
            "task_read_dotcode"
          ]
        }
      ],
      "BarcodeFormatSpecificationOptions": [
        {
          "Name": "format_specification_read_dotcode",
          "BarcodeFormatIds": [
            "BF_DOTCODE"
          ],
          "MirrorMode": "MM_BOTH"
        }
      ],
      "BarcodeReaderTaskSettingOptions": [
        {
          "Name": "task_read_dotcode",
          "ExpectedBarcodesCount" : 1,
          "BarcodeFormatIds" : [ "BF_DOTCODE" ],
          "LocalizationModes": [
            {
              "Mode" : "LM_STATISTICS_MARKS"
            }
          ],
          "DeblurModes":
          [
            {
              "Mode": "DM_BASED_ON_LOC_BIN"
            },
            {
              "Mode": "DM_THRESHOLD_BINARIZATION"
            },
            {
              "Mode": "DM_DEEP_ANALYSIS"
            }
          ],
          "BarcodeFormatSpecificationNameArray": [
            "format_specification_read_dotcode"
          ],
          "SectionImageParameterArray": [
            {
              "Section": "ST_REGION_PREDETECTION",
              "ImageParameterName": "ip_read_dotcode"
            },
            {
              "Section": "ST_BARCODE_LOCALIZATION",
              "ImageParameterName": "ip_read_dotcode"
            },
            {
              "Section": "ST_BARCODE_DECODING",
              "ImageParameterName": "ip_read_dotcode"
            }
          ]
        }
      ],
      "ImageParameterOptions": [
        {
          "Name": "ip_read_dotcode",
          "BinarizationModes": [
            {
              "Mode": "BM_LOCAL_BLOCK",
              "BlockSizeX": 15,
              "BlockSizeY": 15,
              "EnableFillBinaryVacancy": 0,
              "ThresholdCompensation": 10
            },
            {
              "Mode": "BM_LOCAL_BLOCK",
              "BlockSizeX": 21,
              "BlockSizeY": 21,
              "EnableFillBinaryVacancy": 0,
              "ThresholdCompensation": 10,
              "MorphOperation":"Erode",
              "MorphOperationKernelSizeX":3,
              "MorphOperationKernelSizeY":3,
              "MorphShape":"Ellipse"
            },
            {
              "Mode": "BM_LOCAL_BLOCK",
              "BlockSizeX": 35,
              "BlockSizeY": 35,
              "EnableFillBinaryVacancy": 0,
              "ThresholdCompensation": 10,
              "MorphOperation":"Erode",
              "MorphOperationKernelSizeX":3,
              "MorphOperationKernelSizeY":3,
              "MorphShape":"Ellipse"
            },
            {
              "Mode": "BM_LOCAL_BLOCK",
              "BlockSizeX": 45,
              "BlockSizeY": 45,
              "EnableFillBinaryVacancy": 0,
              "ThresholdCompensation": 25,
              "MorphOperation":"Erode",
              "MorphOperationKernelSizeX":3,
              "MorphOperationKernelSizeY":3,
              "MorphShape":"Ellipse"
            }
          ],
          "GrayscaleEnhancementModes": [
            {
              "Mode": "GEM_GENERAL"
            }
          ],
          "GrayscaleTransformationModes": [
            {
              "Mode": "GTM_INVERTED"
            },
            {
              "Mode": "GTM_ORIGINAL"
            }
          ]
        }
      ]
    }
    

    We can see that it is related to image processing. For example, the DotCode on cigarettes is often inverted, so we can set GrayscaleTransformationModes to read the inverted image first. You can learn more about how Dynamsoft Barcode Reader handles DotCode on this page.

    The code to use it:

    const dotcodeTemplate = `JSON content`;
    router.initSettings(dotcodeTemplate);
    

Use the DotCode Scanner Component

Update App.tsx to use the DotCode scanner component to scan a DotCode and display the result.

import React, { useEffect } from 'react';
import {
  Button,
  SafeAreaView,
  StyleSheet,
  Text,
  View,
} from 'react-native';
import { BarcodeScanner } from './components/BarcodeScanner';
import { CameraEnhancer, DecodedBarcodesResult, LicenseManager } from 'dynamsoft-capture-vision-react-native';

function App(): React.JSX.Element {
  const [isScanning, setIsScanning] = React.useState(false);
  const [barcodeText, setBarcodeText] = React.useState('');
  useEffect(()=>{
    LicenseManager.initLicense('LICENSE-KEY')
    .then(()=>{/*Init license successfully.*/})
    .catch(error => console.error('Init License failed.', error));
    CameraEnhancer.requestCameraPermission();
  },[]);

  const toggleScanning = () => {
    setIsScanning(!isScanning);
  };

  const onScanned = (result:DecodedBarcodesResult) => {
    if (result.items && result.items.length > 0) {
      console.log(result.items[0].text);
      toggleScanning();
      setBarcodeText(result.items[0].text);
    }
  };

  return (
    <SafeAreaView style={styles.container}>
      {isScanning &&
      <>
        <BarcodeScanner
          onScanned={onScanned}
        />
        <View style={styles.controls}>
          <Button title="Stop Scanning" onPress={toggleScanning}/>
        </View>
      </>}
      {!isScanning &&
        <View style={styles.home}>
          <Text>DotCode Scanner</Text>
          <Button title="Start Scanning" onPress={toggleScanning}/>
          {barcodeText &&
            <Text>{'Result: ' + barcodeText}</Text>
          }
        </View>
      }
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex:1,
  },
  home:{
    alignItems:'center',
  },
  controls:{
    position:'absolute',
    width:'100%',
    alignItems:'center',
    bottom:10,
  },
  button:{
    width: '50%',
  },
});

export default App;

Source Code

Check out the source code to have a try:

https://github.com/tony-xlh/react-native-dotcode-scanner