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)
|
||||
Reference in New Issue
Block a user