Added scanning barcodes with a camera
This commit is contained in:
758
quagga2/quagga2-1.12.1/docs/reference/api.md
Normal file
758
quagga2/quagga2-1.12.1/docs/reference/api.md
Normal file
@@ -0,0 +1,758 @@
|
||||
# API Documentation {#api-documentation}
|
||||
|
||||
Complete reference for all Quagga2 methods, callbacks, and events.
|
||||
|
||||
## Core Methods {#core-methods}
|
||||
|
||||
### `Quagga.init(config, callback)` {#quagga-init}
|
||||
|
||||
Initializes the library with the given configuration and requests camera access if using live stream mode.
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `config` (Object) - Configuration object. See [Configuration Reference](configuration.md) for complete details.
|
||||
- `callback` (Function) - Called when initialization completes: `callback(err)`
|
||||
- `err` (Error | null) - Error object if initialization failed, `null` on success
|
||||
|
||||
**Returns**: `void`
|
||||
|
||||
**Example - Live Camera**:
|
||||
|
||||
```javascript
|
||||
Quagga.init({
|
||||
inputStream: {
|
||||
type: "LiveStream",
|
||||
target: document.querySelector('#scanner') // Or '#scanner'
|
||||
},
|
||||
decoder: {
|
||||
readers: ["code_128_reader"]
|
||||
}
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
console.error("Initialization failed:", err);
|
||||
return;
|
||||
}
|
||||
console.log("Initialization successful, ready to start");
|
||||
Quagga.start();
|
||||
});
|
||||
```
|
||||
|
||||
**Example - Static Images**:
|
||||
|
||||
```javascript
|
||||
Quagga.init({
|
||||
inputStream: {
|
||||
type: "ImageStream",
|
||||
src: "/path/to/images/*.jpg",
|
||||
target: document.querySelector('#scanner')
|
||||
},
|
||||
decoder: {
|
||||
readers: ["ean_reader", "code_128_reader"]
|
||||
}
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
Quagga.start();
|
||||
});
|
||||
```
|
||||
|
||||
**Error Handling**:
|
||||
|
||||
The callback receives an `err` parameter if initialization fails. Common causes:
|
||||
|
||||
- User denies camera permission
|
||||
- No camera device found
|
||||
- Browser doesn't support required APIs
|
||||
- Invalid configuration parameters
|
||||
|
||||
Always check for errors before calling `start()`:
|
||||
|
||||
**Target Element**:
|
||||
|
||||
If no `target` is specified, Quagga looks for an element matching the CSS selector `#interactive.viewport` (for backwards compatibility).
|
||||
|
||||
### `Quagga.start()` {#quagga-start}
|
||||
|
||||
Starts the video stream and begins locating and decoding barcodes.
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: `void`
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
Quagga.init(config, function(err) {
|
||||
if (!err) {
|
||||
Quagga.start();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Prerequisites**:
|
||||
|
||||
- `Quagga.init()` must have completed successfully
|
||||
- For live stream: Camera permission must be granted
|
||||
|
||||
**Note**: Call this in the `init()` callback after checking for errors.
|
||||
|
||||
### `Quagga.stop()` {#quagga-stop}
|
||||
|
||||
Stops the decoder from processing images and disconnects the camera if one was requested.
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: `Promise<void>` - Resolves when cleanup is complete
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
// Stop scanning
|
||||
await Quagga.stop();
|
||||
console.log("Scanner stopped");
|
||||
|
||||
// Or with .then()
|
||||
Quagga.stop().then(() => {
|
||||
console.log("Scanner stopped");
|
||||
});
|
||||
```
|
||||
|
||||
**Behavior**:
|
||||
|
||||
- Stops processing new frames
|
||||
- If using live camera: disconnects and releases camera
|
||||
- Does not remove event listeners (use `offDetected()` / `offProcessed()` for that)
|
||||
- Returns a Promise that resolves when camera release is complete
|
||||
|
||||
### `Quagga.pause()` {#quagga-pause}
|
||||
|
||||
Pauses frame processing without stopping the camera or releasing resources.
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: `void`
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
// Pause scanning temporarily
|
||||
Quagga.pause();
|
||||
|
||||
// Later, resume scanning
|
||||
Quagga.start();
|
||||
```
|
||||
|
||||
**Behavior**:
|
||||
|
||||
- Stops processing new frames (no more `onProcessed` or `onDetected` callbacks)
|
||||
- **Does not stop the camera** - the video stream continues running
|
||||
- **Does not release resources** - the camera remains connected
|
||||
- Can be resumed by calling `Quagga.start()`
|
||||
|
||||
**Use Cases**:
|
||||
|
||||
- Temporarily pause scanning while showing a modal or dialog
|
||||
- Reduce CPU usage when the scanner is not visible
|
||||
- Pause after detecting a barcode to allow user confirmation before resuming
|
||||
|
||||
**Difference from `stop()`**:
|
||||
|
||||
| Aspect | `pause()` | `stop()` |
|
||||
|--------|-----------|----------|
|
||||
| Frame processing | Stops | Stops |
|
||||
| Camera stream | **Continues** | Disconnects |
|
||||
| Resources | **Retained** | Released |
|
||||
| Resume with | `start()` | `init()` + `start()` |
|
||||
|
||||
> **Note**: Since `pause()` keeps the camera running, the user's camera indicator light will remain on. If you want to fully release the camera, use `stop()` instead.
|
||||
|
||||
### `Quagga.onDetected(callback)` {#quagga-ondetected}
|
||||
|
||||
Registers a callback that is triggered when a barcode is successfully located and decoded.
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `callback` (Function) - Handler function: `callback(data)`
|
||||
- `data` (Object) - Result object containing decoded barcode information
|
||||
|
||||
**Returns**: `void`
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
Quagga.onDetected(function(result) {
|
||||
const code = result.codeResult.code;
|
||||
const format = result.codeResult.format;
|
||||
|
||||
console.log(`Detected ${format} barcode: ${code}`);
|
||||
|
||||
// Process the barcode
|
||||
processBarcode(code);
|
||||
});
|
||||
```
|
||||
|
||||
**Multiple Handlers**:
|
||||
|
||||
You can register multiple handlers - all will be called:
|
||||
|
||||
```javascript
|
||||
Quagga.onDetected(handler1);
|
||||
Quagga.onDetected(handler2); // Both execute on detection
|
||||
```
|
||||
|
||||
### `Quagga.onProcessed(callback)` {#quagga-onprocessed}
|
||||
|
||||
Registers a callback that is called for each processed frame, regardless of detection success.
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `callback` (Function) - Handler function: `callback(data)`
|
||||
- `data` (Object) - Processing result with detailed information
|
||||
|
||||
**Returns**: `void`
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
Quagga.onProcessed(function(result) {
|
||||
const drawingCtx = Quagga.canvas.ctx.overlay;
|
||||
const drawingCanvas = Quagga.canvas.dom.overlay;
|
||||
|
||||
if (result) {
|
||||
// Draw boxes and lines for visualization
|
||||
if (result.boxes) {
|
||||
drawingCtx.clearRect(0, 0,
|
||||
drawingCanvas.width, drawingCanvas.height);
|
||||
|
||||
result.boxes.forEach(function(box) {
|
||||
Quagga.ImageDebug.drawPath(box, {x: 0, y: 1},
|
||||
drawingCtx, {color: "blue", lineWidth: 2});
|
||||
});
|
||||
}
|
||||
|
||||
if (result.box) {
|
||||
Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1},
|
||||
drawingCtx, {color: "green", lineWidth: 2});
|
||||
}
|
||||
|
||||
if (result.codeResult && result.codeResult.code) {
|
||||
// Successfully decoded
|
||||
console.log("Code detected:", result.codeResult.code);
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Use Cases**:
|
||||
|
||||
- Custom visualization of detection process
|
||||
- Counting processed frames
|
||||
- Performance monitoring
|
||||
- Drawing custom overlays
|
||||
|
||||
### `Quagga.drawScannerArea()` {#quagga-drawscannerarea}
|
||||
|
||||
Manually draws the scanner area overlay on the overlay canvas using the configured `inputStream.area`.
|
||||
|
||||
**Parameters**: None (uses the area configuration from `Quagga.init()`)
|
||||
|
||||
**Returns**: `void`
|
||||
|
||||
**Behavior**:
|
||||
|
||||
- Only draws when `locate` is `false` and `inputStream.area` is configured with styling
|
||||
- Uses the actual adjusted scanning area (after patch alignment) to accurately match where barcodes will be detected
|
||||
- Automatically accounts for the area offset and dimensions
|
||||
- Skips drawing if no styling is provided (no `borderColor`, `borderWidth`, or `backgroundColor`)
|
||||
- Requires `canvas.createOverlay: true` so the overlay canvas exists
|
||||
- Drawing occurs automatically every processed frame when conditions are met
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
// Configure area during init
|
||||
Quagga.init({
|
||||
inputStream: {
|
||||
area: {
|
||||
top: "30%",
|
||||
right: "10%",
|
||||
bottom: "30%",
|
||||
left: "10%",
|
||||
borderColor: "#0F0",
|
||||
borderWidth: 2,
|
||||
backgroundColor: "rgba(255,0,0,0.15)"
|
||||
}
|
||||
},
|
||||
locate: false
|
||||
});
|
||||
|
||||
// Later, manually redraw if you've cleared the overlay
|
||||
Quagga.drawScannerArea();
|
||||
```
|
||||
|
||||
### `Quagga.offDetected(handler)` {#quagga-offdetected}
|
||||
|
||||
Removes a previously registered `onDetected` handler.
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `handler` (Function, optional) - Specific handler to remove. If omitted, **all** handlers are removed.
|
||||
|
||||
**Returns**: `void`
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
function myHandler(result) {
|
||||
console.log(result.codeResult.code);
|
||||
}
|
||||
|
||||
Quagga.onDetected(myHandler);
|
||||
|
||||
// Later: remove specific handler
|
||||
Quagga.offDetected(myHandler);
|
||||
|
||||
// Or remove all handlers
|
||||
Quagga.offDetected();
|
||||
```
|
||||
|
||||
### `Quagga.offProcessed(handler)` {#quagga-offprocessed}
|
||||
|
||||
Removes a previously registered `onProcessed` handler.
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `handler` (Function, optional) - Specific handler to remove. If omitted, **all** handlers are removed.
|
||||
|
||||
**Returns**: `void`
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
function processHandler(result) {
|
||||
// Process frame
|
||||
}
|
||||
|
||||
Quagga.onProcessed(processHandler);
|
||||
|
||||
// Remove specific handler
|
||||
Quagga.offProcessed(processHandler);
|
||||
|
||||
// Or remove all handlers
|
||||
Quagga.offProcessed();
|
||||
```
|
||||
|
||||
### `Quagga.decodeSingle(config, callback)` {#quagga-decodesingle}
|
||||
|
||||
Decodes a single image without using `getUserMedia`. Useful for processing uploaded images or static images.
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `config` (Object) - Configuration object (subset of full config)
|
||||
- `callback` (Function) - Result handler: `callback(result)`
|
||||
- `result` (Object) - Same format as `onDetected` callback
|
||||
|
||||
**Returns**: `void`
|
||||
|
||||
**Important - Default Scaling**: `decodeSingle` has a built-in default of `inputStream.size: 800`. This means images are **automatically scaled to 800px** on their longest side (both larger images scaled down AND smaller images scaled up). The result's `box`, `boxes`, and `line` coordinates are returned in this scaled coordinate space, not the original image dimensions. To use the original image dimensions without scaling, set `inputStream.size` to `0`.
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
Quagga.decodeSingle({
|
||||
src: '/images/barcode.jpg', // Or data URL
|
||||
decoder: {
|
||||
readers: ["code_128_reader", "ean_reader"]
|
||||
},
|
||||
locate: true // Try to locate barcode in image
|
||||
// Note: inputStream.size defaults to 800; images are scaled to 800px (up or down)
|
||||
}, function(result) {
|
||||
if (result && result.codeResult) {
|
||||
console.log("Detected:", result.codeResult.code);
|
||||
console.log("Format:", result.codeResult.format);
|
||||
} else {
|
||||
console.log("No barcode detected");
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Using Data URLs**:
|
||||
|
||||
```javascript
|
||||
// From file input
|
||||
document.querySelector('#file-input').addEventListener('change', function(e) {
|
||||
const file = e.target.files[0];
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function(event) {
|
||||
Quagga.decodeSingle({
|
||||
src: event.target.result, // Data URL
|
||||
decoder: {
|
||||
readers: ["code_128_reader"]
|
||||
}
|
||||
// Default size: 800 applies - image scaled if larger
|
||||
}, function(result) {
|
||||
if (result && result.codeResult) {
|
||||
alert("Barcode: " + result.codeResult.code);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
```
|
||||
|
||||
**Node.js Usage**:
|
||||
|
||||
```javascript
|
||||
const Quagga = require('@ericblade/quagga2').default;
|
||||
|
||||
Quagga.decodeSingle({
|
||||
src: "./barcode.jpg",
|
||||
inputStream: {
|
||||
size: 800 // This is actually the default; shown explicitly here
|
||||
},
|
||||
decoder: {
|
||||
readers: ["code_128_reader"]
|
||||
}
|
||||
}, function(result) {
|
||||
if (result && result.codeResult) {
|
||||
console.log("Code:", result.codeResult.code);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Result Object {#result-object}
|
||||
|
||||
The result object passed to `onDetected`, `onProcessed`, and `decodeSingle` callbacks contains detailed information about the detection and decoding process.
|
||||
|
||||
### Complete Result Structure {#result-structure}
|
||||
|
||||
```javascript
|
||||
{
|
||||
codeResult: {
|
||||
code: "FANAVF1461710", // The decoded barcode string
|
||||
format: "code_128", // Barcode format
|
||||
start: 355, // Start position
|
||||
end: 26, // End position
|
||||
codeset: 100, // Code 128 specific
|
||||
startInfo: {
|
||||
error: 1.0,
|
||||
code: 104,
|
||||
start: 21,
|
||||
end: 41
|
||||
},
|
||||
decodedCodes: [ // Individual code segments
|
||||
{ code: 104, start: 21, end: 41 },
|
||||
// ... more segments
|
||||
{ error: 0.88, code: 106, start: 328, end: 350 }
|
||||
],
|
||||
endInfo: {
|
||||
error: 0.88,
|
||||
code: 106,
|
||||
start: 328,
|
||||
end: 350
|
||||
},
|
||||
direction: -1 // Scan direction
|
||||
},
|
||||
line: [ // Scan line coordinates
|
||||
{ x: 25.97, y: 360.56 },
|
||||
{ x: 401.92, y: 70.88 }
|
||||
],
|
||||
angle: -0.657, // Rotation angle in radians
|
||||
pattern: [0, 0, 1, 1, ...], // Bar pattern (0=space, 1=bar)
|
||||
box: [ // Primary bounding box (4 corners)
|
||||
[77.41, 410.93], // Top-left
|
||||
[0.05, 310.54], // Top-right
|
||||
[360.16, 33.06], // Bottom-right
|
||||
[437.51, 133.45] // Bottom-left
|
||||
],
|
||||
boxes: [ // All detected boxes
|
||||
[/* box 1 */],
|
||||
[/* box 2 */],
|
||||
// ...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Result Properties {#result-properties}
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `codeResult` | Object | Decoded barcode information (may be `undefined` if detection failed) |
|
||||
| `codeResult.code` | String | The decoded barcode value |
|
||||
| `codeResult.format` | String | Barcode format (e.g., "code_128", "ean_13") |
|
||||
| `codeResult.start` | Number | Start position in pattern |
|
||||
| `codeResult.end` | Number | End position in pattern |
|
||||
| `codeResult.direction` | Number | Scan direction (1 or -1) |
|
||||
| `codeResult.supplement` | Object | (Optional) Supplement barcode data for EAN-13/UPC-A with EAN-2 or EAN-5 extensions |
|
||||
| `codeResult.supplement.code` | String | The decoded supplement value (2 or 5 digits) |
|
||||
| `codeResult.supplement.format` | String | Supplement format: "ean_2" or "ean_5" |
|
||||
| `line` | Array | Two points defining the scan line |
|
||||
| `angle` | Number | Barcode rotation angle (radians) |
|
||||
| `pattern` | Array | Binary pattern (0=space, 1=bar) |
|
||||
| `box` | Array | Bounding box coordinates (4 corner points) |
|
||||
| `boxes` | Array | All candidate boxes found during localization. When `locate` is `false`, this contains a single box representing the actual adjusted scanning area (after patch alignment) |
|
||||
|
||||
> **Note: `boxes` with `locate: false`**
|
||||
>
|
||||
> When `locate` is `false` and an `inputStream.area` is configured, `result.boxes` contains a single box representing the actual scanning area dimensions. This box reflects the adjusted dimensions after patch alignment (which can differ slightly from the percentage-based area due to rounding to patch size multiples). Use these coordinates if you need to know the exact scanning rectangle:
|
||||
>
|
||||
> ```javascript
|
||||
> Quagga.onProcessed(function(result) {
|
||||
> if (result.boxes && result.boxes.length > 0) {
|
||||
> // When locate=false, boxes[0] is the actual scanning area
|
||||
> const scanArea = result.boxes[0];
|
||||
> console.log("Scanning area corners:", scanArea);
|
||||
> }
|
||||
> });
|
||||
> ```
|
||||
|
||||
> **Important: Coordinate System**
|
||||
>
|
||||
> The `box`, `boxes`, and `line` coordinates are returned in **processed canvas coordinates**, not original image/video coordinates. If you're using `inputStream.size` to scale the processing resolution (e.g., for performance), you'll need to scale these coordinates to match your original video/image dimensions.
|
||||
>
|
||||
> ```javascript
|
||||
> // Scale coordinates to original video size
|
||||
> const scaleX = video.videoWidth / Quagga.canvas.dom.image.width;
|
||||
> const scaleY = video.videoHeight / Quagga.canvas.dom.image.height;
|
||||
> const scaledBox = result.box.map(p => [p[0] * scaleX, p[1] * scaleY]);
|
||||
> ```
|
||||
>
|
||||
> See [Working with Box Coordinates](../how-to-guides/working-with-coordinates.md) for complete examples.
|
||||
|
||||
### Checking for Successful Detection {#checking-detection}
|
||||
|
||||
```javascript
|
||||
Quagga.onDetected(function(result) {
|
||||
// Always check if codeResult exists
|
||||
if (result && result.codeResult && result.codeResult.code) {
|
||||
console.log("Detected:", result.codeResult.code);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Using Multiple Barcode Detection {#multiple-barcode-detection}
|
||||
|
||||
When `decoder.multiple` is `true`, results are returned as an array:
|
||||
|
||||
```javascript
|
||||
Quagga.init({
|
||||
decoder: {
|
||||
readers: ["code_128_reader"],
|
||||
multiple: true
|
||||
}
|
||||
});
|
||||
|
||||
Quagga.onDetected(function(result) {
|
||||
// result is an array of result objects
|
||||
result.forEach(function(item) {
|
||||
if (item.codeResult) {
|
||||
console.log("Code:", item.codeResult.code);
|
||||
console.log("Box:", item.box);
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Canvas Access {#canvas-access}
|
||||
|
||||
Quagga automatically creates and manages two canvas elements for visualization. These are positioned over the video/image stream and sized to match the processing dimensions.
|
||||
|
||||
### Canvas Structure {#canvas-structure}
|
||||
|
||||
```javascript
|
||||
Quagga.canvas = {
|
||||
dom: {
|
||||
image: HTMLCanvasElement, // Canvas for processed image data
|
||||
overlay: HTMLCanvasElement | null // Transparent canvas for drawing overlays
|
||||
},
|
||||
ctx: {
|
||||
image: CanvasRenderingContext2D, // Context for image canvas
|
||||
overlay: CanvasRenderingContext2D | null // Context for overlay canvas
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
> **Note**: The overlay canvas can be `null` if `canvas.createOverlay` is set to `false` in the configuration. See [Canvas Configuration](configuration.md#canvas-configuration) for details.
|
||||
|
||||
### Overlay Canvas {#overlay-canvas}
|
||||
|
||||
The **overlay canvas** (`Quagga.canvas.dom.overlay`) is a transparent canvas element positioned over the video stream. It's automatically created when Quagga initializes (unless `canvas.createOverlay` is `false`) and is designed for drawing bounding boxes, scan lines, and other visual feedback.
|
||||
|
||||
**Key characteristics:**
|
||||
- Has CSS class `drawingBuffer`
|
||||
- Sized to match the processed image dimensions (`inputStream.size`)
|
||||
- Positioned absolutely over the video/image element
|
||||
- Automatically appended to the viewport container
|
||||
- Coordinates match the processed image space (no scaling needed)
|
||||
- Can be disabled via `canvas.createOverlay: false` for performance
|
||||
|
||||
**Accessing the overlay:**
|
||||
```javascript
|
||||
const overlay = Quagga.canvas.dom.overlay;
|
||||
const overlayCtx = Quagga.canvas.ctx.overlay;
|
||||
|
||||
// Always check if overlay exists before using
|
||||
if (overlayCtx && overlay) {
|
||||
// Clear overlay
|
||||
overlayCtx.clearRect(0, 0, overlay.width, overlay.height);
|
||||
|
||||
// Draw custom shapes
|
||||
overlayCtx.strokeStyle = "red";
|
||||
overlayCtx.lineWidth = 3;
|
||||
overlayCtx.strokeRect(10, 10, 100, 100);
|
||||
}
|
||||
```
|
||||
|
||||
### Image Canvas {#image-canvas}
|
||||
|
||||
The **image canvas** (`Quagga.canvas.dom.image`) contains the processed grayscale image data used for barcode detection. This is primarily for internal use and debugging.
|
||||
|
||||
**Key characteristics:**
|
||||
- Has CSS class `imgBuffer`
|
||||
- Contains the grayscale/processed image data
|
||||
- Useful for debugging locator issues
|
||||
|
||||
### When to Use Each Canvas {#when-to-use-canvas}
|
||||
|
||||
| Use Case | Canvas to Use |
|
||||
|----------|---------------|
|
||||
| Drawing bounding boxes | `overlay` |
|
||||
| Highlighting detected barcodes | `overlay` |
|
||||
| Custom scan line visualization | `overlay` |
|
||||
| Debugging image processing | `image` |
|
||||
| Checking processed resolution | Either (they have same dimensions) |
|
||||
|
||||
### Important: Coordinate System {#canvas-coordinate-system}
|
||||
|
||||
When drawing on the overlay canvas, use `result.box` and `result.boxes` coordinates directly - **no scaling is needed**. These coordinates are already in the overlay canvas's coordinate space.
|
||||
|
||||
```javascript
|
||||
Quagga.onProcessed(function(result) {
|
||||
const ctx = Quagga.canvas.ctx.overlay;
|
||||
const canvas = Quagga.canvas.dom.overlay;
|
||||
|
||||
// Clear previous drawings
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Draw box directly - coordinates already match the overlay canvas
|
||||
if (result && result.box) {
|
||||
Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, ctx, {
|
||||
color: "green", lineWidth: 2
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
> **Note**: Scaling is only needed when drawing on a **different** canvas (like a custom overlay on the original video element). See [Working with Box Coordinates](../how-to-guides/working-with-coordinates.md) for details.
|
||||
|
||||
### CSS Styling {#canvas-css-styling}
|
||||
|
||||
The overlay canvas can be styled with CSS for positioning:
|
||||
|
||||
```css
|
||||
/* Default positioning (handled automatically by Quagga) */
|
||||
canvas.drawingBuffer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* Ensure proper stacking */
|
||||
#scanner-container {
|
||||
position: relative;
|
||||
}
|
||||
```
|
||||
|
||||
## ImageDebug Helper {#imagedebug-helper}
|
||||
|
||||
Quagga provides a helper for drawing debug visualizations:
|
||||
|
||||
```javascript
|
||||
// Draw a path (array of points)
|
||||
Quagga.ImageDebug.drawPath(points, offset, ctx, options);
|
||||
|
||||
// Example
|
||||
Quagga.ImageDebug.drawPath(
|
||||
result.box,
|
||||
{ x: 0, y: 1 },
|
||||
overlayCtx,
|
||||
{ color: "green", lineWidth: 2 }
|
||||
);
|
||||
```
|
||||
|
||||
## Complete Example {#complete-example}
|
||||
|
||||
```javascript
|
||||
// Initialize
|
||||
Quagga.init({
|
||||
inputStream: {
|
||||
type: "LiveStream",
|
||||
target: document.querySelector('#scanner'),
|
||||
constraints: {
|
||||
width: 640,
|
||||
height: 480,
|
||||
facingMode: "environment"
|
||||
}
|
||||
},
|
||||
decoder: {
|
||||
readers: ["code_128_reader", "ean_reader"]
|
||||
}
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start scanning
|
||||
Quagga.start();
|
||||
});
|
||||
|
||||
// Handle detections
|
||||
Quagga.onDetected(function(result) {
|
||||
console.log("Barcode detected:", result.codeResult.code);
|
||||
|
||||
// Stop after first detection
|
||||
Quagga.stop();
|
||||
|
||||
// Cleanup
|
||||
Quagga.offDetected();
|
||||
Quagga.offProcessed();
|
||||
});
|
||||
|
||||
// Visualize processing
|
||||
Quagga.onProcessed(function(result) {
|
||||
const ctx = Quagga.canvas.ctx.overlay;
|
||||
const canvas = Quagga.canvas.dom.overlay;
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
if (result && result.box) {
|
||||
Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, ctx, {
|
||||
color: "green",
|
||||
lineWidth: 2
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Stop button
|
||||
document.querySelector('#stop').addEventListener('click', function() {
|
||||
Quagga.stop();
|
||||
Quagga.offDetected();
|
||||
Quagga.offProcessed();
|
||||
});
|
||||
```
|
||||
|
||||
## Related {#related}
|
||||
|
||||
- [Configuration Reference](configuration.md) - Complete configuration options
|
||||
- [CameraAccess API](camera-access.md) - Camera control methods
|
||||
- [Supported Barcode Types](readers.md) - Available barcode readers
|
||||
- [Getting Started](../getting-started.md) - Basic usage examples
|
||||
|
||||
---
|
||||
|
||||
[← Back to Reference](index.md)
|
||||
109
quagga2/quagga2-1.12.1/docs/reference/browser-support.md
Normal file
109
quagga2/quagga2-1.12.1/docs/reference/browser-support.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Browser Support {#browser-support}
|
||||
|
||||
Quagga2 makes use of many modern Web APIs which are not implemented by all browsers yet. This page details browser compatibility and required APIs.
|
||||
|
||||
## Operating Modes {#operating-modes}
|
||||
|
||||
Quagga2 operates in two modes:
|
||||
|
||||
1. **Analyzing static images** - Process existing image files
|
||||
2. **Using a camera** - Decode images from a live video stream
|
||||
|
||||
The latter requires the MediaDevices API for camera access.
|
||||
|
||||
## Browser Compatibility {#browser-compatibility}
|
||||
|
||||
You can track the compatibility of the used Web APIs for each mode:
|
||||
|
||||
- [Static Images](http://caniuse.com/#feat=canvas,typedarrays,bloburls,blobbuilder)
|
||||
- [Live Stream](http://caniuse.com/#feat=canvas,typedarrays,bloburls,blobbuilder,stream)
|
||||
|
||||
### Static Image Mode {#static-image-mode}
|
||||
|
||||
The following APIs must be supported by your browser:
|
||||
|
||||
- [Canvas](http://caniuse.com/#feat=canvas)
|
||||
- [Typed Arrays](http://caniuse.com/#feat=typedarrays)
|
||||
- [Blob URLs](http://caniuse.com/#feat=bloburls)
|
||||
- [Blob Builder](http://caniuse.com/#feat=blobbuilder)
|
||||
|
||||
### Live Stream Mode {#live-stream-mode}
|
||||
|
||||
In addition to the APIs required for static images:
|
||||
|
||||
- [MediaDevices API](http://caniuse.com/#feat=stream) - Required for camera access
|
||||
|
||||
## Secure Origins Required {#secure-origins}
|
||||
|
||||
**Important**: Accessing `getUserMedia` requires a secure origin in most browsers:
|
||||
|
||||
- `http://` can **only** be used on `localhost`
|
||||
- All other hostnames **must** be served via `https://`
|
||||
|
||||
This is a browser security requirement. Read more in the [Chrome M47 WebRTC Release Notes](https://groups.google.com/forum/#!topic/discuss-webrtc/sq5CVmY69sc).
|
||||
|
||||
## Feature Detection {#feature-detection}
|
||||
|
||||
### Detecting getUserMedia Support {#detecting-getusermedia}
|
||||
|
||||
Every browser implements the `mediaDevices.getUserMedia` API differently. It's highly recommended to include [webrtc-adapter](https://github.com/webrtc/adapter) in your project for cross-browser compatibility.
|
||||
|
||||
**How to test browser capabilities:**
|
||||
|
||||
```javascript
|
||||
if (navigator.mediaDevices && typeof navigator.mediaDevices.getUserMedia === 'function') {
|
||||
// Safe to use getUserMedia
|
||||
console.log('Camera access is supported');
|
||||
} else {
|
||||
// Camera access not available
|
||||
console.log('Camera access is NOT supported');
|
||||
}
|
||||
```
|
||||
|
||||
### Browser Support Table {#browser-support-table}
|
||||
|
||||
The above condition evaluates as follows:
|
||||
|
||||
| Browser | Result | Notes |
|
||||
|---------------|---------|-------|
|
||||
| Chrome | `true` | Full support |
|
||||
| Firefox | `true` | Full support |
|
||||
| Edge | `true` | Full support |
|
||||
| Safari iOS | `true` | Requires HTTPS |
|
||||
| IE 11 | `false` | Not supported |
|
||||
| Safari Desktop| `true` | macOS 11+ |
|
||||
|
||||
## Known Issues {#known-issues}
|
||||
|
||||
### iOS Torch/Flash {#ios-torch-flash}
|
||||
|
||||
Torch (flash) control via `CameraAccess.enableTorch()` and `CameraAccess.disableTorch()` does **not work** on iOS devices running version 16.4 and earlier. Support on later versions may vary.
|
||||
|
||||
### Safari Limitations {#safari-limitations}
|
||||
|
||||
- Older Safari versions may require user interaction before camera access
|
||||
- Some older iOS versions have limited WebRTC support
|
||||
|
||||
### Internet Explorer {#internet-explorer}
|
||||
|
||||
Internet Explorer 11 and below do not support the MediaDevices API and cannot use live camera features. Static image decoding may work with polyfills, but this is not officially supported.
|
||||
|
||||
## Recommendations {#recommendations}
|
||||
|
||||
For best compatibility:
|
||||
|
||||
1. **Use HTTPS** - Required for camera access on all non-localhost domains
|
||||
2. **Include webrtc-adapter** - Normalizes browser differences
|
||||
3. **Feature detect** - Check for API support before attempting to use camera
|
||||
4. **Provide fallbacks** - Offer file upload as alternative to camera access
|
||||
5. **Test thoroughly** - Browser behavior varies, especially on mobile
|
||||
|
||||
## Related {#related}
|
||||
|
||||
- [Configuration Reference](configuration.md) - How to configure Quagga2
|
||||
- [Camera Access API](camera-access.md) - Camera control methods
|
||||
- [Getting Started](../getting-started.md) - Installation and setup
|
||||
|
||||
---
|
||||
|
||||
[← Back to Reference](index.md)
|
||||
376
quagga2/quagga2-1.12.1/docs/reference/camera-access.md
Normal file
376
quagga2/quagga2-1.12.1/docs/reference/camera-access.md
Normal file
@@ -0,0 +1,376 @@
|
||||
# CameraAccess API {#cameraaccess-api}
|
||||
|
||||
Quagga2 exposes a `CameraAccess` API for direct control of camera functionality. This API provides shortcuts for commonly used camera operations.
|
||||
|
||||
**Access**: `Quagga.CameraAccess`
|
||||
|
||||
## Overview {#overview}
|
||||
|
||||
The CameraAccess API allows you to:
|
||||
|
||||
- Request and release camera access
|
||||
- Enumerate available video devices
|
||||
- Control camera torch (flash)
|
||||
- Get information about active video streams and tracks
|
||||
|
||||
All methods return Promises for async operation handling.
|
||||
|
||||
## Methods {#methods}
|
||||
|
||||
### `CameraAccess.request(videoElement, constraints)` {#cameraaccess-request}
|
||||
|
||||
Initializes the camera and starts playback.
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `videoElement` (HTMLVideoElement | null) - Video element to display camera stream. If `null`, camera initializes but remains invisible.
|
||||
- `constraints` (MediaTrackConstraints, optional) - Camera selection and configuration constraints.
|
||||
|
||||
**Returns**: `Promise<void>` - Resolves when camera is ready, rejects on error.
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
const video = document.querySelector('#camera-video');
|
||||
|
||||
// Request camera with default constraints
|
||||
await Quagga.CameraAccess.request(video);
|
||||
|
||||
// Request specific camera
|
||||
await Quagga.CameraAccess.request(video, {
|
||||
facingMode: 'environment', // Back camera on mobile
|
||||
width: { ideal: 1280 },
|
||||
height: { ideal: 720 }
|
||||
});
|
||||
|
||||
// Request camera by device ID
|
||||
const deviceId = 'abc123...';
|
||||
await Quagga.CameraAccess.request(video, { deviceId });
|
||||
|
||||
// Initialize camera without displaying (for probing)
|
||||
await Quagga.CameraAccess.request(null);
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
|
||||
- Start camera before Quagga initialization
|
||||
- Probe camera availability and permissions
|
||||
- Initialize camera without displaying video
|
||||
|
||||
### `CameraAccess.release()` {#cameraaccess-release}
|
||||
|
||||
Stops the video stream and releases all camera resources.
|
||||
|
||||
**Returns**: `Promise<void>` - Resolves when all tracks are stopped and resources released.
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
// Stop camera
|
||||
await Quagga.CameraAccess.release();
|
||||
console.log('Camera released');
|
||||
```
|
||||
|
||||
**Behavior**:
|
||||
|
||||
1. Pauses the video element
|
||||
2. Stops all tracks in the media stream
|
||||
3. Releases camera for use by other applications
|
||||
|
||||
**Note**: Always call `release()` when finished with the camera to free system resources.
|
||||
|
||||
### `CameraAccess.enumerateVideoDevices(constraints?)` {#cameraaccess-enumeratevideodevices}
|
||||
|
||||
Lists all available video input devices (cameras), optionally filtered by constraints.
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `constraints` (MediaTrackConstraints, optional) - Constraints to filter devices. When provided, only devices that can satisfy the given constraints will be returned.
|
||||
|
||||
**Returns**: `Promise<MediaDeviceInfo[]>` - Array of video device information.
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
// Get all video devices
|
||||
const devices = await Quagga.CameraAccess.enumerateVideoDevices();
|
||||
|
||||
devices.forEach(device => {
|
||||
console.log('Device:', device.label);
|
||||
console.log('Device ID:', device.deviceId);
|
||||
console.log('Group ID:', device.groupId);
|
||||
});
|
||||
|
||||
// Example output:
|
||||
// Device: Front Camera
|
||||
// Device ID: abc123...
|
||||
// Device: Back Camera
|
||||
// Device ID: def456...
|
||||
```
|
||||
|
||||
**Filtering devices with constraints**:
|
||||
|
||||
```javascript
|
||||
// Get only devices that support a minimum resolution
|
||||
const hdDevices = await Quagga.CameraAccess.enumerateVideoDevices({
|
||||
width: { min: 1280 },
|
||||
height: { min: 720 }
|
||||
});
|
||||
|
||||
// Get only back-facing cameras
|
||||
const backCameras = await Quagga.CameraAccess.enumerateVideoDevices({
|
||||
facingMode: 'environment'
|
||||
});
|
||||
|
||||
// Eliminate wide-angle only cameras by specifying aspect ratio
|
||||
const standardCameras = await Quagga.CameraAccess.enumerateVideoDevices({
|
||||
aspectRatio: { ideal: 1.777 } // 16:9
|
||||
});
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
|
||||
- Build camera selector UI
|
||||
- Detect available cameras before initialization
|
||||
- Check for front/back camera availability on mobile
|
||||
- Filter out cameras that don't meet quality requirements
|
||||
- Eliminate wide-angle cameras that may not be suitable for barcode scanning
|
||||
|
||||
**Note**: Device labels may be empty strings until camera permission is granted. When using constraints, the method will request temporary access to each device to test if it satisfies the constraints.
|
||||
|
||||
### `CameraAccess.getActiveStreamLabel()` {#cameraaccess-getactivestreamlabel}
|
||||
|
||||
Gets the label of the currently active video track.
|
||||
|
||||
**Returns**: `string` - Label of active video track (e.g., "Back Camera", "USB Camera").
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
const label = Quagga.CameraAccess.getActiveStreamLabel();
|
||||
console.log('Using camera:', label);
|
||||
// Output: "Using camera: Back Camera"
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
|
||||
- Display which camera is currently active
|
||||
- Verify correct camera is being used
|
||||
- Logging and debugging
|
||||
|
||||
### `CameraAccess.getActiveStream()` {#cameraaccess-getactivestream}
|
||||
|
||||
Gets the complete MediaStream object for the currently active video.
|
||||
|
||||
**Returns**: `MediaStream | null` - The active MediaStream object, or `null` if no camera is active.
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
const stream = Quagga.CameraAccess.getActiveStream();
|
||||
|
||||
if (stream) {
|
||||
console.log('Stream ID:', stream.id);
|
||||
console.log('Stream active:', stream.active);
|
||||
console.log('Video tracks:', stream.getVideoTracks().length);
|
||||
console.log('Audio tracks:', stream.getAudioTracks().length);
|
||||
|
||||
// Clone the stream
|
||||
const clonedStream = stream.clone();
|
||||
}
|
||||
|
||||
// Pass stream to WebRTC peer connection
|
||||
if (stream?.active) {
|
||||
peerConnection.addStream(stream);
|
||||
}
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
|
||||
- Pass the stream to WebRTC peer connections
|
||||
- Clone the stream for multiple consumers
|
||||
- Check if the stream is still active via `stream.active`
|
||||
- Access the stream ID
|
||||
- Work with all tracks (video and audio) in the stream
|
||||
|
||||
**Note**: For accessing just the video track, use `getActiveTrack()` instead.
|
||||
|
||||
### `CameraAccess.getActiveTrack()` {#cameraaccess-getactivetrack}
|
||||
|
||||
Gets the MediaStreamTrack for the currently active video.
|
||||
|
||||
**Returns**: `MediaStreamTrack | null` - Active video track object, or `null` if no camera is active.
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
const track = Quagga.CameraAccess.getActiveTrack();
|
||||
|
||||
console.log('Track state:', track.readyState);
|
||||
console.log('Track settings:', track.getSettings());
|
||||
console.log('Track capabilities:', track.getCapabilities());
|
||||
|
||||
// Get current resolution
|
||||
const settings = track.getSettings();
|
||||
console.log(`Resolution: ${settings.width}x${settings.height}`);
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
|
||||
- Access advanced track capabilities
|
||||
- Monitor track state
|
||||
- Apply additional constraints
|
||||
- Access camera capabilities (zoom, focus, etc.)
|
||||
|
||||
### `CameraAccess.enableTorch()` {#cameraaccess-enabletorch}
|
||||
|
||||
Turns on the camera torch (flash).
|
||||
|
||||
**Returns**: `Promise<void>` - Resolves when torch is enabled, rejects on error.
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
try {
|
||||
await Quagga.CameraAccess.enableTorch();
|
||||
console.log('Torch enabled');
|
||||
} catch (error) {
|
||||
console.error('Failed to enable torch:', error);
|
||||
}
|
||||
```
|
||||
|
||||
**Browser Support**:
|
||||
|
||||
- ✅ Chrome (Android)
|
||||
- ✅ Chrome (Desktop with supported cameras)
|
||||
- ❌ Safari iOS 16.4 and earlier
|
||||
- ⚠️ Safari iOS later versions - may or may not work
|
||||
|
||||
**Requirements**:
|
||||
|
||||
- Camera must support torch capability
|
||||
- Camera must be actively streaming
|
||||
- Browser must support torch constraint
|
||||
|
||||
**Note**: Always wrap in try-catch as not all devices support torch.
|
||||
|
||||
### `CameraAccess.disableTorch()` {#cameraaccess-disabletorch}
|
||||
|
||||
Turns off the camera torch (flash).
|
||||
|
||||
**Returns**: `Promise<void>` - Resolves when torch is disabled, rejects on error.
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
try {
|
||||
await Quagga.CameraAccess.disableTorch();
|
||||
console.log('Torch disabled');
|
||||
} catch (error) {
|
||||
console.error('Failed to disable torch:', error);
|
||||
}
|
||||
```
|
||||
|
||||
**Browser Support**: Same as `enableTorch()`.
|
||||
|
||||
## Complete Example {#complete-example}
|
||||
|
||||
```javascript
|
||||
// Enumerate cameras and let user choose
|
||||
const devices = await Quagga.CameraAccess.enumerateVideoDevices();
|
||||
const backCamera = devices.find(d => d.label.includes('back'));
|
||||
|
||||
// Initialize camera
|
||||
const video = document.querySelector('#video');
|
||||
await Quagga.CameraAccess.request(video, {
|
||||
deviceId: backCamera.deviceId
|
||||
});
|
||||
|
||||
console.log('Active camera:', Quagga.CameraAccess.getActiveStreamLabel());
|
||||
|
||||
// Enable torch for better scanning in dark environments
|
||||
try {
|
||||
await Quagga.CameraAccess.enableTorch();
|
||||
} catch (error) {
|
||||
console.log('Torch not available');
|
||||
}
|
||||
|
||||
// ... use camera for scanning ...
|
||||
|
||||
// Cleanup
|
||||
await Quagga.CameraAccess.disableTorch();
|
||||
await Quagga.CameraAccess.release();
|
||||
```
|
||||
|
||||
## Torch Control in Live Scanning {#torch-control}
|
||||
|
||||
For torch control during live scanning, you may want to provide a toggle button:
|
||||
|
||||
```javascript
|
||||
let torchEnabled = false;
|
||||
|
||||
document.querySelector('#torch-toggle').addEventListener('click', async () => {
|
||||
try {
|
||||
if (torchEnabled) {
|
||||
await Quagga.CameraAccess.disableTorch();
|
||||
torchEnabled = false;
|
||||
} else {
|
||||
await Quagga.CameraAccess.enableTorch();
|
||||
torchEnabled = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Torch control failed:', error);
|
||||
alert('Torch not available on this device');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Advanced Camera Control {#advanced-camera-control}
|
||||
|
||||
For advanced camera control (zoom, focus, etc.), use the MediaStreamTrack API:
|
||||
|
||||
```javascript
|
||||
const track = Quagga.CameraAccess.getActiveTrack();
|
||||
const capabilities = track.getCapabilities();
|
||||
|
||||
// Check if zoom is supported
|
||||
if (capabilities.zoom) {
|
||||
console.log('Zoom range:', capabilities.zoom.min, '-', capabilities.zoom.max);
|
||||
|
||||
// Apply zoom
|
||||
await track.applyConstraints({
|
||||
advanced: [{ zoom: 2.0 }]
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Read more: [MediaStreamTrack Capabilities](https://www.oberhofer.co/mediastreamtrack-and-its-capabilities)
|
||||
|
||||
## Error Handling {#error-handling}
|
||||
|
||||
Always handle errors when using CameraAccess methods:
|
||||
|
||||
```javascript
|
||||
try {
|
||||
await Quagga.CameraAccess.request(video);
|
||||
} catch (error) {
|
||||
if (error.name === 'NotAllowedError') {
|
||||
console.error('Camera permission denied');
|
||||
} else if (error.name === 'NotFoundError') {
|
||||
console.error('No camera found');
|
||||
} else {
|
||||
console.error('Camera error:', error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Related {#related}
|
||||
|
||||
- [Browser Support](browser-support.md) - Camera compatibility information
|
||||
- [Configuration Reference](configuration.md) - Camera configuration in Quagga.init()
|
||||
- [API Documentation](api.md) - Main Quagga API methods
|
||||
- [Tips & Tricks](../how-to-guides/tips-and-tricks.md) - Camera optimization tips
|
||||
|
||||
---
|
||||
|
||||
[← Back to Reference](index.md)
|
||||
1009
quagga2/quagga2-1.12.1/docs/reference/configuration.md
Normal file
1009
quagga2/quagga2-1.12.1/docs/reference/configuration.md
Normal file
File diff suppressed because it is too large
Load Diff
295
quagga2/quagga2-1.12.1/docs/reference/dependencies.md
Normal file
295
quagga2/quagga2-1.12.1/docs/reference/dependencies.md
Normal file
@@ -0,0 +1,295 @@
|
||||
# Quagga2 Dependencies
|
||||
|
||||
This document explains the dependency structure of Quagga2 and clarifies which packages are runtime code dependencies versus build/test tools.
|
||||
|
||||
## Background
|
||||
|
||||
Quagga2 bundles all its code with Webpack, producing standalone browser and Node.js builds. As a result, **all packages are listed as `devDependencies`** in `package.json` because consumers never directly install them - they only use the pre-built bundles in `dist/` and `lib/`.
|
||||
|
||||
However, this makes it unclear which packages are actual code dependencies (bundled into the final output) versus which are just build/test tools. This document clarifies that distinction.
|
||||
|
||||
---
|
||||
|
||||
## Runtime Code Dependencies
|
||||
|
||||
These packages contain code that is **imported by the source code** and **bundled into the final output**:
|
||||
|
||||
### Core Libraries
|
||||
|
||||
- **`gl-matrix`** (^3.4.4)
|
||||
- **Purpose**: High-performance vector and matrix math operations
|
||||
- **Usage**: Used throughout the codebase for geometric calculations
|
||||
- **Files**:
|
||||
- `src/quagga/quagga.ts` - vec2 operations for bounding boxes
|
||||
- `src/quagga/initBuffers.ts` - vec2 for buffer initialization
|
||||
- `src/locator/barcode_locator.js` - vec2, mat2 for barcode location
|
||||
- `src/common/image_wrapper.ts` - vec2 for image transforms
|
||||
- `src/common/cvutils/ImageRef.ts` - vec2, vec3 for computer vision
|
||||
- `src/common/cluster.js` - vec2 for clustering algorithms
|
||||
|
||||
- **`lodash`** (^4.17.21)
|
||||
- **Purpose**: Utility functions for object manipulation
|
||||
- **Usage**: Primarily `merge()` for config merging, `pick()` for object selection
|
||||
- **Files**:
|
||||
- `src/quagga.js` - merge() for configuration
|
||||
- `src/QuaggaStatic.ts` - merge() for configuration
|
||||
- `src/reader/ean_reader.ts` - merge() for config defaults
|
||||
- `src/reader/i2of5_reader.ts` - merge() for config defaults
|
||||
- `src/input/camera_access.ts` - pick() for MediaTrackConstraints
|
||||
- `src/locator/test/barcode_locator.spec.ts` - merge() in tests
|
||||
|
||||
### Image Processing
|
||||
|
||||
- **`ndarray`** (^1.0.19)
|
||||
- **Purpose**: N-dimensional array manipulation
|
||||
- **Usage**: Core data structure for image data processing
|
||||
- **Files**:
|
||||
- `src/input/input_stream/input_stream_base.ts` - NdArray type definitions
|
||||
- `src/input/input_stream/input_stream.ts` - NdArray for frame data
|
||||
- `src/input/frame_grabber.ts` - Ndarray for frame manipulation
|
||||
- `src/vendor.d.ts` - Type definitions
|
||||
|
||||
- **`ndarray-linear-interpolate`** (^1.0.0)
|
||||
- **Purpose**: Bilinear interpolation for ndarray data
|
||||
- **Usage**: Image scaling and transformations
|
||||
- **Files**:
|
||||
- `src/input/frame_grabber.ts` - `d2()` method for 2D interpolation
|
||||
|
||||
- **`ndarray-pixels`** (^5.0.1)
|
||||
- **Purpose**: Convert between image formats and ndarray
|
||||
- **Usage**: Loading image data from various sources
|
||||
- **Files**:
|
||||
- `src/input/input_stream/input_stream.ts` - `getPixels()` for image loading
|
||||
|
||||
### Polyfills (Deprecated)
|
||||
|
||||
- **`@babel/polyfill`** (^7.12.1)
|
||||
- **Status**: ⚠️ **DEPRECATED** by Babel team
|
||||
- **Purpose**: Legacy polyfill for ES6+ features
|
||||
- **Current Usage**: Not directly imported in source code
|
||||
- **Recommendation**: Should be removed in favor of `core-js` + `regenerator-runtime` or Babel's automatic polyfill injection
|
||||
- **Migration Path**: Use `@babel/preset-env` with `useBuiltIns: 'usage'` and explicit `core-js@3`
|
||||
|
||||
---
|
||||
|
||||
## Build & Development Tools
|
||||
|
||||
These packages are **only used during build/development** and are **not bundled into the final output**:
|
||||
|
||||
### TypeScript Toolchain
|
||||
|
||||
- **`typescript`** (^5.9.3) - TypeScript compiler
|
||||
- **`@types/*`** packages - Type definitions for TypeScript
|
||||
- `@types/chai`, `@types/gl-vec2`, `@types/lodash`, `@types/mocha`, `@types/node`, `@types/sinon`, `@types/sinon-chai`
|
||||
|
||||
### Webpack & Bundling
|
||||
|
||||
- **`webpack`** (^4.44.2) - Module bundler (used to create `dist/` and `lib/` outputs)
|
||||
- **`webpack-cli`** (^3.3.12) - Webpack command-line interface
|
||||
- **`babel-loader`** (^8.2.5) - Webpack loader for Babel transpilation
|
||||
- **`source-map-loader`** (^1.1.1) - Webpack loader for source maps
|
||||
|
||||
### Babel Transpilation
|
||||
|
||||
- **`@babel/core`** (^7.28.5) - Babel compiler core
|
||||
- **`@babel/preset-env`** (^7.28.5) - Smart transpilation based on target environments
|
||||
- **`@babel/preset-typescript`** (^7.28.5) - TypeScript support in Babel
|
||||
- **`@babel/plugin-*`** - Various syntax plugins:
|
||||
- `@babel/plugin-proposal-class-properties`
|
||||
- `@babel/plugin-proposal-nullish-coalescing-operator`
|
||||
- `@babel/plugin-proposal-object-rest-spread`
|
||||
- `@babel/plugin-proposal-optional-chaining`
|
||||
- `@babel/plugin-transform-runtime`
|
||||
- **`@babel/runtime`** (^7.28.4) - Babel runtime helpers
|
||||
- **`babel-plugin-add-module-exports`** (^1.0.4) - CommonJS module.exports handling
|
||||
- **`babel-plugin-istanbul`** (^7.0.1) - Code coverage instrumentation
|
||||
|
||||
### Testing
|
||||
|
||||
- **`mocha`** (^5.2.0) - Test framework
|
||||
- **`chai`** (^4.3.10) - Assertion library
|
||||
- **`sinon`** (^21.0.0) - Test spies, stubs, and mocks
|
||||
- **`sinon-chai`** (^3.7.0) - Sinon assertions for Chai
|
||||
- **`ts-mocha`** (^11.1.0) - TypeScript support for Mocha
|
||||
- **`ts-node`** (^10.9.2) - TypeScript execution for Node.js
|
||||
- **`cypress`** (^13.1.0) - End-to-end browser testing
|
||||
- **`@cypress/webpack-preprocessor`** (6.0.0) - Webpack integration for Cypress
|
||||
- **`@cypress/code-coverage`** (^3.12.4) - Code coverage for Cypress tests
|
||||
- **`nyc`** (^17.1.0) - Code coverage tool (Istanbul wrapper)
|
||||
|
||||
### Linting & Code Quality
|
||||
|
||||
- **`eslint`** (^8.57.1) - JavaScript/TypeScript linter
|
||||
- **`@typescript-eslint/eslint-plugin`** (^7.18.0) - TypeScript-specific ESLint rules
|
||||
- **`@typescript-eslint/parser`** (^7.18.0) - TypeScript parser for ESLint
|
||||
- **`eslint-config-airbnb-base`** (^15.0.0) - Airbnb JavaScript style guide
|
||||
- **`eslint-config-airbnb-typescript`** (^18.0.0) - Airbnb style for TypeScript
|
||||
- **`eslint-config-airbnb-typescript-base`** (^6.0.1) - Base Airbnb TypeScript config
|
||||
- **`eslint-plugin-import`** (^2.32.0) - Import/export validation
|
||||
- **`eslint-plugin-jsx-a11y`** (^6.10.2) - Accessibility linting
|
||||
- **`eslint-plugin-typescript-sort-keys`** (^3.3.0) - Enforce sorted object keys
|
||||
|
||||
### Utilities
|
||||
|
||||
- **`core-js`** (^3.46.0) - Modern JavaScript polyfills (used by Babel)
|
||||
- **`cross-env`** (^10.1.0) - Cross-platform environment variable setting
|
||||
|
||||
---
|
||||
|
||||
## Optional Dependencies
|
||||
|
||||
- **`fsevents`** (2.3.3)
|
||||
- **Platform**: macOS only
|
||||
- **Purpose**: Native file watching for better performance
|
||||
- **Usage**: Automatically used by Webpack/build tools on macOS
|
||||
|
||||
---
|
||||
|
||||
## Overrides
|
||||
|
||||
The `overrides` field forces specific versions of transitive dependencies:
|
||||
|
||||
```json
|
||||
"overrides": {
|
||||
"@cypress/request": "^3.0.9"
|
||||
}
|
||||
```
|
||||
|
||||
- **Purpose**: Security fix for `form-data` vulnerability (CVE in versions < 2.5.4)
|
||||
- **Details**: Cypress 13.1.0 bundles `@cypress/request@3.0.0` which depends on vulnerable `form-data@2.3.3`. This override forces `@cypress/request@^3.0.9` which uses safe `form-data@~4.0.4`.
|
||||
|
||||
---
|
||||
|
||||
## Bundle Size Impact
|
||||
|
||||
When evaluating dependencies, consider their impact on bundle size:
|
||||
|
||||
| Package | Approximate Size | Bundled? |
|
||||
|---------|-----------------|----------|
|
||||
| `gl-matrix` | ~50 KB (minified) | ✅ Yes |
|
||||
| `lodash` | ~4 KB (only `merge` + `pick`) | ✅ Yes (tree-shaken) |
|
||||
| `ndarray` | ~5 KB | ✅ Yes |
|
||||
| `ndarray-linear-interpolate` | ~2 KB | ✅ Yes |
|
||||
| `ndarray-pixels` | ~10 KB | ✅ Yes (browser) |
|
||||
| `webpack` | ~1.5 MB | ❌ No (dev only) |
|
||||
| `typescript` | ~50 MB | ❌ No (dev only) |
|
||||
|
||||
---
|
||||
|
||||
## Adding New Dependencies
|
||||
|
||||
When adding a new dependency, consider:
|
||||
|
||||
1. **Is it a runtime dependency?**
|
||||
- Will the code be `import`ed in `src/` files?
|
||||
- Will it be bundled into `dist/` or `lib/` output?
|
||||
- → Add to `devDependencies` (all deps go here due to bundling)
|
||||
- → Document it in the "Runtime Code Dependencies" section above
|
||||
|
||||
2. **Is it a build/test tool?**
|
||||
- Is it only used by Webpack, Babel, ESLint, Mocha, etc.?
|
||||
- → Add to `devDependencies`
|
||||
- → Document it in the "Build & Development Tools" section above
|
||||
|
||||
3. **Bundle size impact?**
|
||||
- Run `npm run build` and check the size change in `dist/quagga.min.js`
|
||||
- Consider tree-shaking (does the library support ES modules?)
|
||||
- Look for lighter alternatives if the package is large
|
||||
|
||||
4. **Browser compatibility?**
|
||||
- Does the package work in browsers?
|
||||
- Does it require Node.js-specific APIs (`fs`, `path`, etc.)?
|
||||
- → Check if it's already shimmed in `configs/webpack.config.js` (e.g., `node: { fs: 'empty' }`)
|
||||
|
||||
---
|
||||
|
||||
## Version Constraints
|
||||
|
||||
### Pinned Versions
|
||||
|
||||
Some packages are pinned to specific versions due to compatibility issues:
|
||||
|
||||
- **`mocha@^5.2.0`** - Pinned to v5 because newer versions have breaking changes
|
||||
- **`chai@^4.3.10`** - Pinned to v4 because v5+ and v6+ are ESM-only, incompatible with CommonJS tests
|
||||
- **`sinon-chai@^3.7.0`** - Pinned to match `chai@4.x` compatibility
|
||||
- **`webpack@^4.44.2`** - Pinned to v4 because v5 requires significant config migration
|
||||
- **`cypress@^13.1.0`** - Pinned to v13 for stability
|
||||
|
||||
These are configured in `.ncurc.json` to prevent accidental upgrades via `npm-check-updates`.
|
||||
|
||||
### Upgrade Policy
|
||||
|
||||
- **TypeScript ecosystem** (`typescript`, `@typescript-eslint/*`, `ts-*`): Keep up-to-date
|
||||
- **Babel ecosystem** (`@babel/*`): Keep up-to-date for security and features
|
||||
- **Testing tools** (`mocha`, `chai`, `sinon`): Upgrade cautiously, test thoroughly
|
||||
- **Webpack & bundlers**: Major version upgrades require careful migration planning
|
||||
- **Runtime dependencies** (`gl-matrix`, `lodash`, `ndarray*`): Keep up-to-date unless breaking changes occur
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Known Issues
|
||||
|
||||
1. **`@babel/polyfill` is deprecated** - Should migrate to `core-js@3` + `regenerator-runtime`
|
||||
2. **Old `mocha` version** - v5.2.0 is from 2018, may have unpatched vulnerabilities
|
||||
3. **Webpack 4** - No longer receives updates, consider upgrading to Webpack 5
|
||||
|
||||
### Monitoring
|
||||
|
||||
- Run `npm audit` regularly to check for vulnerabilities
|
||||
- Use `npm run check-updates` to see available updates
|
||||
- Check GitHub Dependabot alerts
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Why are runtime dependencies in `devDependencies` instead of `dependencies`?**
|
||||
|
||||
A: Quagga2 is a **bundled library**. Consumers install the package and use the pre-built files (`dist/quagga.min.js` or `lib/quagga.js`), not the source code. They never run `npm install` on Quagga2's dependencies. Therefore, from npm's perspective, all packages are development dependencies (used during build), not runtime dependencies (used after install).
|
||||
|
||||
**Q: How can I tell if a package is actually used in the code?**
|
||||
|
||||
A: Search the `src/` directory:
|
||||
```bash
|
||||
# Search for imports
|
||||
grep -r "from 'package-name'" src/
|
||||
grep -r 'from "package-name"' src/
|
||||
grep -r "require('package-name')" src/
|
||||
```
|
||||
|
||||
**Q: What's the difference between `optionalDependencies` and `devDependencies`?**
|
||||
|
||||
A: `optionalDependencies` are packages that enhance functionality if available but aren't required (like `fsevents` for macOS file watching). `devDependencies` are required for development but not for using the published package.
|
||||
|
||||
**Q: Can I remove `@babel/polyfill`?**
|
||||
|
||||
A: Yes, but carefully. It's deprecated and not directly imported anymore. Remove it from `package.json` and verify that `@babel/preset-env` is configured to polyfill features automatically via `core-js@3`. Test thoroughly in older browsers (IE11, older Safari) after removal.
|
||||
|
||||
**Q: Why can't I upgrade `chai` to version 5 or 6?**
|
||||
|
||||
A: `chai@5+` and `chai@6+` are ESM-only (ES modules). Quagga2's tests use CommonJS (`require()`), and `mocha@5` doesn't support ESM. Upgrading `chai` requires also upgrading `mocha` to v9.1.0+ and migrating all test files to ESM syntax.
|
||||
|
||||
---
|
||||
|
||||
## Related Files
|
||||
|
||||
- **`package.json`** - Dependency declarations
|
||||
- **`.ncurc.json`** - npm-check-updates configuration (blocks unsafe auto-upgrades)
|
||||
- **`configs/webpack.config.js`** - Build configuration showing which dependencies are bundled
|
||||
- **`configs/webpack.node.config.js`** - Node.js-specific build configuration
|
||||
- **`CHANGELOG.md`** - Version history and dependency changes
|
||||
|
||||
---
|
||||
|
||||
## Maintenance Notes
|
||||
|
||||
This document was created in November 2025 following the TypeScript 5.9.3 upgrade. It should be updated whenever:
|
||||
|
||||
- A new dependency is added or removed
|
||||
- A major version upgrade changes behavior
|
||||
- Security vulnerabilities are discovered and patched
|
||||
- Build tooling changes significantly
|
||||
|
||||
Last updated: 2025-11-16
|
||||
74
quagga2/quagga2-1.12.1/docs/reference/index.md
Normal file
74
quagga2/quagga2-1.12.1/docs/reference/index.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Reference Documentation
|
||||
|
||||
Precise technical descriptions of Quagga2's API, configuration, and capabilities. Consult these when you need exact details about how something works.
|
||||
|
||||
## Core API
|
||||
|
||||
### [API Documentation](api.md)
|
||||
|
||||
Complete reference for all Quagga2 methods, callbacks, and events.
|
||||
|
||||
### [Configuration Options](configuration.md)
|
||||
|
||||
Detailed documentation of every configuration parameter and its effects.
|
||||
|
||||
### [Camera Access API](camera-access.md)
|
||||
|
||||
Methods for controlling camera access, torch/flash, and device enumeration.
|
||||
|
||||
## Barcode Support
|
||||
|
||||
### [Supported Barcode Types](readers.md)
|
||||
|
||||
List of all supported barcode formats with characteristics and use cases.
|
||||
|
||||
## Compatibility
|
||||
|
||||
### [Browser Support](browser-support.md)
|
||||
|
||||
Browser compatibility matrix and required Web APIs.
|
||||
|
||||
## Development
|
||||
|
||||
### [Dependencies](dependencies.md)
|
||||
|
||||
Explanation of all package dependencies - which are bundled vs. dev-only.
|
||||
|
||||
## Quick Lookup
|
||||
|
||||
| Need | See |
|
||||
|------|-----|
|
||||
| Method signatures | [API Documentation](api.md) |
|
||||
| Config parameter details | [Configuration Options](configuration.md) |
|
||||
| Which browsers work | [Browser Support](browser-support.md) |
|
||||
| Which barcodes supported | [Supported Barcode Types](readers.md) |
|
||||
| Camera control | [Camera Access API](camera-access.md) |
|
||||
| Package versions | [Dependencies](dependencies.md) |
|
||||
|
||||
## Reading Reference Docs
|
||||
|
||||
Reference documentation is:
|
||||
|
||||
- **Information-oriented** - Focuses on describing *what exists*
|
||||
- **Accurate** - Every detail matters, kept up-to-date with code
|
||||
- **Complete** - Covers all features, even obscure ones
|
||||
- **Structured** - Organized for lookup, not linear reading
|
||||
|
||||
Don't read reference docs cover-to-cover. Instead:
|
||||
|
||||
1. **Look up** what you need when you need it
|
||||
2. **Verify** assumptions about how things work
|
||||
3. **Discover** features you didn't know existed
|
||||
4. **Confirm** exact method signatures or parameter types
|
||||
|
||||
## Need Context?
|
||||
|
||||
Reference docs tell you *what* and *how*, but not *why*:
|
||||
|
||||
- For **why** something works a certain way → See [Explanation](../explanation/)
|
||||
- For **how to use** something in practice → See [How-To Guides](../how-to-guides/)
|
||||
- For **learning** from scratch → See [Tutorials](../tutorials/)
|
||||
|
||||
---
|
||||
|
||||
[← Back to Documentation Home](../index.md)
|
||||
326
quagga2/quagga2-1.12.1/docs/reference/readers.md
Normal file
326
quagga2/quagga2-1.12.1/docs/reference/readers.md
Normal file
@@ -0,0 +1,326 @@
|
||||
# Supported Barcode Types {#supported-barcode-types}
|
||||
|
||||
Quagga2 supports a wide variety of 1D barcode formats. This page lists all available barcode readers and how to configure them.
|
||||
|
||||
## Available Readers {#available-readers}
|
||||
|
||||
Quagga2 includes built-in readers for the following barcode formats:
|
||||
|
||||
| Reader Name | Barcode Format | Common Uses |
|
||||
|-------------|----------------|-------------|
|
||||
| `code_128_reader` | [Code 128](https://en.wikipedia.org/wiki/Code_128), [GS1-128](https://en.wikipedia.org/wiki/GS1-128) | General purpose, shipping, packaging, supply chain |
|
||||
| `ean_reader` | [EAN-13](https://en.wikipedia.org/wiki/International_Article_Number) | Retail products worldwide |
|
||||
| `ean_8_reader` | [EAN-8](https://en.wikipedia.org/wiki/EAN-8) | Small retail products |
|
||||
| `code_39_reader` | [Code 39](https://en.wikipedia.org/wiki/Code_39) | Automotive, defense, healthcare |
|
||||
| `code_39_vin_reader` | Code 39 VIN | Vehicle Identification Numbers |
|
||||
| `codabar_reader` | [Codabar](https://en.wikipedia.org/wiki/Codabar) | Libraries, blood banks, logistics |
|
||||
| `upc_reader` | [UPC-A](https://en.wikipedia.org/wiki/Universal_Product_Code) | Retail products (North America) |
|
||||
| `upc_e_reader` | [UPC-E](https://en.wikipedia.org/wiki/Universal_Product_Code#UPC-E) | Small retail products |
|
||||
| `i2of5_reader` | [Interleaved 2 of 5](https://en.wikipedia.org/wiki/Interleaved_2_of_5) | Warehouse, distribution |
|
||||
| `2of5_reader` | [Standard 2 of 5](https://en.wikipedia.org/wiki/Two-out-of-five_code) | Industrial, airline tickets |
|
||||
| `code_93_reader` | [Code 93](https://en.wikipedia.org/wiki/Code_93) | Logistics, retail |
|
||||
| `code_32_reader` | [Code 32](https://en.wikipedia.org/wiki/Pharmacode#Code_32) | Italian pharmaceuticals |
|
||||
| `pharmacode_reader` | [Pharmacode](https://en.wikipedia.org/wiki/Pharmacode) | Pharmaceutical packaging |
|
||||
|
||||
## Basic Configuration {#basic-configuration}
|
||||
|
||||
Specify which barcode types to detect in the `decoder.readers` array:
|
||||
|
||||
```javascript
|
||||
Quagga.init({
|
||||
decoder: {
|
||||
readers: ["code_128_reader"] // Only detect Code 128
|
||||
}
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
Quagga.start();
|
||||
});
|
||||
```
|
||||
|
||||
### Multiple Readers {#multiple-readers}
|
||||
|
||||
You can enable multiple readers to detect different barcode types:
|
||||
|
||||
```javascript
|
||||
Quagga.init({
|
||||
decoder: {
|
||||
readers: [
|
||||
"code_128_reader",
|
||||
"ean_reader",
|
||||
"upc_reader"
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Important Considerations {#important-considerations}
|
||||
|
||||
### Reader Priority and Order {#reader-priority-and-order}
|
||||
|
||||
**Readers are processed in the exact order they appear in the `readers` array.** The first reader to successfully decode the barcode wins - subsequent readers are not tried.
|
||||
|
||||
This allows you to prioritize certain formats over others when multiple formats might match the same barcode pattern:
|
||||
|
||||
```javascript
|
||||
decoder: {
|
||||
// EAN-13 checked first, then UPC formats
|
||||
readers: ['ean_reader', 'upc_reader', 'upc_e_reader']
|
||||
}
|
||||
```
|
||||
|
||||
**Why order matters:**
|
||||
|
||||
- Readers are processed sequentially, not in parallel
|
||||
- Some readers may return false positives for other formats
|
||||
- Example: EAN-13 and UPC-A/UPC-E share similar patterns and can clash
|
||||
- The first successful decode is returned immediately
|
||||
|
||||
**Best practice**: List your most commonly expected barcode types first for best accuracy and performance.
|
||||
|
||||
### Don't Enable All Readers {#dont-enable-all-readers}
|
||||
|
||||
**Why not enable all readers by default?**
|
||||
|
||||
- More readers = more processing time
|
||||
- Increased chance of false positives
|
||||
- Some formats overlap and can interfere
|
||||
|
||||
**Best practice**: Only enable the barcode formats you actually need to scan.
|
||||
|
||||
### Format Conflicts {#format-conflicts}
|
||||
|
||||
Some barcode formats are subsets or extensions of others:
|
||||
|
||||
- **UPC-A** is a subset of **EAN-13**
|
||||
- **EAN-8** is shorter version of **EAN-13**
|
||||
- **Code 39** and **Code 39 VIN** share similar patterns
|
||||
|
||||
Be careful when enabling multiple related formats together.
|
||||
|
||||
## GS1-128 Barcodes {#gs1-128-barcodes}
|
||||
|
||||
[GS1-128](https://en.wikipedia.org/wiki/GS1-128) (formerly known as EAN-128 or UCC-128) is a subset of Code 128 used extensively in supply chain and logistics. It uses special FNC1 (Function Code 1) characters to separate variable-length data fields called Application Identifiers (AIs).
|
||||
|
||||
### How GS1-128 Works {#gs1-128-how-it-works}
|
||||
|
||||
GS1-128 barcodes encode structured data using standardized Application Identifiers. For example:
|
||||
- **AI 01** = GTIN (Global Trade Item Number)
|
||||
- **AI 10** = Batch/Lot Number
|
||||
- **AI 17** = Expiration Date
|
||||
- **AI 21** = Serial Number
|
||||
|
||||
The FNC1 character acts as a field separator between variable-length AIs, allowing decoders to know where one field ends and another begins.
|
||||
|
||||
### FNC1 Character Handling {#fnc1-character-handling}
|
||||
|
||||
When the `code_128_reader` decodes a GS1-128 barcode, FNC1 characters are represented as ASCII 29 (Group Separator, `\x1D` or `\u001d`). This follows the GS1 standard for representing FNC1 in decoded data.
|
||||
|
||||
```javascript
|
||||
Quagga.decodeSingle({
|
||||
src: 'gs1-128-barcode.jpg',
|
||||
decoder: {
|
||||
readers: ['code_128_reader']
|
||||
}
|
||||
}, function(result) {
|
||||
if (result && result.codeResult) {
|
||||
const code = result.codeResult.code;
|
||||
// FNC1 characters appear as ASCII 29 (Group Separator)
|
||||
const GS = String.fromCharCode(29); // '\x1D'
|
||||
|
||||
// Split on Group Separator to get individual AI fields
|
||||
const fields = code.split(GS);
|
||||
console.log('Fields:', fields);
|
||||
// Example output: ["", "01034531200000111719050810ABCD1234", ...]
|
||||
|
||||
// Or check for GS1-128 format (starts with FNC1)
|
||||
if (code.startsWith(GS)) {
|
||||
console.log('This is a GS1-128 barcode');
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Parsing GS1-128 Data {#parsing-gs1-128-data}
|
||||
|
||||
Once decoded, you can parse the GS1-128 data using the Application Identifier structure:
|
||||
|
||||
```javascript
|
||||
function parseGS1(code) {
|
||||
const GS = String.fromCharCode(29);
|
||||
// Remove leading FNC1 if present
|
||||
const data = code.startsWith(GS) ? code.substring(1) : code;
|
||||
|
||||
// Split by FNC1 separator
|
||||
const segments = data.split(GS);
|
||||
|
||||
// Parse each segment for its AI
|
||||
// (A full implementation would use a complete AI table)
|
||||
return segments;
|
||||
}
|
||||
```
|
||||
|
||||
For full GS1 parsing, consider using a dedicated library like [gs1-barcode-parser](https://www.npmjs.com/package/gs1-barcode-parser) after decoding with Quagga2.
|
||||
|
||||
## EAN Extensions {#ean-extensions}
|
||||
|
||||
### EAN-2 and EAN-5 Supplements {#ean-supplements}
|
||||
|
||||
The EAN and UPC barcode formats support a supplement format, adding an additional 2 or 5 digits beyond the main barcode, EAN-2 and EAN-5, respectively. They are typically used for:
|
||||
- **Magazines and periodicals**: The main barcode identifies the publication, while the supplement denotes issue numbers or publication dates
|
||||
- **Books with ISBN**: The 5-digit supplement often encodes the suggested retail price
|
||||
|
||||
By default, `ean_reader` does not read and decode these extensions, you must explicitly enable support for them, if you are looking for them. Since UPC-A is a subset of EAN-13 -- UPC-A codes are EAN-13 codes that begin with a 0 -- supplement support configured on `ean_reader` also works for UPC-A codes.
|
||||
|
||||
To enable supplement decoding:
|
||||
|
||||
```javascript
|
||||
Quagga.init({
|
||||
decoder: {
|
||||
readers: [{
|
||||
format: "ean_reader",
|
||||
config: {
|
||||
supplements: [
|
||||
'ean_5_reader', // 5-digit supplement
|
||||
'ean_2_reader' // 2-digit supplement
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Supplement Result Structure {#supplement-result-structure}
|
||||
|
||||
When a barcode with a supplement is decoded, the result includes a `supplement` property:
|
||||
|
||||
```javascript
|
||||
{
|
||||
codeResult: {
|
||||
code: "419871600890101", // Combined: main barcode + supplement
|
||||
format: "ean_13", // Main barcode format
|
||||
supplement: {
|
||||
code: "01", // Supplement digits only
|
||||
format: "ean_2" // "ean_2" or "ean_5"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The main `codeResult.code` contains the full combined value, while `codeResult.supplement` provides the supplement details separately.
|
||||
|
||||
### Important Notes About Supplements {#supplements-notes}
|
||||
|
||||
**Supplement order matters**: The reader stops when it finds the first matching supplement. List `ean_5_reader` before `ean_2_reader` if you want to prioritize 5-digit extensions.
|
||||
|
||||
**Cannot read regular EAN-13 with supplements enabled**: If you configure supplements, that reader instance can **only** decode EAN codes **with** supplements. To read both:
|
||||
|
||||
```javascript
|
||||
Quagga.init({
|
||||
decoder: {
|
||||
readers: [
|
||||
"ean_reader", // Regular EAN-13 without supplements
|
||||
{
|
||||
format: "ean_reader",
|
||||
config: {
|
||||
supplements: ['ean_5_reader', 'ean_2_reader']
|
||||
}
|
||||
} // EAN-13 with supplements
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
This configuration creates two separate reader instances.
|
||||
|
||||
## External Readers {#external-readers}
|
||||
|
||||
Quagga2 supports external reader modules for additional barcode formats not built into the core library.
|
||||
|
||||
### QR Code Reader {#qr-code-reader}
|
||||
|
||||
For QR code support, see [quagga2-reader-qr](https://github.com/ericblade/quagga2-reader-qr).
|
||||
|
||||
External readers extend Quagga2's capabilities beyond 1D barcodes:
|
||||
|
||||
```javascript
|
||||
import Quagga from '@ericblade/quagga2';
|
||||
import QRReader from 'quagga2-reader-qr';
|
||||
|
||||
// Register external reader
|
||||
Quagga.registerReader('qr', QRReader);
|
||||
|
||||
Quagga.init({
|
||||
decoder: {
|
||||
readers: ['qr'] // Use external QR reader
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### External Reader Priority {#external-reader-priority}
|
||||
|
||||
External readers follow the **same priority rules** as built-in readers. Once registered with `Quagga.registerReader()`, an external reader can be placed anywhere in the `readers` array, and its position determines when it attempts to decode relative to other readers:
|
||||
|
||||
```javascript
|
||||
// Register external reader first
|
||||
Quagga.registerReader('my_custom_reader', MyCustomReader);
|
||||
|
||||
// Use in config - position determines priority
|
||||
Quagga.init({
|
||||
decoder: {
|
||||
// External reader tried first, then built-in readers
|
||||
readers: ['my_custom_reader', 'ean_reader', 'code_128_reader']
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
- External readers must be registered via `registerReader()` before use
|
||||
- Their position in `readers` array determines decode priority
|
||||
- There is no automatic "internal first, external second" ordering
|
||||
- External readers interleave freely with built-in readers
|
||||
|
||||
### Creating Custom Readers {#creating-custom-readers}
|
||||
|
||||
You can create your own barcode reader implementations by extending the `BarcodeReader` prototype exported by Quagga2. See [How-To: Create External Readers](../how-to-guides/external-readers.md) for details.
|
||||
|
||||
## Reader Performance {#reader-performance}
|
||||
|
||||
Different readers have different performance characteristics:
|
||||
|
||||
**Fastest readers**:
|
||||
|
||||
- `code_128_reader` - Optimized, widely used
|
||||
- `ean_reader` - Fast and reliable
|
||||
|
||||
**Slower readers**:
|
||||
|
||||
- `code_39_reader` - More complex pattern
|
||||
- `i2of5_reader` - Requires more validation
|
||||
|
||||
**Resource intensive**:
|
||||
|
||||
- Multiple readers enabled simultaneously
|
||||
- Readers with supplements configured
|
||||
|
||||
## Validation {#validation}
|
||||
|
||||
Some barcode formats include check digits for validation:
|
||||
|
||||
- **EAN-13/EAN-8**: Built-in check digit
|
||||
- **Code 128**: Built-in check digit
|
||||
- **UPC-A/UPC-E**: Built-in check digit
|
||||
|
||||
For additional validation in your application, consider using [barcode-validator](https://github.com/ericblade/barcode-validator).
|
||||
|
||||
## Related {#related}
|
||||
|
||||
- [Configuration Reference](configuration.md) - Complete config options
|
||||
- [API Documentation](api.md) - How to use Quagga2 methods
|
||||
- [Tips & Tricks](../how-to-guides/tips-and-tricks.md) - Handling false positives
|
||||
|
||||
---
|
||||
|
||||
[← Back to Reference](index.md)
|
||||
Reference in New Issue
Block a user