quadqr-js 1.5.3 → 1.5.4

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.
package/README.md CHANGED
@@ -258,7 +258,7 @@ Compression modes are `none`, `auto`, `smart`, `brotli`, `deflate`, and `lz`. `a
258
258
 
259
259
  Signing can also be composed with Secure Payload. QuadQR compresses if requested, signs the normal payload with the private key, then encrypts the protected bytes with AES-256-GCM. A verifier supplies the trusted public key separately, or resolves it from `keyId`.
260
260
 
261
- The renderer supports an explicit `mode: "print"`. Print mode enforces a minimum 4-module quiet zone, uses darker print-safe RGB defaults, and prefers Classic solid modules. `getPrintGuidance()` converts a chosen physical size into module millimeters/pixels so print layouts can be checked before production testing.
261
+ The renderer supports an explicit `mode: "print"`. Print mode uses darker print-safe RGB defaults and prefers Classic solid modules, while `quietZone` behaves exactly as it does in screen mode. Four modules remains the recommended default. `getPrintGuidance()` converts a chosen physical size into module millimeters/pixels so print layouts can be checked before production testing.
262
262
 
263
263
  Centered logos support `size: "auto"`, which estimates a conservative ECC-aware ratio from code utilization and rendering choices. `findMaxSafeLogoSize()` can additionally probe ImageData output and empirically search for the largest size that still decodes.
264
264
 
@@ -1281,4 +1281,4 @@ AGPL v3.0. See `LICENSE`.
1281
1281
 
1282
1282
  **Experimental / research project**
1283
1283
 
1284
- QuadQR is actively evolving. Format details may change between versions until the wire format is considered stable.
1284
+ QuadQR is actively evolving. Format details may change between versions until the wire format is considered stable.
package/SPECIFICATION.md CHANGED
@@ -253,9 +253,9 @@ inset
253
253
 
254
254
  ### Print mode
255
255
 
256
- `mode: "print"` applies conservative defaults:
256
+ `mode: "print"` applies print-oriented defaults:
257
257
 
258
- - minimum quiet zone of 4 modules unless explicitly overridden;
258
+ - caller-controlled quiet-zone sizing, identical to screen mode (4 modules recommended by default);
259
259
  - print-safe darker RGB primaries;
260
260
  - Classic solid-module rendering by default;
261
261
  - physical-size guidance through `getPrintGuidance()`.
@@ -3056,10 +3056,7 @@ function svgLogoHref(source) {
3056
3056
 
3057
3057
  function resolveRenderSizing(options, matrixSize) {
3058
3058
  const mode = normalizeRenderMode(options.mode ?? options.renderMode ?? RENDER_MODES.SCREEN);
3059
- const requestedQuietZone = Math.max(0, Math.floor(options.quietZone ?? 4));
3060
- const quietZone = mode === RENDER_MODES.PRINT && options.allowUnsafePrintQuietZone !== true
3061
- ? Math.max(4, requestedQuietZone)
3062
- : requestedQuietZone;
3059
+ const quietZone = Math.max(0, Math.floor(options.quietZone ?? 4));
3063
3060
  const totalModules = matrixSize + quietZone * 2;
3064
3061
  const hasImageSize = options.imageSize !== undefined && options.imageSize !== null;
3065
3062
  const hasModuleSize = options.moduleSize !== undefined && options.moduleSize !== null;
package/dist/quadqr.js CHANGED
@@ -9241,10 +9241,7 @@ function svgLogoHref(source) {
9241
9241
 
9242
9242
  function resolveRenderSizing(options, matrixSize) {
9243
9243
  const mode = normalizeRenderMode(options.mode ?? options.renderMode ?? RENDER_MODES.SCREEN);
9244
- const requestedQuietZone = Math.max(0, Math.floor(options.quietZone ?? 4));
9245
- const quietZone = mode === RENDER_MODES.PRINT && options.allowUnsafePrintQuietZone !== true
9246
- ? Math.max(4, requestedQuietZone)
9247
- : requestedQuietZone;
9244
+ const quietZone = Math.max(0, Math.floor(options.quietZone ?? 4));
9248
9245
  const totalModules = matrixSize + quietZone * 2;
9249
9246
  const hasImageSize = options.imageSize !== undefined && options.imageSize !== null;
9250
9247
  const hasModuleSize = options.moduleSize !== undefined && options.moduleSize !== null;
@@ -9071,10 +9071,7 @@ function svgLogoHref(source) {
9071
9071
 
9072
9072
  function resolveRenderSizing(options, matrixSize) {
9073
9073
  const mode = normalizeRenderMode(options.mode ?? options.renderMode ?? RENDER_MODES.SCREEN);
9074
- const requestedQuietZone = Math.max(0, Math.floor(options.quietZone ?? 4));
9075
- const quietZone = mode === RENDER_MODES.PRINT && options.allowUnsafePrintQuietZone !== true
9076
- ? Math.max(4, requestedQuietZone)
9077
- : requestedQuietZone;
9074
+ const quietZone = Math.max(0, Math.floor(options.quietZone ?? 4));
9078
9075
  const totalModules = matrixSize + quietZone * 2;
9079
9076
  const hasImageSize = options.imageSize !== undefined && options.imageSize !== null;
9080
9077
  const hasModuleSize = options.moduleSize !== undefined && options.moduleSize !== null;
package/docs/API.md CHANGED
@@ -531,7 +531,7 @@ All render APIs accept:
531
531
  { mode: "screen" | "print" }
532
532
  ```
533
533
 
534
- Print mode uses a darker print-safe palette, forces Classic modules by default, and enforces a minimum 4-module quiet zone unless `allowUnsafePrintQuietZone: true` is explicitly set.
534
+ Print mode uses a darker print-safe palette and forces Classic modules by default. `quietZone` has the same behavior in print and screen modes, including support for values below the recommended four-module default.
535
535
 
536
536
  ### `getPrintGuidance(codeOrMatrix, options?)`
537
537
 
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 uses the print-safe palette and Classic rendering defaults. `--quiet-zone` is honored unchanged, just as it is in screen mode; four modules remains recommended.
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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quadqr-js",
3
- "version": "1.5.3",
3
+ "version": "1.5.4",
4
4
  "description": "QuadQR: experimental RGBW matrix code with optional experimental High Density Mode, Spectrum ECC 2.0, multi-frame camera scanning, advanced calibration, Reliability Lab, and 3D perspective recovery.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",