DotCode(点阵码)是一种二维(2D)矩阵条形码,主要用于烟草行业,其优点是可以通过高速工业打印机和激光雕刻等方式打印。
下面是一包香烟,上面的DotCode代表着其唯一标识符。
在本文中,我们将使用Dynamsoft Barcode Reader创建一个React Native DotCode扫描应用。
演示视频:
创建新的React Native项目
使用特定版本创建新的React Native项目:
npx @react-native-community/cli init DotCodeScanner --version 0.75.2
添加Dynamsoft Barcode Reader
安装Dynamsoft Capture Vision(内含Dynamsoft Barcode Reader):
npm install dynamsoft-capture-vision-react-native
设置许可证
在App.tsx
添加以下代码以在应用启动时设置许可证。可以在此处申请许可证。
useEffect(()=>{
LicenseManager.initLicense('LICENSE-KEY')
.then(()=>{/*Init license successfully.*/})
.catch(error => console.error('Init License failed.', error));
},[]);
请求相机权限
-
将以下行添加到
Info.plist
来声明iOS端相机的用途。<key>NSCameraUsageDescription</key> <string>For barcode scanning</string>
-
应用启动后,请求相机权限。
useEffect(()=>{ CameraEnhancer.requestCameraPermission(); },[]);
编写DotCode扫描组件
-
使用以下模板在
components/BarcodeScanner.tsx
下创建新文件: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, }, });
-
添加一个
CameraView
组件。export function BarcodeScanner(props:ScannerProps) { const cameraView = useRef<CameraView>(null); return ( <CameraView style={styles.container} ref={cameraView} /> ); }
-
获取Camera实例以打开相机,并在
CameraView
组件中显示视频流。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} /> ); }
-
设置扫描区域,以便只处理相机画面的一部分,从而提高DotCode的定位效果和识别率。
setTimeout(()=>{ camera.setScanRegion({ left: 0, top: 0.4, right: 1, bottom: 0.6, measuredInPercentage: true, }); },500)
-
获取Capture Vision Router的实例,以调用Barcode Reader从视频流读取条形码。
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]); }
-
我们需要使用JSON模板来更新设置,以支持读取DotCode。
模板:
{ "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" } ] } ] }
我们可以看到它与图像处理有关。例如,香烟上的DotCode通常是黑底白码的,因此我们可以通过设置
GrayscaleTransformationModes
,首先处理反转颜色的图像。可以在此页面上了解有关Dynamsoft Barcode Reader如何处理DotCode的更多信息。代码:
const dotcodeTemplate = `JSON content`; router.initSettings(dotcodeTemplate);
使用DotCode扫描组件
更新App.tsx
以使用DotCode扫描组件扫描DotCode并显示结果。
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;
源代码
获取源代码来自己试用一下吧: