Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3adc257
Backup scanContinuous before frame-accurate refactor.
bparth24 Oct 8, 2025
fab6e95
Update documentation for enhancedPdf417Plugin
bparth24 Oct 8, 2025
71d9074
Add frame-accurate scanning method to OpticalScanner.
bparth24 Oct 8, 2025
06fb791
Add polling fallback method to OpticalScanner.
bparth24 Oct 8, 2025
8d1a1fb
Refactor scanContinuous to route by source type.
bparth24 Oct 8, 2025
27970d9
Move down backup function
bparth24 Oct 8, 2025
7c50798
Add comprehensive architecture documentation for continuous scanning.
bparth24 Oct 8, 2025
3ed24c3
Fix _createScanError helper to preserve error message context.
bparth24 Oct 8, 2025
9cc07da
Complete testing and verification of frame-accurate scanning.
bparth24 Oct 12, 2025
5113c27
Add performance documentation to README.
bparth24 Oct 12, 2025
17bf868
Document frame-accurate scanning refactor in CHANGELOG.
bparth24 Oct 12, 2025
02be7be
Update refactor notes
bparth24 Oct 12, 2025
9c8cedc
Correct lint issues and update comments
bparth24 Oct 12, 2025
be0377b
Correct comments in documentation
bparth24 Oct 12, 2025
81dd2e5
Update .gitignore to ignore package-lock.json
bparth24 Oct 12, 2025
df9d870
Delete Refactor-notes.md
bparth24 Oct 13, 2025
6255e6e
Update readme - correct formatting in code
bparth24 Oct 13, 2025
1146996
Update changelog - changed section, remove improved section.
bparth24 Oct 13, 2025
3dab62e
Add logging functionality
bparth24 Oct 13, 2025
2a8110d
Update console log with proper debug flag - logging functionality.
bparth24 Oct 13, 2025
4184c67
Remove package-lock.json
bparth24 Oct 13, 2025
dcfcb5c
Rename files with camel case format, fix inline comments to top (sepa…
bparth24 Oct 14, 2025
c2c19e9
Correct file name in readme and version in changelog file
bparth24 Oct 14, 2025
8460c32
Cleanup, format - documentation section and comments
bparth24 Oct 16, 2025
99c32ef
Use browser APIs for signal handling.
bparth24 Oct 18, 2025
2b84580
Remove _createTimeoutController function.
bparth24 Oct 18, 2025
6a705d8
Validate license before MRZ scanning.
bparth24 Oct 18, 2025
2e61ace
Refactor frame loop and simplify documentation.
bparth24 Oct 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ coverage
node_modules
reports
.cache
package-lock.json
.DS_STORE
72 changes: 46 additions & 26 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# bedrock-web-optical-scanner ChangeLog

## 1.1.0 - 2025-mm-dd

### Added

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normal style is no blank line after these sub headers.

Suggested change

- **Frame-accurate scanning** using `requestVideoFrameCallback()` for optimal performance.
- Automatic routing based on source type (HTMLVideoElement vs others).
- Polling fallback method for non-video sources.
- Ensures universal compatibility with all source types.
- Emits warning when using slower fallback path.
- Enhanced error messages with scan context.
- Comprehensive architecture documentation in code.
- Detailed comments explaining continuous scanning strategies.
- Performance characteristics for each approach.

### Changed

- Refactored `scanContinuous()` method to route by source type.
- Maintains same public API (no breaking changes for consumers).
- Internal implementation split into two strategies.
- Significantly improved performance for video sources.
- Updated error handling to include scan method context.
- User experience: From laggy/frustrating to instant/smooth.
- Performance regression from original `bedrock-vue-barcode-scanner` implementation.
- Restored frame-accurate scanning that was lost during refactor.

## 1.0.0 - 2025-10-02

### Added
Expand All @@ -9,38 +34,33 @@
- Core `OpticalScanner` class with async API for scanning various formats from images, video, or other sources.
- Plugin system for extensible scanning formats.
- Built-in plugins for:
- QR Code scanning (`qrCodePlugin`)
- PDF417 barcode scanning (`pdf417Plugin`)
- PDF417 Enhanced barcode scanning using Dynamsoft (`enhancedPdf417Plugin`)
- MRZ scanning using Dynamsoft (`mrzPlugin`)
- QR Code scanning (`qrCodePlugin`).
- PDF417 barcode scanning (`pdf417Plugin`).
- PDF417 Enhanced barcode scanning using Dynamsoft (`enhancedPdf417Plugin`).
- MRZ scanning using Dynamsoft (`mrzPlugin`).
- Camera utilities for:
- Getting default camera constraints
- Starting camera streams
- Listing available cameras
- Getting default camera constraints.
- Starting camera streams.
- Listing available cameras.
- Uses `barcode-detector` ponyfill for cross-browser barcode detection.
- Exports:
- `OpticalScanner`
- `createPlugin`
- `cameraUtils`
- New `CameraScanner` class for framework-agnostic scanning with unified API
- Orchestrates video stream management with configurable container strategies
- Handles continuous scanning with unified result formatting across scan types
- Centralizes scanning complexity
- Enables thin framework wrappers by abstracting low-level scanning details
- `createTimeOutController` function in OpticalScanner for better scan timeout management

### Improved

- Enhanced OpticalScanner debugging and timeout handling
- Comprehensive debug logging for better troubleshooting
- Updated documentation for improved code clarity
- MRZ plugin structure and debugging capabilities
- Refactored code structure for improved readability
- Updated documentation for better maintainability
- Overall separation of UI concerns from scanning logic for better code reusability
- New `CameraScanner` class for framework-agnostic scanning with unified API.
- Orchestrates video stream management with configurable container strategies.
- Handles continuous scanning with unified result formatting across scan types.
- Centralizes scanning complexity.
- Enables thin framework wrappers by abstracting low-level scanning details.
- `createTimeOutController` function in OpticalScanner for better scan timeout management.
- Enhanced OpticalScanner debugging and timeout handling.
- Comprehensive debug logging for better troubleshooting.
- MRZ plugin structure and debugging capabilities.
- Refactored code structure for improved readability.
- Updated documentation for better maintainability.
- Overall separation of UI concerns from scanning logic for better code reusability.

### Changed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should clean up the format of entries in the same ways mentioned above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dlongley

addressed above in commit - 1146996

- **NOTE**: CameraScanner now serves as the primary high-level interface for most scanning use cases
- Improved modularity to support framework-agnostic design patterns

- **NOTE**: CameraScanner now serves as the primary high-level interface for most scanning use cases.
- Improved modularity to support framework-agnostic design patterns.
163 changes: 151 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,153 @@ allows you to easily add support for new formats and scanning modes.
## Features

- **Multi-format scanning**: Built-in support for QR codes, PDF417 barcodes, and MRZ format
- **High performance**: 12-16 fps frame-accurate scanning with video sources (30x-40x faster than polling)
- **Intelligent fallback**: Automatic polling for non-video sources (universal compatibility)
- **Flexible scanning modes**: First match, all formats, or exhaustive scanning
- **Plugin architecture**: Easily extend with custom format scanners
- **Camera utilities**: Helper functions for camera access and video handling
- **Enhanced error context**: Rich error messages with frame counts, scan method, and abort reason
- **Framework agnostic**: Works with any JavaScript framework or vanilla JS
- **Web Worker ready**: Architecture prepared for future threading support

## Performance

### Frame-Accurate Scanning

The scanner uses `requestVideoFrameCallback()` for optimal performance when scanning from video elements:

**Measured Performance:**

- **Scan rate:** 12-16 frame per second (fps).
- **Time per scan:** 62-83 milliseconds.
- **Video frame rate:** 60 fps (camera/video source).
- **Coverage:** Processes ~20-27% of available video frames.
- **30x-40x faster** than polling-based approaches.
- **Near-instant** barcode detection for responsive UX.

**Note:** Above performance measurements were obtained from:

- **Camera & Device:** Native camera, Macbook Pro M1 (arm64), 16 GB RAM.
- **Browser:** Google Chrome (latest version - 141.0.7390.77).

**Why not 60 fps?**

The scan rate is lower than video frame rate because:

1. **Processing takes time** - Each scan takes 62-83ms to complete (barcode detection is CPU-intensive).
2. **JavaScript is single-threaded** - Scanning blocks until complete.
3. **This is normal and expected** - Detection still feels instant to users.

### Scanning Strategies

The library automatically selects the optimal strategy based on source type:

| Source Type | Method | Performance | Use Case |
|-------------|--------|-------------|----------|
| Video (HTMLVideoElement) | `requestVideoFrameCallback()` | 12-16 fps | Real-time camera scanning (optimal) |
| Other sources | `setTimeout()` polling | 0.4 fps | Fallback for compatibility |

### Performance Metrics

Comparison of polling vs frame-accurate approaches:

| Metric | Polling | Frame-Accurate | Improvement |
|--------|---------------|----------------------|-------------|
| Scan Rate | 0.4 fps | 12-16 fps | **30x-40x faster** |
| Detection Time | 2.5-7.5s | < 0.5s | **15x faster** |
| Frame Interval | 2500ms | 62-83ms | **97% reduction** |
| User Experience | Laggy, frustrating | Instant, smooth | **Significantly improved** |

Note: Math behind frame interval for frame-accurate scan is 12 fps -> 83ms per frame (1000/12) = 83ms and
16 fps -> 62ms per frame (1000/16) = 62.5ms.

**Want implementation details?** See [Continuous Scanning Architecture](#continuous-scanning-architecture)

## Continuous Scanning Architecture

### Overview

The `OpticalScanner` class implements two strategies for continuous scanning, automatically selecting the optimal approach based on source type.

### Strategy 1: Frame-Accurate Scanning (Optimal)

**Method:** `_scanContinuousFrameCallback()` originally logic from (`bedrock-vue-barcode-scanner` library):

**When used:** Automatically selected for `HTMLVideoElement` sources

**How it works:**

```javascript
// Uses requestVideoFrameCallback for frame synchronization
video.requestVideoFrameCallback(() => {
// Scan current video frame
const results = await this.scan(video, options);
if(results.length > 0) {
return results; // Found barcode - done!
}
// No results - try next frame
video.requestVideoFrameCallback(scanFrame);
});
```

**Advantages:**

- Scans every video frame (no missed opportunities)
- No artificial delays (maximum responsiveness)
- Efficient resource usage (only scans when new frames available)
- Best possible user experience

### Strategy 2: Polling-Based Scanning (Fallback)

**Method:** `_scanContinuousPolling()`

**When used:** Automatically selected for non-video sources (compatibility)

**How it works:**

```javascript
// Uses setTimeout with 2.5 second delays
while(!aborted) {
const results = await this.scan(source, options);
if(results.length > 0) {
return results; // Found barcode - done!
}
// No results - wait before next attempt
await new Promise(resolve => setTimeout(resolve, 2500));
}
```

**When you'd see this:**

- Scanning from canvas elements (rare)
- Scanning from ImageData (rare)
- Fallback for unsupported source types

**Warning:** If developer/user see "Polling fallback" in console, your source isn't optimal for performance.

**Automatic Routing Logic**
The public `scanContinuous()` method automatically routes to the best strategy:

```javascript
async scanContinuous(source, options) {
// Check source type
if(source instanceof HTMLVideoElement) {
// Fast path: 12-16 fps frame-accurate
console.log('bedrock-web-optical-scanner: Using frame-callback (optimal)');
return this._scanContinuousFrameCallback(source, options);
}
// Fallback: 0.4 fps polling
console.warn('bedrock-web-optical-scanner: Using polling fallback (slower)');
return this._scanContinuousPolling(source, options);
}
```

## Directory & File Structure

```
lib/
camera-scanner.js // Camera Scanner class
optical-scanner.js // Optical scanner class
cameraScanner.js // Camera Scanner class
opticalScanner.js // Optical scanner class
plugins/
index.js // Plugin registration
enhancedpdf417Plugin.js // Enhanced PDF417 plugin using Dynamsoft
Expand Down Expand Up @@ -60,7 +195,7 @@ The scanner supports three different resolution strategies:

### 'first' Mode (Default)

Resolves as soon as any plugin successfully scans the requested formats. This is the suitable for most use cases where you want quick results.
Resolves as soon as any plugin successfully scans the requested formats. This is suitable for most use cases where you want quick results.

### 'all' Mode

Expand All @@ -75,14 +210,14 @@ succeeded. This is the most thorough option but potentially slower.
```javascript
// Example usage
const results = await scanner.scan(image, {
formats: ['qr_code', 'pdf417', 'pdf417_enhanced'],
formats: ['qr_code', 'pdf417', 'pdf417_enhanced', 'mrz'],
mode: 'first' // or 'all' or 'exhaustive'
});
```

## Main Components

### `lib/camera-scanner.js`
### `lib/cameraScanner.js`

- Exports the `CameraScanner` class - a high-level camera scanner that provides a simple API for framework integration.
- Handles all scanning complexities internally by delegating scan operations to OpticalScanner class - frameworks just handle UI.
Expand All @@ -91,10 +226,15 @@ const results = await scanner.scan(image, {
- Manages camera lifecycle, plugin configuration, and provides built-in timeout handling.
- Designed for easy integration with Vue, React, or any JavaScript framework.

### `lib/optical-scanner.js`
### `lib/opticalScanner.js`

- Exports the `OpticalScanner` class.
- Handles scanning images/files for barcodes using registered plugins.
- Exports the `OpticalScanner` class - core scanning engine.
- Handles scanning from images/video/files using registered plugins.
- Implements two continuous scanning strategies:
- **Frame-accurate:** 12-16 fps using `requestVideoFrameCallback()` (optimal)
- **Polling fallback:** 0.4 fps using `setTimeout()` (compatibility)
- Automatically routes to best strategy based on source type.
- Provides rich error context (frame counts, scan method, abort reason).
- Accepts plugins for different barcode formats.

### `lib/plugins/`
Expand All @@ -113,8 +253,7 @@ const results = await scanner.scan(image, {

## Architecture Principle

- The web module handles all scanning complexities, while framework modules (Vue, React, etc.) focus purely
on UI concerns and user interactions.
- The web module handles all scanning complexities, while framework modules (Vue, React, etc.) focus purely on UI concerns and user interactions.

## Plugin Architecture

Expand All @@ -128,7 +267,7 @@ Vue (UI Only) -> CameraScanner (Business Logic) -> OpticalScanner (Core Engine)

## Core Classes

`lib/opitcal-scanner.js`
`lib/opticalScanner.js`

- Core scanning engine - handles the actual scanning process
- Plugin architecture - manages format-specific plugins
Expand All @@ -139,7 +278,7 @@ Vue (UI Only) -> CameraScanner (Business Logic) -> OpticalScanner (Core Engine)
- Format-agnostic - doesn't know about specific barcode types
- Source-flexible - can scan from image, video, canvas, or ImageData

`lib/camera-scanner.js`
`lib/cameraScanner.js`

- High-level API for framework integration
- Business logic orchestration - combines camera + scanning
Expand Down
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*!
* Copyright (c) 2025 Digital Bazaar, Inc. All rights reserved.
*/
export {CameraScanner} from './lib/camera-scanner.js';
export {OpticalScanner} from './lib/optical-scanner.js';
export {CameraScanner} from './lib/cameraScanner.js';
export {OpticalScanner} from './lib/opticalScanner.js';
export * from './lib/plugins/index.js';
export * as cameraUtils from './lib/utils/camera.js';
Loading