Someone asked me how to create a real-time web barcode scanning app with a webcam. Is it hard to implement it? I’ve written an article sharing how to integrate Dynamsoft JavaScript Barcode Reader SDK into a React project. The remaining work is to make a webcam component. Since there is an open source project called react-webcam, we don’t need to reinvent the wheel. In this article, I will share how to build a web barcode scanner step by step.
Camera-based Web Barcode Scanning Component
Download and open react-webcam.js.
Find render() function to add a button and a canvas. We use the button to trigger barcode scan and render barcode results on the canvas:
render() { return ( <div id='videoview' width={this.props.width} height={this.props.height}> <button onClick={this.scanBarcode}>Scan Barcodes</button> <video autoPlay width={this.props.width} height={this.props.height} src={this.state.src} muted={this.props.audio} className={this.props.className} playsInline style={this.props.style} ref={(ref) => { this.video = ref; }} /> <canvas id="overlay" width={this.props.width} height={this.props.height}></canvas> </div> ); }
To show the results on the video, we need to adjust the styles of the HTML elements. Create a react-webcam.css file:
#videoview { position: relative; width: 640px; height: 480px; } #video { position: relative; width: 100%; height: 100%; z-index: 1 } #overlay { position: absolute; top: 100; left: 0; width: 100%; height: 100%; z-index: 2 }
Import the CSS file in the react-webcam.js file:
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import './react-webcam.css';
Create a scanBarcode() function, in which we need to get the byte array of the video frame and then call the decodeBuffer() method:
scanBarcode() { if (window.reader) { let canvas = document.createElement('canvas'); canvas.width = this.props.width; canvas.height = this.props.height let ctx = canvas.getContext('2d'); ctx.drawImage(this.video, 0, 0, this.props.width, this.props.height); window.reader.decodeBuffer( ctx.getImageData(0, 0, canvas.width, canvas.height).data, canvas.width, canvas.height, canvas.width * 4, window.dynamsoft.BarcodeReader.EnumImagePixelFormat.IPF_ARGB_8888 ) .then((results) => { this.showResults(results); }); } }
How to make the window.reader initialized? In public/index.html, create the instance of the barcode reader and make it globally accessible once the wasm file is loaded:
<body> <img src="loading.gif" style="margin-top:10px" id="anim-loading"> <script src="https://demo.dynamsoft.com/dbr_wasm/js/dbr-6.4.1.3.min.js"></script> <script> dynamsoft.dbrEnv.resourcesPath = 'https://demo.dynamsoft.com/dbr_wasm/js'; dynamsoft.dbrEnv.onAutoLoadWasmSuccess = function () { window.reader = new dynamsoft.BarcodeReader(); window.dynamsoft = dynamsoft; document.getElementById('anim-loading').style.display = 'none'; }; dynamsoft.dbrEnv.onAutoLoadWasmError = function (ex) { document.getElementById('anim-loading').style.display = 'none'; alert('Fail to load the wasm file.'); }; dynamsoft.dbrEnv.bUseWorker = true; // Get a free trial license from https://www.dynamsoft.com/CustomerPortal/Portal/TrialLicense.aspx dynamsoft.dbrEnv.licenseKey = "Your Barcode SDK License" </script> <div id="root"></div>
Note: dynamsoft.dbrEnv.bUseWorker has to be true. If we do not use web worker, the main thread will be heavily blocked.
To make this work in scanBarcode(), bind it in the constructor:
constructor() { super(); this.state = { hasUserMedia: false, }; this.scanBarcode = this.scanBarcode.bind(this); }
The following code shows how to continuously scan and show the barcode results on the webcam video:
showResults(results) { let context = this.clearOverlay(); let txts = []; try { let localization; for (var i = 0; i < results.length; ++i) { if (results[i].LocalizationResult.ExtendedResultArray[0].Confidence >= 30) { txts.push(results[i].BarcodeText); localization = results[i].LocalizationResult; this.drawResult(context, localization, results[i].BarcodeText); } } this.scanBarcode(); } catch (e) { this.scanBarcode(); } } clearOverlay() { let context = document.getElementById('overlay').getContext('2d'); context.clearRect(0, 0, this.props.width, this.props.height); context.strokeStyle = '#ff0000'; context.lineWidth = 5; return context; } drawResult(context, localization, text) { context.beginPath(); context.moveTo(localization.X1, localization.Y1); context.lineTo(localization.X2, localization.Y2); context.lineTo(localization.X3, localization.Y3); context.lineTo(localization.X4, localization.Y4); context.lineTo(localization.X1, localization.Y1); context.stroke(); context.font = '18px Verdana'; context.fillStyle = '#ff0000'; let x = [ localization.X1, localization.X2, localization.X3, localization.X4 ]; let y = [ localization.Y1, localization.Y2, localization.Y3, localization.Y4 ]; x.sort(function(a, b) { return a - b; }); y.sort(function(a, b) { return b - a; }); let left = x[0]; let top = y[0]; context.fillText(text, left, top + 50); }
Open App.js to add the React webcam component:
import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; import {Barcode} from './Barcode'; import Webcam from './react-webcam'; class App extends Component { render() { return ( <div className="App"> <Barcode/> <Webcam /> </div> ); } } export default App;
Run the web barcode scanner app:
npm start
Visit localhost:3000:
Source Code
https://github.com/dynamsoft-dbr/javascript-barcode/tree/master/examples/react-wasm-barcode
The post How to Build Web Barcode Scanner Using React and Webcam appeared first on Code Pool.