quadqr-js 1.4.2 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
package/docs/API.md CHANGED
@@ -209,11 +209,16 @@ const result = scanVideoFrame(video);
209
209
 
210
210
  ### `startCameraScanner(video, options?)`
211
211
 
212
- Starts live camera scanning. On browsers that expose camera controls, QuadQR requests continuous autofocus, exposure, and white balance. It scans the CSS-visible preview region by default. Finder detection uses a QuadQR-specific RGB value channel (`max(R,G,B)`) on the fast pass so saturated blue/red/green data cells are not mistaken for structural black. If a miss still contains at least two strong finder patterns, the scanner can retry the visible ROI at up to 1600 px before heavier recovery, which preserves more pixels per module for dense versions. If that does not decode, the **same captured frame** is retried through QuadQR code-centric Auto Color recovery. The default recovery sequence crops 8%, 16%, and 22% from the camera-frame edges, then falls back to the full frame. This prevents dark room pixels, browser UI, or monitor bezels outside the guide from controlling QuadQR Auto Color and Otsu thresholds. Each crop uses the QuadQR-specific per-channel shadow/highlight correction with a neutral mid-high highlight target (190 by default). Finder-only recovery also tries multiple center-weighted QuadQR Auto Color histogram windows before raw threshold bracketing. The normal fast path is untouched; these extra passes run only after a miss. If geometry is found but color decoding fails, the captured ROI is retried with stronger color/geometry recovery, including affine cross-channel calibration. Consecutive failed frames can then be combined with tracked-symbol **confidence fusion**: cell evidence is weighted by source confidence, frame quality, and recency, and second hypotheses are carried forward into Spectrum ECC 2.0.
212
+ Starts live camera scanning. On browsers that expose camera controls, QuadQR requests continuous autofocus, exposure, and white balance. Modern browsers use two module Web Workers by default: a **fast fresh-frame worker** for normal finder/geometry/decode attempts and a separate **full-recovery worker** for the same perspective, color, high-resolution, ECC, damaged-code, and multi-frame recovery stack used by the main scanner. The recovery worker is lazy and independent, so a difficult old frame cannot block the fast worker from inspecting a newer camera frame. Finder detection itself is JavaScript; WASM only accelerates deterministic grayscale/binary preprocessing and CRC. The loop uses `requestVideoFrameCallback()` when available, drops stale fast-path frames, and measures `scanInterval` from scan start. Worker mode defaults to a 33 ms minimum cadence; automatic main-thread fallback uses 80 ms. The default camera request is approximately 1280×720, while the CSS-visible preview crop is resized to a 640 px working bitmap before crossing the worker boundary. Finder acquisition uses the streaming 1:1:3:1:1 RGB-value pass, direct cross-checks, local-threshold fallback, and directional module-size/version estimation. Once a geometry candidate validates structure, ECC, and CRC, it returns immediately. A miss with strong finder evidence dispatches parallel full recovery quickly; frames with weak or zero finder evidence still receive periodic full recovery so color-cast/damaged locator cases remain recoverable. That recovery can use up to 960 px and retains the full QuadQR Auto Color crop sequence, center-weighted color recovery, threshold bracketing, precise alignment, perspective recovery, affine cross-channel calibration, QR-region enhancement, multi-frame confidence fusion, erasure decoding, and soft-decision Spectrum ECC.
213
213
 
214
214
  ```js
215
215
  const scanner = await startCameraScanner(video, {
216
- scanInterval: 120,
216
+ cameraWorker: true,
217
+ maxDimension: 640,
218
+ scanInterval: 33,
219
+ useVideoFrameCallback: true,
220
+ cameraGeometryReuse: true,
221
+ cameraGeometryReuseMaxMisses: 5,
217
222
  multiFrame: true,
218
223
  multiFrameWindow: 4,
219
224
  multiFrameMinFrames: 2,
@@ -226,8 +231,11 @@ const scanner = await startCameraScanner(video, {
226
231
  cameraAutoEnhanceEvery: 2,
227
232
  cameraFinderRecoveryEvery: 2,
228
233
  cameraHighResolutionRecovery: true,
229
- cameraHighResolutionMaxDimension: 1600,
234
+ cameraHighResolutionMaxDimension: 960,
230
235
  cameraHighResolutionEvery: 2,
236
+ cameraRecoveryStrongFinderInterval: 120,
237
+ cameraRecoveryWeakFinderInterval: 260,
238
+ cameraRecoveryNoFinderInterval: 850,
231
239
  onResult(result) {
232
240
  console.log(result);
233
241
  },
@@ -331,14 +339,14 @@ Security constants include:
331
339
 
332
340
  ### `initWasm(options?)`
333
341
 
334
- Loads and activates the optional bundled WASM accelerator.
342
+ Loads and activates the optional bundled WASM accelerator for CRC-32 and scanner pixel preprocessing (RGBA grayscale conversion, Otsu thresholding, and finder binary generation).
335
343
 
336
344
  ```js
337
345
  import { initWasm } from "quadqr-js";
338
346
  await initWasm();
339
347
  ```
340
348
 
341
- An explicit URL or byte buffer can also be supplied.
349
+ An explicit URL or byte buffer can also be supplied. Initialize it once before performance-sensitive synchronous `scanImageData()` loops or before starting the camera scanner.
342
350
 
343
351
  ### `getWasmState()`
344
352
 
@@ -95,7 +95,7 @@ If the symbol uses Secure Payload, the scan result has `secure: true` and `requi
95
95
  const video = document.querySelector("#camera");
96
96
 
97
97
  const scanner = await startCameraScanner(video, {
98
- scanInterval: 120,
98
+ scanInterval: 33,
99
99
  cameraFinderRecoveryEvery: 2,
100
100
  async onResult(result) {
101
101
  console.log(result);
@@ -137,7 +137,7 @@ The global browser build exposes `window.QuadQR` / `globalThis.QuadQR`.
137
137
 
138
138
  ```html
139
139
  <canvas id="qr"></canvas>
140
- <script src="https://cdn.jsdelivr.net/npm/quadqr-js@1.4.1/dist/quadqr.min.js"></script>
140
+ <script src="https://cdn.jsdelivr.net/npm/quadqr-js@1.5.1/dist/quadqr.min.js"></script>
141
141
  <script>
142
142
  const code = QuadQR.encodeText("Hello CDN");
143
143
 
@@ -151,7 +151,7 @@ The global browser build exposes `window.QuadQR` / `globalThis.QuadQR`.
151
151
  ## unpkg
152
152
 
153
153
  ```html
154
- <script src="https://unpkg.com/quadqr-js@1.4.1/dist/quadqr.min.js"></script>
154
+ <script src="https://unpkg.com/quadqr-js@1.5.1/dist/quadqr.min.js"></script>
155
155
  ```
156
156
 
157
157
  ## Direct CDN ESM
@@ -161,7 +161,7 @@ The global browser build exposes `window.QuadQR` / `globalThis.QuadQR`.
161
161
  import {
162
162
  encodeText,
163
163
  renderToCanvas
164
- } from "https://cdn.jsdelivr.net/npm/quadqr-js@1.4.1/dist/browser.js";
164
+ } from "https://cdn.jsdelivr.net/npm/quadqr-js@1.5.1/dist/browser.js";
165
165
 
166
166
  const code = encodeText("ES module CDN");
167
167
  renderToCanvas(code, document.querySelector("#qr"));
@@ -188,4 +188,4 @@ WASM is optional. The normal JavaScript implementation remains available if it c
188
188
 
189
189
  ## Production recommendation
190
190
 
191
- Pin a concrete package version such as `@1.4.1` in CDN URLs so an existing site does not silently change when a newer package version becomes available.
191
+ Pin a concrete package version such as `@1.5.1` in CDN URLs so an existing site does not silently change when a newer package version becomes available.
package/docs/CLI.md CHANGED
@@ -1,167 +1,167 @@
1
- # Command Line Interface
2
-
3
- The npm package includes the `quadqr` executable and can be used directly through `npx`.
4
-
5
- ## Encode text
6
-
7
- ```bash
8
- npx quadqr-js encode "Hello QuadQR" -o hello.png
9
- npx quadqr-js encode "Hello QuadQR" -o hello.svg
10
- ```
11
-
12
- Optional encoding controls:
13
-
14
- ```bash
15
- npx quadqr-js encode "Hello" --ecc M --version auto --image-size 720 --quiet-zone 4 -o hello.png
16
- ```
17
-
18
- Use the print-safe rendering profile when the symbol is intended for physical output:
19
-
20
- ```bash
21
- npx quadqr-js encode "Print me" --print -o print.svg
22
- ```
23
-
24
- Print mode enforces a minimum four-module quiet zone and uses the print-safe rendering defaults.
25
-
26
- ## Compression
27
-
28
- Compression works directly with normal text payloads:
29
-
30
- ```bash
31
- npx quadqr-js encode "repeat repeat repeat repeat" \
32
- --compression auto \
33
- -o compressed.png
34
- ```
35
-
36
- Compression modes are `none`, `auto`, `smart`, `brotli`, `deflate`, and `lz`. `auto` performs one balanced comparison using LZ level 6, DEFLATE level 6, and Brotli quality 6. `smart` is CPU-heavy: it starts with the same pass and only escalates to stronger DEFLATE/Brotli levels when a smaller QuadQR version is realistically reachable. If envelope overhead would erase the gain, Auto/Smart leave the original payload untouched. No separate payload mode is required.
37
-
38
- Explicit codecs can select a level:
39
-
40
- ```bash
41
- npx quadqr-js encode "structured payload" --compression lz --compression-level 9 -o lz.png
42
- npx quadqr-js encode "structured payload" --compression deflate --compression-level 9 -o deflate.png
43
- npx quadqr-js encode "structured payload" --compression brotli --compression-level 11 -o brotli.png
44
- ```
45
-
46
- LZ and DEFLATE accept levels `1..9` and default to 6. Brotli accepts qualities `0..11` and defaults to 11. `--compression-level` is ignored by Auto/Smart because those modes manage their own staged levels.
47
-
48
- ## Signed QuadQR
49
-
50
- Generate an Ed25519 signing-key bundle:
51
-
52
- ```bash
53
- npx quadqr-js signkeygen -o quadqr-signing-key.json
54
- ```
55
-
56
- Keep this file secret because it contains the private signing key. Encode a signed payload with:
57
-
58
- ```bash
59
- npx quadqr-js encode "Offline-verifiable ticket" \
60
- --sign-key quadqr-signing-key.json \
61
- -o signed.png
62
- ```
63
-
64
- The generated key bundle contains both keys plus a compact `keyId`. Only the private key signs. The public key is **not embedded** in the QuadQR by default and should be distributed separately to trusted scanners or stored in a trusted-key registry.
65
-
66
- To override the identifier stored in the symbol:
67
-
68
- ```bash
69
- npx quadqr-js encode "Offline-verifiable ticket" \
70
- --sign-key quadqr-signing-key.json \
71
- --key-id event-main-2026 \
72
- -o signed.png
73
- ```
74
-
75
- Signing can be combined with password or raw-key encryption:
76
-
77
- ```bash
78
- npx quadqr-js encode "Signed and private" \
79
- --sign-key quadqr-signing-key.json \
80
- --password "my-password" \
81
- -o signed-secure.png
82
- ```
83
-
84
- ## Decode an image
85
-
86
- ```bash
87
- npx quadqr-js decode hello.png
88
- npx quadqr-js decode signed.png --verify-key quadqr-signing-key.json
89
- ```
90
-
91
- For an unencrypted text payload, the decoded text is printed to stdout. To verify a signed symbol against a trusted public key, pass the signing bundle with `--verify-key`.
92
-
93
- Add scanner diagnostics without changing the normal stdout payload:
94
-
95
- ```bash
96
- npx quadqr-js decode hello.png --debug
97
- ```
98
-
99
- Diagnostics are written to stderr and include confidence, geometry/color confidence, ECC utilization, signing state, and the scanner diagnostics object when available.
100
-
101
- ## Password-protected payloads
102
-
103
- Encode:
104
-
105
- ```bash
106
- npx quadqr-js encode "Private data" --password "my-password" -o secure.png
107
- ```
108
-
109
- Decode:
110
-
111
- ```bash
112
- npx quadqr-js decode secure.png --password "my-password"
113
- ```
114
-
115
- If an encrypted symbol is decoded without a credential, the CLI reports that decryption is required instead of exposing plaintext.
116
-
117
- ## Raw 256-bit key mode
118
-
119
- Generate a random 256-bit encryption key:
120
-
121
- ```bash
122
- npx quadqr-js keygen
123
- ```
124
-
125
- The output is a 64-character hexadecimal key. Store it securely and do not place it inside the same QuadQR symbol.
126
-
127
- Encode using the key:
128
-
129
- ```bash
130
- npx quadqr-js encode "Application secret" --key <64-hex-key> -o secure-key.png
131
- ```
132
-
133
- Decode using the key:
134
-
135
- ```bash
136
- npx quadqr-js decode secure-key.png --key <64-hex-key>
137
- ```
138
-
139
- ## Options
140
-
141
- | Option | Purpose |
142
- | --- | --- |
143
- | `-o, --output <file>` | Output PNG/SVG path, or signing-key JSON path for `signkeygen` |
144
- | `--ecc <L|M|Q|H>` | QuadQR ECC profile. Default: `M` |
145
- | `--version <auto|1..40>` | Symbol version. Default: `auto` |
146
- | `--compression <mode>` | `none`, `auto`, `smart`, `brotli`, `deflate`, or `lz`. Default: `auto` |
147
- | `--compression-level <n>` | Explicit LZ/DEFLATE `1..9` or Brotli `0..11` encoder level |
148
- | `--high-density` | Enable experimental Triangle16 High Density Mode |
149
- | `--sign-key <file>` | Sign using a key bundle generated by `signkeygen` |
150
- | `--key-id <id>` | Override the signing key ID stored in the symbol |
151
- | `--embed-public-key` | Explicit compatibility mode that embeds the public key |
152
- | `--verify-key <file>` | Verify a signed symbol with a trusted Ed25519 key bundle |
153
- | `--password <text>` | Password-mode encryption/decryption |
154
- | `--key <hex>` | Raw 256-bit key encryption/decryption |
155
- | `--print` | Use the print-safe render profile |
156
- | `--image-size <px>` | Exact square output size in pixels. Default: `720` |
157
- | `--module-size <px>` | Legacy pixels-per-module sizing. Used when `--image-size` is omitted |
158
- | `--quiet-zone <modules>` | Quiet-zone size in modules. Default: `4` |
159
- | `--debug` | Emit scanner diagnostics to stderr when decoding |
160
- | `-h, --help` | Show CLI help |
161
-
162
- Password mode and raw-key mode are mutually exclusive for a single operation.
163
-
164
-
165
- ## High Density Mode (Experimental)
166
-
167
- Use `--high-density` to enable the experimental Triangle16 layout with 16 states and 4 raw bits per body cell. Decode is automatic; no matching decode flag is required.
1
+ # Command Line Interface
2
+
3
+ The npm package includes the `quadqr` executable and can be used directly through `npx`.
4
+
5
+ ## Encode text
6
+
7
+ ```bash
8
+ npx quadqr-js encode "Hello QuadQR" -o hello.png
9
+ npx quadqr-js encode "Hello QuadQR" -o hello.svg
10
+ ```
11
+
12
+ Optional encoding controls:
13
+
14
+ ```bash
15
+ npx quadqr-js encode "Hello" --ecc M --version auto --image-size 720 --quiet-zone 4 -o hello.png
16
+ ```
17
+
18
+ Use the print-safe rendering profile when the symbol is intended for physical output:
19
+
20
+ ```bash
21
+ npx quadqr-js encode "Print me" --print -o print.svg
22
+ ```
23
+
24
+ Print mode enforces a minimum four-module quiet zone and uses the print-safe rendering defaults.
25
+
26
+ ## Compression
27
+
28
+ Compression works directly with normal text payloads:
29
+
30
+ ```bash
31
+ npx quadqr-js encode "repeat repeat repeat repeat" \
32
+ --compression auto \
33
+ -o compressed.png
34
+ ```
35
+
36
+ Compression modes are `none`, `auto`, `smart`, `brotli`, `deflate`, and `lz`. `auto` performs one balanced comparison using LZ level 6, DEFLATE level 6, and Brotli quality 6. `smart` is CPU-heavy: it starts with the same pass and only escalates to stronger DEFLATE/Brotli levels when a smaller QuadQR version is realistically reachable. If envelope overhead would erase the gain, Auto/Smart leave the original payload untouched. No separate payload mode is required.
37
+
38
+ Explicit codecs can select a level:
39
+
40
+ ```bash
41
+ npx quadqr-js encode "structured payload" --compression lz --compression-level 9 -o lz.png
42
+ npx quadqr-js encode "structured payload" --compression deflate --compression-level 9 -o deflate.png
43
+ npx quadqr-js encode "structured payload" --compression brotli --compression-level 11 -o brotli.png
44
+ ```
45
+
46
+ LZ and DEFLATE accept levels `1..9` and default to 6. Brotli accepts qualities `0..11` and defaults to 11. `--compression-level` is ignored by Auto/Smart because those modes manage their own staged levels.
47
+
48
+ ## Signed QuadQR
49
+
50
+ Generate an Ed25519 signing-key bundle:
51
+
52
+ ```bash
53
+ npx quadqr-js signkeygen -o quadqr-signing-key.json
54
+ ```
55
+
56
+ Keep this file secret because it contains the private signing key. Encode a signed payload with:
57
+
58
+ ```bash
59
+ npx quadqr-js encode "Offline-verifiable ticket" \
60
+ --sign-key quadqr-signing-key.json \
61
+ -o signed.png
62
+ ```
63
+
64
+ The generated key bundle contains both keys plus a compact `keyId`. Only the private key signs. The public key is **not embedded** in the QuadQR by default and should be distributed separately to trusted scanners or stored in a trusted-key registry.
65
+
66
+ To override the identifier stored in the symbol:
67
+
68
+ ```bash
69
+ npx quadqr-js encode "Offline-verifiable ticket" \
70
+ --sign-key quadqr-signing-key.json \
71
+ --key-id event-main-2026 \
72
+ -o signed.png
73
+ ```
74
+
75
+ Signing can be combined with password or raw-key encryption:
76
+
77
+ ```bash
78
+ npx quadqr-js encode "Signed and private" \
79
+ --sign-key quadqr-signing-key.json \
80
+ --password "my-password" \
81
+ -o signed-secure.png
82
+ ```
83
+
84
+ ## Decode an image
85
+
86
+ ```bash
87
+ npx quadqr-js decode hello.png
88
+ npx quadqr-js decode signed.png --verify-key quadqr-signing-key.json
89
+ ```
90
+
91
+ For an unencrypted text payload, the decoded text is printed to stdout. To verify a signed symbol against a trusted public key, pass the signing bundle with `--verify-key`.
92
+
93
+ Add scanner diagnostics without changing the normal stdout payload:
94
+
95
+ ```bash
96
+ npx quadqr-js decode hello.png --debug
97
+ ```
98
+
99
+ Diagnostics are written to stderr and include confidence, geometry/color confidence, ECC utilization, signing state, and the scanner diagnostics object when available.
100
+
101
+ ## Password-protected payloads
102
+
103
+ Encode:
104
+
105
+ ```bash
106
+ npx quadqr-js encode "Private data" --password "my-password" -o secure.png
107
+ ```
108
+
109
+ Decode:
110
+
111
+ ```bash
112
+ npx quadqr-js decode secure.png --password "my-password"
113
+ ```
114
+
115
+ If an encrypted symbol is decoded without a credential, the CLI reports that decryption is required instead of exposing plaintext.
116
+
117
+ ## Raw 256-bit key mode
118
+
119
+ Generate a random 256-bit encryption key:
120
+
121
+ ```bash
122
+ npx quadqr-js keygen
123
+ ```
124
+
125
+ The output is a 64-character hexadecimal key. Store it securely and do not place it inside the same QuadQR symbol.
126
+
127
+ Encode using the key:
128
+
129
+ ```bash
130
+ npx quadqr-js encode "Application secret" --key <64-hex-key> -o secure-key.png
131
+ ```
132
+
133
+ Decode using the key:
134
+
135
+ ```bash
136
+ npx quadqr-js decode secure-key.png --key <64-hex-key>
137
+ ```
138
+
139
+ ## Options
140
+
141
+ | Option | Purpose |
142
+ | --- | --- |
143
+ | `-o, --output <file>` | Output PNG/SVG path, or signing-key JSON path for `signkeygen` |
144
+ | `--ecc <L|M|Q|H>` | QuadQR ECC profile. Default: `M` |
145
+ | `--version <auto|1..40>` | Symbol version. Default: `auto` |
146
+ | `--compression <mode>` | `none`, `auto`, `smart`, `brotli`, `deflate`, or `lz`. Default: `auto` |
147
+ | `--compression-level <n>` | Explicit LZ/DEFLATE `1..9` or Brotli `0..11` encoder level |
148
+ | `--high-density` | Enable experimental Triangle16 High Density Mode |
149
+ | `--sign-key <file>` | Sign using a key bundle generated by `signkeygen` |
150
+ | `--key-id <id>` | Override the signing key ID stored in the symbol |
151
+ | `--embed-public-key` | Explicit compatibility mode that embeds the public key |
152
+ | `--verify-key <file>` | Verify a signed symbol with a trusted Ed25519 key bundle |
153
+ | `--password <text>` | Password-mode encryption/decryption |
154
+ | `--key <hex>` | Raw 256-bit key encryption/decryption |
155
+ | `--print` | Use the print-safe render profile |
156
+ | `--image-size <px>` | Exact square output size in pixels. Default: `720` |
157
+ | `--module-size <px>` | Legacy pixels-per-module sizing. Used when `--image-size` is omitted |
158
+ | `--quiet-zone <modules>` | Quiet-zone size in modules. Default: `4` |
159
+ | `--debug` | Emit scanner diagnostics to stderr when decoding |
160
+ | `-h, --help` | Show CLI help |
161
+
162
+ Password mode and raw-key mode are mutually exclusive for a single operation.
163
+
164
+
165
+ ## High Density Mode (Experimental)
166
+
167
+ Use `--high-density` to enable the experimental Triangle16 layout with 16 states and 4 raw bits per body cell. Decode is automatic; no matching decode flag is required.