ZXing (pronounced zebra crossing) is an open-source JavaScript library that’s widely used for barcode scanning and generation. It can read and process many different types of barcodes, such as Code 128, EAN, QR codes, and UPC, in both 1D and 2D formats.
In this tutorial, we’ll show you how to integrate ZXing’s JavaScript library into a web app to use its barcode scanning functionalities. This involves the following steps:
- Setting up the project
- Installing the ZXing library
- Creating the source files
- Defining the HTML structure
- Implementing the JavaScript code
- Running the application
Before we start, make sure you have latest version of Node.js with npm installed on your machine. You can use a code editor such as Visual Studio Code for this project or stick to the command line.
Step 1: Set up the project
Create a new directory for your project and initialize it with npm.
mkdir zxing-barcode-scanner
cd zxing-barcode-scanner
npm init -y
Step 2: Install the ZXing library
Use the npm
command to install the ZXing library:
npm install @zxing/library
Step 3: Create the source files
Create the required source files in your project folder (zxing-barcode-scanner).
mkdir src
touch src/index.html src/index.js
💡 If you’re using PowerShell on Windows, use the type
command instead:
mkdir src
type nul > src/index.html src/index.js
Step 4: Define the HTML structure
In index.html
, define the HTML structure that contains a video
element to display the camera feed, a startButton
for scanning, and a resetButton
to reset the scanner. A div
with the ID result
displays the scanned barcode.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ZXing TypeScript | Decoding from camera stream</title>
<link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null"
href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
<link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null"
href="https://unpkg.com/normalize.css@8.0.0/normalize.css">
<link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null"
href="https://unpkg.com/milligram@1.3.0/dist/milligram.min.css">
</head>
<body>
<main class="wrapper" style="padding-top:2em">
<section class="container" id="demo-content">
<h1 class="title">ZXing Barcode Scanner</h1>
<p>
<a class="button-small button-outline" href="../../index.html">HOME 🏡</a>
</p>
<p>Scan any supported 1D/2D code with ZXing javascript library from the device video
camera.</p>
<div>
<a class="button" id="startButton">Start</a>
<a class="button" id="resetButton">Reset</a>
</div>
<div>
<video id="video" width="300" height="200" style="border: 1px solid gray"></video>
</div>
<div id="sourceSelectPanel" style="display:none">
<label for="sourceSelect">Change video source:</label>
<select id="sourceSelect" style="max-width:400px">
</select>
</div>
<label>Result:</label>
<pre><code id="result"></code></pre>
</section>
</main>
<script type="text/javascript" src="https://unpkg.com/@zxing/library@latest/umd/index.min.js"></script>
<script src="index.js" defer></script>
</body>
</html>
We use the defer
attribute so that the script is executed after the HTML document is fully parsed.
Step 5: Implement the JavaScript code
Add the JavaScript code to initialize ZXing and manage the logic for the barcode scanning process to the index.js
file.
window.addEventListener('load', function () {
let selectedDeviceId;
const codeReader = new ZXing.BrowserMultiFormatReader()
console.log('ZXing code reader initialized')
codeReader.listVideoInputDevices()
.then((videoInputDevices) => {
const sourceSelect = document.getElementById('sourceSelect')
selectedDeviceId = videoInputDevices[0].deviceId
if (videoInputDevices.length >= 1) {
videoInputDevices.forEach((element) => {
const sourceOption = document.createElement('option')
sourceOption.text = element.label
sourceOption.value = element.deviceId
sourceSelect.appendChild(sourceOption)
})
sourceSelect.onchange = () => {
selectedDeviceId = sourceSelect.value;
};
const sourceSelectPanel = document.getElementById('sourceSelectPanel')
sourceSelectPanel.style.display = 'block'
}
document.getElementById('startButton').addEventListener('click', () => {
codeReader.decodeFromVideoDevice(selectedDeviceId, 'video', (result, err) => {
if (result) {
console.log(result)
document.getElementById('result').textContent = result.text
}
if (err && !(err instanceof ZXing.NotFoundException)) {
console.error(err)
document.getElementById('result').textContent = err
}
})
console.log(`Started continous decode from camera with id ${selectedDeviceId}`)
})
document.getElementById('resetButton').addEventListener('click', () => {
codeReader.reset()
document.getElementById('result').textContent = '';
console.log('Reset.')
})
})
.catch((err) => {
console.error(err)
})
})
When the page loads, the script imports the BrowserMultiFormatReader
class from the ZXing library and creates a new instance. It provides references to the video element, result paragraph, and start and reset buttons.
When you click the start button, the script calls decodeFromVideoDevice
to start scanning from the camera feed.
If there is a barcode for scanning, the script displays the result in the resultElement
and logs it to the console. If the process fails, the errors are logged to the console.
The script calls listVideoInputDevices
to retrieve a list of available video input devices. It retrieves the HTML element with ID sourceSelect
and sets the default device to the first available video input device.
Step 6: Run the application
Open your index.html
file in a web browser. Click Start and allow camera access when prompted. Scan the barcode, and find the result displayed on the screen.
Click Reset to close the camera and clear the results.
If more than one video input device is found (for example front and back camera), you can select the device from the Change video source dropdown.
Disadvantages of using the ZXing barcode scanner library
ZXing provides decent performance for basic barcode scanning tasks but sometimes struggles with more challenging scenarios. Its most notable drawbacks as a barcode scanning solution include:
- Scanning accuracy and speed: ZXing struggles with scanning poorly lit or damaged barcodes. It often exhibits low recognition rates for smaller barcodes and can fail to decode them altogether.
- Compatibility issues: ZXing may not perform reliably across all devices, particularly newer models. This has led to frustration among developers who require consistent performance across different platforms.
- Lack of active development: As an open-source project, ZXing has seen limited updates and maintenance in recent years. This stagnation can lead to unresolved bugs and compatibility issues, making it less reliable for commercial applications.
- Integration complexity: Integrating ZXing into your app can be cumbersome, especially for developers who may not be familiar with its architecture. This can lead to longer development times and increased chances of bugs during implementation.
We developed the Scanbot Barcode Scanner SDK as a commercial solution to help enterprises overcome these hurdles presented by free barcode scanning software. Our goal was to have a developer-friendly solution available for a wide range of platforms that consistently delivers high-quality results – even in challenging circumstances.
You can try it out using our demo app – just scan the barcode with your phone:
You can also take a look at our integration guides for JavaScript and React.js for implementations similar to this one. Should you have any questions, feel free to reach out to us on Slack or MS Teams or send us an email via sdksupport@scanbot.io
Interested in the Scanbot SDK’s performance compared to the ZXing library? Then take a look at the video below.