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.
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
-
Declare the camera usage for iOS by adding the following lines to
Info.plist
.<key>NSCameraUsageDescription</key> <string>For barcode scanning</string>
-
When the app starts, request camera permission.
useEffect(()=>{ CameraEnhancer.requestCameraPermission(); },[]);
Create a DotCode Scanning Component
-
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, }, });
-
Add a
CameraView
component.export function BarcodeScanner(props:ScannerProps) { const cameraView = useRef<CameraView>(null); return ( <CameraView style={styles.container} ref={cameraView} /> ); }
-
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} /> ); }
-
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)
-
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]); }
-
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: