A React barcode scanner component with WASM support for ZXing and Photon image processing. Includes IIFE standalone build for direct browser use.
npm install bs-barcode-scanner

A powerful, high-performance barcode and QR code scanner library with WebAssembly support. Features ZXing-WASM for maximum compatibility and Photon-WASM for advanced image processing. Provides a familiar API with standalone browser support.
- ๐ Zero Dependencies Runtime - Standalone IIFE build works directly in browsers
- ๐ฏ Multiple Barcode Formats - Supports 13+ barcode types including QR, EAN, UPC, Code128, and more
- โก WebAssembly Powered - Uses ZXing-WASM and Photon-WASM for blazing-fast processing
- ๐ง Worker Pool Support - Multi-threaded processing for optimal performance
- ๐ธ Advanced Camera Controls - Torch toggle, camera switching, tap-to-focus
- ๐จ Customizable UI - Multiple GUI styles (laser, viewfinder, none)
- ๐ผ๏ธ Intelligent Image Processing - Adaptive strategies including grayscale, contrast enhancement, edge detection
- ๐พ Frame Caching - Smart frame deduplication to avoid redundant processing
- ๐๏ธ Detailed Logging - Uses console.log, console.debug, and console.trace for different verbosity levels
``bash`
npm install bs-barcode-scanner
Or with yarn:
`bash`
yarn add bs-barcode-scanner
The simplest way to get started - no build tools required!
#### Using CDN
`html
`
#### Using Local Installation
`html
`
`typescript
import {
BarcodePicker,
ScanSettings,
Symbology,
GuiStyle
} from 'bs-barcode-scanner';
// Configure scan settings
const settings = new ScanSettings();
settings.enableSymbologies([
Symbology.QR,
Symbology.EAN13,
Symbology.EAN8,
Symbology.CODE128,
Symbology.DATA_MATRIX
]);
settings.setMaxNumberOfCodesPerFrame(3);
settings.setCodeDuplicateFilter(1500);
// Create scanner instance
const container = document.getElementById('scanner-container');
const picker = await BarcodePicker.create(container, {
scanSettings: settings,
guiStyle: GuiStyle.VIEWFINDER,
playSoundOnScan: true,
vibrateOnScan: true,
enableTorchToggle: true,
enableCameraSwitcher: true,
enableTapToFocus: true,
useWorkers: true, // Enable multi-threaded processing
workerPoolConfig: {
workerCount: 4,
workerScriptPath: './node_modules/bs-barcode-scanner/dist/barcode-worker.js'
}
});
// Handle scan events
picker.onDidScan((result) => {
result.barcodes.forEach(barcode => {
console.log(Code: ${barcode.data});Format: ${barcode.symbology}
console.log();Raw data:
console.log(, barcode.rawData);
});
});
// Control scanning
picker.resumeScanning();
// picker.pauseScanning();
// picker.stopScanning();
`
The main scanner component.
#### Static Methods
##### BarcodePicker.create(element, options?)
Creates a new barcode picker instance.
Parameters:
- element: HTMLElement - Container element for the scanneroptions?: BarcodePickerOptions
- - Configuration options
Returns: Promise
Example:
`typescript`
const picker = await BarcodePicker.create(container, {
scanSettings: new ScanSettings(),
guiStyle: GuiStyle.LASER,
playSoundOnScan: true
});
#### Instance Methods
##### onDidScan(callback)
Register a callback for successful scans.
Parameters:
- callback: (result: ScanResult) => void - Function called when barcodes are detected
`typescript`
picker.onDidScan((result) => {
result.barcodes.forEach(barcode => {
console.log(barcode.data);
});
});
##### onScan(callback)
Register a callback with session information.
Parameters:
- callback: (session: ScanSession) => void - Function called with scan session
`typescript`
picker.onScan((session) => {
console.log('Newly recognized codes:', session.newlyRecognizedCodes);
});
##### onError(callback)
Register an error callback.
Parameters:
- callback: (error: Error) => void - Function called on errors
##### resumeScanning()
Start or resume barcode scanning.
##### pauseScanning()
Pause barcode scanning without releasing the camera.
##### stopScanning()
Stop scanning and release camera resources.
##### destroy()
Clean up all resources and remove the scanner.
##### setTorchEnabled(enabled)
Toggle the camera flash/torch.
Parameters:
- enabled: boolean - True to turn on, false to turn off
Returns: Promise
##### setActiveCamera(camera, cameraSettings?)
Switch to a specific camera.
Parameters:
- camera: { deviceId?: string } - Camera to activatecameraSettings?: CameraSettings
- - Optional camera settings
Returns: Promise
##### getActiveCamera()
Get information about the currently active camera.
Returns: { deviceId?: string, label: string, cameraType: string } | undefined
Configuration for barcode detection.
#### Methods
##### enableSymbologies(symbologies)
Enable specific barcode types.
Parameters:
- symbologies: string[] - Array of symbology constants
`typescript`
const settings = new ScanSettings();
settings.enableSymbologies([
Symbology.QR,
Symbology.EAN13,
Symbology.CODE128
]);
##### setSymbologyEnabled(symbology, enabled)
Enable or disable a specific barcode type.
Parameters:
- symbology: string - Symbology constantenabled: boolean
- - Enable or disable
##### setCodeDuplicateFilter(milliseconds)
Set the duplicate detection window.
Parameters:
- milliseconds: number - Time window for filtering duplicates (default: 500)
##### setMaxNumberOfCodesPerFrame(max)
Set maximum barcodes to detect per frame.
Parameters:
- max: number - Maximum number of codes (default: 1)
##### setActiveScanningArea(rect)
Restrict scanning to a specific area.
Parameters:
- rect: { x: number, y: number, width: number, height: number } - Scanning area (normalized 0-1)
`typescript`
settings.setActiveScanningArea({
x: 0.1,
y: 0.3,
width: 0.8,
height: 0.4
});
The Symbology object provides constants for all supported barcode formats:
`typescript`
Symbology.EAN13 // EAN-13
Symbology.EAN8 // EAN-8
Symbology.UPCA // UPC-A
Symbology.UPCE // UPC-E
Symbology.CODE128 // Code 128
Symbology.CODE39 // Code 39
Symbology.CODE93 // Code 93
Symbology.ITF // Interleaved 2 of 5
Symbology.CODABAR // Codabar
Symbology.QR // QR Code
Symbology.DATA_MATRIX // Data Matrix
Symbology.AZTEC // Aztec
Symbology.PDF417 // PDF417
Control the scanner overlay appearance:
`typescript`
GuiStyle.NONE // No overlay
GuiStyle.LASER // Laser line overlay
GuiStyle.VIEWFINDER // Rectangular viewfinder with rounded corners
`typescript`
interface BarcodePickerOptions {
accessCamera?: boolean; // Request camera access (default: true)
camera?: {
deviceId?: string; // Specific camera device ID
};
cameraSettings?: {
resolutionPreference?: string; // Resolution preference
};
enableCameraSwitcher?: boolean; // Show camera switch button (default: true)
enableTapToFocus?: boolean; // Enable tap-to-focus (default: true)
enableTorchToggle?: boolean; // Show torch toggle button (default: true)
guiStyle?: number; // GUI style (default: GuiStyle.LASER)
playSoundOnScan?: boolean; // Play beep on scan (default: false)
scanSettings?: ScanSettings; // Scan configuration
scanningPaused?: boolean; // Start in paused state (default: false)
vibrateOnScan?: boolean; // Vibrate on scan (default: false)
visible?: boolean; // Initial visibility (default: true)
useWorkers?: boolean; // Enable worker pool (default: true)
workerPoolConfig?: {
workerCount?: number; // Number of workers (default: 4)
workerScriptPath?: string; // Path to worker script
};
}
Enable worker pool for optimal performance:
`typescript`
const picker = await BarcodePicker.create(container, {
useWorkers: true,
workerPoolConfig: {
workerCount: 4,
workerScriptPath: './dist/barcode-worker.js'
}
});
Focus scanning on a specific region:
`typescript`
const settings = new ScanSettings();
settings.setActiveScanningArea({
x: 0.1, // 10% from left
y: 0.3, // 30% from top
width: 0.8, // 80% of width
height: 0.4 // 40% of height
});
Detect multiple barcodes in a single frame:
`typescript
const settings = new ScanSettings();
settings.setMaxNumberOfCodesPerFrame(5);
picker.onDidScan((result) => {
console.log(Found ${result.barcodes.length} codes:);${index + 1}. ${barcode.data} (${barcode.symbology})
result.barcodes.forEach((barcode, index) => {
console.log();`
});
});
`typescript`
picker.onError((error) => {
console.error('Scanner error:', error);
if (error.name === 'NotAllowedError') {
alert('Camera access denied. Please grant permission.');
} else if (error.name === 'NotFoundError') {
alert('No camera found on this device.');
}
});
`typescript
// Toggle torch/flash
await picker.setTorchEnabled(true);
// Get currently active camera information
const activeCameraInfo = picker.getActiveCamera();
console.log('Active camera info:', activeCameraInfo);
// Switch to specific camera
await picker.setActiveCamera({ deviceId: 'your-camera-device-id' });
// Apply camera settings
await picker.applyCameraSettings({ resolutionPreference: 'hd' });
`
`typescript`
picker.onScan((session) => {
const codes = session.newlyRecognizedCodes;
// Process new codes
codes.forEach(code => {
console.log('New code:', code.data);
});
// Control scanning flow
if (codes.length > 0) {
session.pauseScanning();
// Do something with the code...
setTimeout(() => session.resumeScanning(), 2000);
}
});
`bashInstall dependencies
npm install
$3
The build process creates:
-
dist/standalone.js - Main IIFE bundle for browsers
- dist/standalone.d.ts - TypeScript type definitions
- dist/barcode-worker.js - Web Worker script for multi-threaded processing
- WASM files are bundled from dependencies๐งช Testing
The library includes comprehensive test coverage:
`bash
Run all tests
npm testWatch mode for development
npm run test:watchGenerate coverage report
npm run test:coverage
`Test files are located in
__tests__/:
- legacy-barcode-scanner.test.ts - Main scanner tests
- barcode-image-processor.test.ts - Image processing tests
- worker-pool.test.ts - Worker pool tests
- standalone-iife.test.ts - Standalone build tests๐ Browser Compatibility
- Chrome/Edge: Full support with Web Workers
- Firefox: Full support with Web Workers
- Safari: Full support (iOS 14.3+, macOS 11+)
- Mobile: Full support on iOS and Android
Requirements:
- WebAssembly support
- getUserMedia API for camera access
- ES6+ JavaScript support
๐ Example Projects
$3
See simple-example.html for a complete standalone example.
To run the example:
`bash
Start a local server
python3 -m http.server 8000
or
npx serveOpen browser
Navigate to http://localhost:8000/simple-example.html
`$3
`typescript
import { useEffect, useRef } from 'react';
import { BarcodePicker, ScanSettings, Symbology } from 'bs-barcode-scanner';function BarcodeScanner() {
const containerRef = useRef(null);
const pickerRef = useRef(null);
useEffect(() => {
const initScanner = async () => {
if (!containerRef.current) return;
const settings = new ScanSettings();
settings.enableSymbologies([Symbology.QR, Symbology.EAN13]);
const picker = await BarcodePicker.create(containerRef.current, {
scanSettings: settings,
guiStyle: 1
});
picker.onDidScan((result) => {
console.log('Scanned:', result.barcodes);
});
pickerRef.current = picker;
};
initScanner();
return () => {
pickerRef.current?.destroy();
};
}, []);
return
;
}
`๐ How It Works
$3
1. Camera Access: Uses
getUserMedia API to access device cameras
2. Frame Capture: Continuously captures frames from the video stream
3. Worker Pool: Distributes frame processing across multiple web workers
4. Image Processing: Applies intelligent preprocessing strategies:
- Resize for optimal performance
- Grayscale conversion
- Contrast enhancement
- Edge detection
- Gaussian blur
- Thresholding
5. Barcode Detection: Uses ZXing-WASM for high-performance barcode recognition
6. Caching: Smart frame deduplication to avoid redundant processing
7. Result Delivery: Filters duplicates and delivers results via callbacks$3
The library uses multiple processing strategies in sequence:
1. Original Frame: Direct processing without modifications
2. Grayscale: Convert to grayscale for better contrast
3. Contrast Enhancement: Improve barcode edge visibility
4. Edge Detection: Emphasize barcode patterns
5. Gaussian Blur + Threshold: Reduce noise and binarize
6. Sharpen: Enhance barcode edges
Strategies are applied until a barcode is detected or all strategies are exhausted.
๐ค Contributing
Contributions are welcome! Please follow these steps:
1. Fork the repository
2. Create a feature branch (
git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add amazing feature')
4. Push to the branch (git push origin feature/amazing-feature)
5. Open a Pull Request$3
- Write tests for new features
- Follow the existing code style (use
npm run lint)
- Update documentation as needed
- Ensure all tests pass (npm test`)MIT License - see LICENSE file for details.
This library builds upon excellent open-source projects:
- ZXing-WASM - WebAssembly port of ZXing barcode library
- Photon - High-performance image processing library
- barcode-detector - Polyfill for Barcode Detection API
- Issues: GitHub Issues
- NPM Package: bs-barcode-scanner
- Repository: GitHub
---
Made with โค๏ธ by Zoobean
If you find this library helpful, please consider giving it a โญ on GitHub!