@vielzeug/sigil 26.10.0 → 26.10.5
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 +5 -5
- package/dist/_galois.cjs.map +1 -1
- package/dist/_galois.d.ts +1 -1
- package/dist/_galois.d.ts.map +1 -1
- package/dist/_galois.js.map +1 -1
- package/dist/_matrix.cjs.map +1 -1
- package/dist/_matrix.d.ts +1 -1
- package/dist/_matrix.d.ts.map +1 -1
- package/dist/_matrix.js.map +1 -1
- package/dist/_segments.cjs.map +1 -1
- package/dist/_segments.d.ts +1 -1
- package/dist/_segments.d.ts.map +1 -1
- package/dist/_segments.js.map +1 -1
- package/dist/_tables.cjs.map +1 -1
- package/dist/_tables.d.ts +4 -4
- package/dist/_tables.js.map +1 -1
- package/dist/canvas.cjs.map +1 -1
- package/dist/canvas.d.ts +1 -1
- package/dist/canvas.js.map +1 -1
- package/dist/encode.cjs.map +1 -1
- package/dist/encode.d.ts +2 -2
- package/dist/encode.js.map +1 -1
- package/dist/scan.cjs.map +1 -1
- package/dist/scan.js.map +1 -1
- package/dist/sigil.cjs.map +1 -1
- package/dist/sigil.iife.js.map +1 -1
- package/dist/sigil.js.map +1 -1
- package/dist/svg.cjs.map +1 -1
- package/dist/svg.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @vielzeug/sigil
|
|
2
2
|
|
|
3
|
-
> QR code generation and scanning
|
|
3
|
+
> QR code generation and scanning: pure matrix encoder, SVG and canvas renderers, native BarcodeDetector scanning
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -15,18 +15,18 @@ yarn add @vielzeug/sigil
|
|
|
15
15
|
```ts
|
|
16
16
|
import { createQrScanner, encodeQr, toSvg } from '@vielzeug/sigil';
|
|
17
17
|
|
|
18
|
-
// Encode to an inline SVG string
|
|
18
|
+
// Encode to an inline SVG string: works in Node and the browser.
|
|
19
19
|
const matrix = encodeQr('https://vielzeug.dev');
|
|
20
20
|
document.querySelector('#qr').innerHTML = toSvg(matrix, { label: 'Vielzeug link' });
|
|
21
21
|
|
|
22
|
-
// Scan with the camera (browser only
|
|
22
|
+
// Scan with the camera (browser only: feature-detect first).
|
|
23
23
|
const scanner = createQrScanner({ video: document.querySelector('video') });
|
|
24
24
|
scanner.onResult(({ value }) => console.log('scanned:', value));
|
|
25
25
|
await scanner.start();
|
|
26
26
|
scanner.dispose();
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
`toSvg` output uses `currentColor` modules by default
|
|
29
|
+
`toSvg` output uses `currentColor` modules by default: the code themes with ordinary CSS. Scanning requires `BarcodeDetector` and a secure context; call `qrScanSupport()` before showing a scan affordance.
|
|
30
30
|
|
|
31
31
|
## Documentation
|
|
32
32
|
|
|
@@ -37,4 +37,4 @@ scanner.dispose();
|
|
|
37
37
|
|
|
38
38
|
## License
|
|
39
39
|
|
|
40
|
-
MIT © [Helmuth Saatkamp](https://github.com/helmuthdu)
|
|
40
|
+
MIT © [Helmuth Saatkamp](https://github.com/helmuthdu): part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
|
package/dist/_galois.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_galois.cjs","names":[],"sources":["../src/_galois.ts"],"sourcesContent":["/**\n * GF(2⁸) arithmetic over the QR primitive polynomial x⁸+x⁴+x³+x²+1 (0x11D).\n * Tables are built once at module load: `EXP[i] = αⁱ` for generator α = 2.\n */\n\nconst PRIMITIVE = 0x11d;\n\nconst EXP = new Uint8Array(512);\nconst LOG = new Uint8Array(256);\n\n{\n let x = 1;\n for (let i = 0; i < 255; i++) {\n EXP[i] = x;\n LOG[x] = i;\n x <<= 1;\n if (x & 0x100) x ^= PRIMITIVE;\n }\n // Duplicate the cycle so `EXP[log(a) + log(b)]` never needs a mod.\n for (let i = 255; i < 512; i++) EXP[i] = EXP[i - 255];\n}\n\n/** `a * b` in GF(256); `0` when either operand is 0. */\nexport function gfMultiply(a: number, b: number): number {\n return a === 0 || b === 0 ? 0 : EXP[LOG[a] + LOG[b]];\n}\n\n/**
|
|
1
|
+
{"version":3,"file":"_galois.cjs","names":[],"sources":["../src/_galois.ts"],"sourcesContent":["/**\n * GF(2⁸) arithmetic over the QR primitive polynomial x⁸+x⁴+x³+x²+1 (0x11D).\n * Tables are built once at module load: `EXP[i] = αⁱ` for generator α = 2.\n */\n\nconst PRIMITIVE = 0x11d;\n\nconst EXP = new Uint8Array(512);\nconst LOG = new Uint8Array(256);\n\n{\n let x = 1;\n for (let i = 0; i < 255; i++) {\n EXP[i] = x;\n LOG[x] = i;\n x <<= 1;\n if (x & 0x100) x ^= PRIMITIVE;\n }\n // Duplicate the cycle so `EXP[log(a) + log(b)]` never needs a mod.\n for (let i = 255; i < 512; i++) EXP[i] = EXP[i - 255];\n}\n\n/** `a * b` in GF(256); `0` when either operand is 0. */\nexport function gfMultiply(a: number, b: number): number {\n return a === 0 || b === 0 ? 0 : EXP[LOG[a] + LOG[b]];\n}\n\n/** `αⁱ`: the i-th power of the generator. `i` may exceed 254 (wraps). */\nexport function gfExp(i: number): number {\n return EXP[i % 255];\n}\n\n/** Polynomial evaluation in GF(256): Σ coeffᵢ·xⁱ with coeff[0] highest-degree. */\nexport function gfPolyEval(coeffs: readonly number[], x: number): number {\n let y = 0;\n for (const c of coeffs) y = gfMultiply(y, x) ^ c;\n return y;\n}\n\n/** Multiply two polynomials (coefficients highest-degree first). */\nexport function gfPolyMultiply(p: readonly number[], q: readonly number[]): number[] {\n const out = new Array<number>(p.length + q.length - 1).fill(0);\n for (let i = 0; i < p.length; i++) for (let j = 0; j < q.length; j++) out[i + j] ^= gfMultiply(p[i], q[j]);\n return out;\n}\n"],"mappings":"AAKA,IAAM,EAAY,IAEZ,EAAM,IAAI,WAAW,GAAG,EACxB,EAAM,IAAI,WAAW,GAAG,EAE9B,CACE,IAAI,EAAI,EACR,IAAK,IAAI,EAAI,EAAG,EAAI,IAAK,IACvB,EAAI,GAAK,EACT,EAAI,GAAK,EACT,IAAM,EACF,EAAI,MAAO,GAAK,GAGtB,IAAK,IAAI,EAAI,IAAK,EAAI,IAAK,IAAK,EAAI,GAAK,EAAI,EAAI,IACnD,CAGA,SAAgB,WAAW,EAAW,EAAmB,CACvD,OAAO,IAAM,GAAK,IAAM,EAAI,EAAI,EAAI,EAAI,GAAK,EAAI,GACnD,CAGA,SAAgB,MAAM,EAAmB,CACvC,OAAO,EAAI,EAAI,IACjB,CAUA,SAAgB,eAAe,EAAsB,EAAgC,CACnF,IAAM,EAAU,MAAc,EAAE,OAAS,EAAE,OAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAC7D,IAAK,IAAI,EAAI,EAAG,EAAI,EAAE,OAAQ,IAAK,IAAK,IAAI,EAAI,EAAG,EAAI,EAAE,OAAQ,IAAK,EAAI,EAAI,IAAM,WAAW,EAAE,GAAI,EAAE,EAAE,EACzG,OAAO,CACT"}
|
package/dist/_galois.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
/** `a * b` in GF(256); `0` when either operand is 0. */
|
|
6
6
|
export declare function gfMultiply(a: number, b: number): number;
|
|
7
|
-
/**
|
|
7
|
+
/** `αⁱ`: the i-th power of the generator. `i` may exceed 254 (wraps). */
|
|
8
8
|
export declare function gfExp(i: number): number;
|
|
9
9
|
/** Polynomial evaluation in GF(256): Σ coeffᵢ·xⁱ with coeff[0] highest-degree. */
|
|
10
10
|
export declare function gfPolyEval(coeffs: readonly number[], x: number): number;
|
package/dist/_galois.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_galois.d.ts","sourceRoot":"","sources":["../src/_galois.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH,wDAAwD;AACxD,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,
|
|
1
|
+
{"version":3,"file":"_galois.d.ts","sourceRoot":"","sources":["../src/_galois.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH,wDAAwD;AACxD,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,yEAAyE;AACzE,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAIvE;AAED,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,EAAE,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAInF"}
|
package/dist/_galois.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_galois.js","names":[],"sources":["../src/_galois.ts"],"sourcesContent":["/**\n * GF(2⁸) arithmetic over the QR primitive polynomial x⁸+x⁴+x³+x²+1 (0x11D).\n * Tables are built once at module load: `EXP[i] = αⁱ` for generator α = 2.\n */\n\nconst PRIMITIVE = 0x11d;\n\nconst EXP = new Uint8Array(512);\nconst LOG = new Uint8Array(256);\n\n{\n let x = 1;\n for (let i = 0; i < 255; i++) {\n EXP[i] = x;\n LOG[x] = i;\n x <<= 1;\n if (x & 0x100) x ^= PRIMITIVE;\n }\n // Duplicate the cycle so `EXP[log(a) + log(b)]` never needs a mod.\n for (let i = 255; i < 512; i++) EXP[i] = EXP[i - 255];\n}\n\n/** `a * b` in GF(256); `0` when either operand is 0. */\nexport function gfMultiply(a: number, b: number): number {\n return a === 0 || b === 0 ? 0 : EXP[LOG[a] + LOG[b]];\n}\n\n/**
|
|
1
|
+
{"version":3,"file":"_galois.js","names":[],"sources":["../src/_galois.ts"],"sourcesContent":["/**\n * GF(2⁸) arithmetic over the QR primitive polynomial x⁸+x⁴+x³+x²+1 (0x11D).\n * Tables are built once at module load: `EXP[i] = αⁱ` for generator α = 2.\n */\n\nconst PRIMITIVE = 0x11d;\n\nconst EXP = new Uint8Array(512);\nconst LOG = new Uint8Array(256);\n\n{\n let x = 1;\n for (let i = 0; i < 255; i++) {\n EXP[i] = x;\n LOG[x] = i;\n x <<= 1;\n if (x & 0x100) x ^= PRIMITIVE;\n }\n // Duplicate the cycle so `EXP[log(a) + log(b)]` never needs a mod.\n for (let i = 255; i < 512; i++) EXP[i] = EXP[i - 255];\n}\n\n/** `a * b` in GF(256); `0` when either operand is 0. */\nexport function gfMultiply(a: number, b: number): number {\n return a === 0 || b === 0 ? 0 : EXP[LOG[a] + LOG[b]];\n}\n\n/** `αⁱ`: the i-th power of the generator. `i` may exceed 254 (wraps). */\nexport function gfExp(i: number): number {\n return EXP[i % 255];\n}\n\n/** Polynomial evaluation in GF(256): Σ coeffᵢ·xⁱ with coeff[0] highest-degree. */\nexport function gfPolyEval(coeffs: readonly number[], x: number): number {\n let y = 0;\n for (const c of coeffs) y = gfMultiply(y, x) ^ c;\n return y;\n}\n\n/** Multiply two polynomials (coefficients highest-degree first). */\nexport function gfPolyMultiply(p: readonly number[], q: readonly number[]): number[] {\n const out = new Array<number>(p.length + q.length - 1).fill(0);\n for (let i = 0; i < p.length; i++) for (let j = 0; j < q.length; j++) out[i + j] ^= gfMultiply(p[i], q[j]);\n return out;\n}\n"],"mappings":"AAKA,IAAM,EAAY,IAEZ,EAAM,IAAI,WAAW,GAAG,EACxB,EAAM,IAAI,WAAW,GAAG,EAE9B,CACE,IAAI,EAAI,EACR,IAAK,IAAI,EAAI,EAAG,EAAI,IAAK,IACvB,EAAI,GAAK,EACT,EAAI,GAAK,EACT,IAAM,EACF,EAAI,MAAO,GAAK,GAGtB,IAAK,IAAI,EAAI,IAAK,EAAI,IAAK,IAAK,EAAI,GAAK,EAAI,EAAI,IACnD,CAGA,SAAgB,WAAW,EAAW,EAAmB,CACvD,OAAO,IAAM,GAAK,IAAM,EAAI,EAAI,EAAI,EAAI,GAAK,EAAI,GACnD,CAGA,SAAgB,MAAM,EAAmB,CACvC,OAAO,EAAI,EAAI,IACjB,CAUA,SAAgB,eAAe,EAAsB,EAAgC,CACnF,IAAM,EAAU,MAAc,EAAE,OAAS,EAAE,OAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAC7D,IAAK,IAAI,EAAI,EAAG,EAAI,EAAE,OAAQ,IAAK,IAAK,IAAI,EAAI,EAAG,EAAI,EAAE,OAAQ,IAAK,EAAI,EAAI,IAAM,WAAW,EAAE,GAAI,EAAE,EAAE,EACzG,OAAO,CACT"}
|
package/dist/_matrix.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_matrix.cjs","names":[],"sources":["../src/_matrix.ts"],"sourcesContent":["import { alignmentPatternPositions } from './_tables';\n\n/**\n * Module placement (§7.7–7.9, Annex E): function patterns are drawn first and\n * recorded in `isFunction`, then the codeword bit stream fills the remaining\n * modules in a two-column zigzag starting bottom-right, skipping column 6.\n */\n\nexport interface QrGrid {\n /** Modules owned by function patterns
|
|
1
|
+
{"version":3,"file":"_matrix.cjs","names":[],"sources":["../src/_matrix.ts"],"sourcesContent":["import { alignmentPatternPositions } from './_tables';\n\n/**\n * Module placement (§7.7–7.9, Annex E): function patterns are drawn first and\n * recorded in `isFunction`, then the codeword bit stream fills the remaining\n * modules in a two-column zigzag starting bottom-right, skipping column 6.\n */\n\nexport interface QrGrid {\n /** Modules owned by function patterns: skipped by data placement and masks. */\n readonly isFunction: boolean[][];\n /** Final module colors; `true` = dark. Mutable during construction. */\n modules: boolean[][];\n readonly size: number;\n}\n\nexport function createGrid(size: number): QrGrid {\n return {\n isFunction: Array.from({ length: size }, () => new Array<boolean>(size).fill(false)),\n modules: Array.from({ length: size }, () => new Array<boolean>(size).fill(false)),\n size,\n };\n}\n\nconst setFunction = (grid: QrGrid, x: number, y: number, dark: boolean): void => {\n grid.modules[y][x] = dark;\n grid.isFunction[y][x] = true;\n};\n\n/** 7×7 finder pattern plus the one-module separator ring, centered at (x+3, y+3). */\nfunction drawFinder(grid: QrGrid, x: number, y: number): void {\n for (let dy = -4; dy <= 4; dy++)\n for (let dx = -4; dx <= 4; dx++) {\n const xx = x + 3 + dx;\n const yy = y + 3 + dy;\n if (xx < 0 || yy < 0 || xx >= grid.size || yy >= grid.size) continue;\n const dist = Math.max(Math.abs(dx), Math.abs(dy));\n setFunction(grid, xx, yy, dist !== 2 && dist !== 4);\n }\n}\n\n/** Alternating timing pattern along row/col 6, between the finders. */\nfunction drawTiming(grid: QrGrid): void {\n for (let i = 8; i < grid.size - 8; i++) {\n const dark = i % 2 === 0;\n if (!grid.isFunction[6][i]) setFunction(grid, i, 6, dark);\n if (!grid.isFunction[i][6]) setFunction(grid, 6, i, dark);\n }\n}\n\n/** 5×5 alignment pattern centered at (cx, cy). */\nfunction drawAlignment(grid: QrGrid, cx: number, cy: number): void {\n for (let dy = -2; dy <= 2; dy++)\n for (let dx = -2; dx <= 2; dx++) setFunction(grid, cx + dx, cy + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1);\n}\n\n/**\n * Reserve the 15 format-info modules around each finder (both copies) and the\n * 6×3 version-info blocks for v≥7: drawn later by `_format.ts`, but data\n * placement must skip them now.\n */\nfunction reserveFormatAreas(grid: QrGrid): void {\n const size = grid.size;\n // Around the top-left finder.\n for (let i = 0; i <= 8; i++) {\n if (i !== 6) {\n grid.isFunction[8][i] = true;\n grid.isFunction[i][8] = true;\n }\n }\n // Second copy: column 8 rows size-1..size-7 beside the bottom-left finder,\n // row 8 columns size-1..size-8 beside the top-right finder.\n for (let i = 0; i < 7; i++) grid.isFunction[size - 1 - i][8] = true;\n for (let i = 0; i < 8; i++) grid.isFunction[8][size - 1 - i] = true;\n // Always-dark module below the bottom-left format strip.\n grid.isFunction[size - 8][8] = true;\n}\n\nfunction reserveVersionAreas(grid: QrGrid, version: number): void {\n if (version < 7) return;\n const size = grid.size;\n for (let i = 0; i < 18; i++) {\n const a = size - 11 + (i % 3);\n const b = Math.floor(i / 3);\n grid.isFunction[b][a] = true; // top-right block\n grid.isFunction[a][b] = true; // bottom-left block\n }\n}\n\n/** Draw every function pattern and mark reserved areas. */\nexport function drawFunctionPatterns(grid: QrGrid, version: number): void {\n drawFinder(grid, 0, 0);\n drawFinder(grid, grid.size - 7, 0);\n drawFinder(grid, 0, grid.size - 7);\n drawTiming(grid);\n const positions = alignmentPatternPositions(version);\n for (const cy of positions)\n for (const cx of positions) {\n // Skip the three corners covered by finder patterns.\n const isCorner =\n (cx === 6 && cy === 6) || (cx === 6 && cy === grid.size - 7) || (cx === grid.size - 7 && cy === 6);\n if (!isCorner) drawAlignment(grid, cx, cy);\n }\n reserveFormatAreas(grid);\n reserveVersionAreas(grid, version);\n}\n\n/** Place codeword bits into non-function modules via the zigzag scan. */\nexport function placeData(grid: QrGrid, codewords: readonly number[]): void {\n const size = grid.size;\n const totalBits = codewords.length * 8;\n let bitIndex = 0;\n let upward = true;\n for (let right = size - 1; right >= 1; right -= 2) {\n if (right === 6) right = 5; // skip the vertical timing column\n for (let vert = 0; vert < size; vert++) {\n for (let j = 0; j < 2; j++) {\n const x = right - j;\n const y = upward ? size - 1 - vert : vert;\n if (grid.isFunction[y][x]) continue;\n grid.modules[y][x] = bitIndex < totalBits && ((codewords[bitIndex >>> 3] >>> (7 - (bitIndex & 7))) & 1) === 1;\n bitIndex++;\n }\n }\n upward = !upward;\n }\n}\n"],"mappings":"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"}
|
package/dist/_matrix.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* modules in a two-column zigzag starting bottom-right, skipping column 6.
|
|
5
5
|
*/
|
|
6
6
|
export interface QrGrid {
|
|
7
|
-
/** Modules owned by function patterns
|
|
7
|
+
/** Modules owned by function patterns: skipped by data placement and masks. */
|
|
8
8
|
readonly isFunction: boolean[][];
|
|
9
9
|
/** Final module colors; `true` = dark. Mutable during construction. */
|
|
10
10
|
modules: boolean[][];
|
package/dist/_matrix.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_matrix.d.ts","sourceRoot":"","sources":["../src/_matrix.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,WAAW,MAAM;IACrB
|
|
1
|
+
{"version":3,"file":"_matrix.d.ts","sourceRoot":"","sources":["../src/_matrix.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,WAAW,MAAM;IACrB,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;IACjC,uEAAuE;IACvE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM/C;AAmED,2DAA2D;AAC3D,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAexE;AAED,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAkB1E"}
|
package/dist/_matrix.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_matrix.js","names":[],"sources":["../src/_matrix.ts"],"sourcesContent":["import { alignmentPatternPositions } from './_tables';\n\n/**\n * Module placement (§7.7–7.9, Annex E): function patterns are drawn first and\n * recorded in `isFunction`, then the codeword bit stream fills the remaining\n * modules in a two-column zigzag starting bottom-right, skipping column 6.\n */\n\nexport interface QrGrid {\n /** Modules owned by function patterns
|
|
1
|
+
{"version":3,"file":"_matrix.js","names":[],"sources":["../src/_matrix.ts"],"sourcesContent":["import { alignmentPatternPositions } from './_tables';\n\n/**\n * Module placement (§7.7–7.9, Annex E): function patterns are drawn first and\n * recorded in `isFunction`, then the codeword bit stream fills the remaining\n * modules in a two-column zigzag starting bottom-right, skipping column 6.\n */\n\nexport interface QrGrid {\n /** Modules owned by function patterns: skipped by data placement and masks. */\n readonly isFunction: boolean[][];\n /** Final module colors; `true` = dark. Mutable during construction. */\n modules: boolean[][];\n readonly size: number;\n}\n\nexport function createGrid(size: number): QrGrid {\n return {\n isFunction: Array.from({ length: size }, () => new Array<boolean>(size).fill(false)),\n modules: Array.from({ length: size }, () => new Array<boolean>(size).fill(false)),\n size,\n };\n}\n\nconst setFunction = (grid: QrGrid, x: number, y: number, dark: boolean): void => {\n grid.modules[y][x] = dark;\n grid.isFunction[y][x] = true;\n};\n\n/** 7×7 finder pattern plus the one-module separator ring, centered at (x+3, y+3). */\nfunction drawFinder(grid: QrGrid, x: number, y: number): void {\n for (let dy = -4; dy <= 4; dy++)\n for (let dx = -4; dx <= 4; dx++) {\n const xx = x + 3 + dx;\n const yy = y + 3 + dy;\n if (xx < 0 || yy < 0 || xx >= grid.size || yy >= grid.size) continue;\n const dist = Math.max(Math.abs(dx), Math.abs(dy));\n setFunction(grid, xx, yy, dist !== 2 && dist !== 4);\n }\n}\n\n/** Alternating timing pattern along row/col 6, between the finders. */\nfunction drawTiming(grid: QrGrid): void {\n for (let i = 8; i < grid.size - 8; i++) {\n const dark = i % 2 === 0;\n if (!grid.isFunction[6][i]) setFunction(grid, i, 6, dark);\n if (!grid.isFunction[i][6]) setFunction(grid, 6, i, dark);\n }\n}\n\n/** 5×5 alignment pattern centered at (cx, cy). */\nfunction drawAlignment(grid: QrGrid, cx: number, cy: number): void {\n for (let dy = -2; dy <= 2; dy++)\n for (let dx = -2; dx <= 2; dx++) setFunction(grid, cx + dx, cy + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1);\n}\n\n/**\n * Reserve the 15 format-info modules around each finder (both copies) and the\n * 6×3 version-info blocks for v≥7: drawn later by `_format.ts`, but data\n * placement must skip them now.\n */\nfunction reserveFormatAreas(grid: QrGrid): void {\n const size = grid.size;\n // Around the top-left finder.\n for (let i = 0; i <= 8; i++) {\n if (i !== 6) {\n grid.isFunction[8][i] = true;\n grid.isFunction[i][8] = true;\n }\n }\n // Second copy: column 8 rows size-1..size-7 beside the bottom-left finder,\n // row 8 columns size-1..size-8 beside the top-right finder.\n for (let i = 0; i < 7; i++) grid.isFunction[size - 1 - i][8] = true;\n for (let i = 0; i < 8; i++) grid.isFunction[8][size - 1 - i] = true;\n // Always-dark module below the bottom-left format strip.\n grid.isFunction[size - 8][8] = true;\n}\n\nfunction reserveVersionAreas(grid: QrGrid, version: number): void {\n if (version < 7) return;\n const size = grid.size;\n for (let i = 0; i < 18; i++) {\n const a = size - 11 + (i % 3);\n const b = Math.floor(i / 3);\n grid.isFunction[b][a] = true; // top-right block\n grid.isFunction[a][b] = true; // bottom-left block\n }\n}\n\n/** Draw every function pattern and mark reserved areas. */\nexport function drawFunctionPatterns(grid: QrGrid, version: number): void {\n drawFinder(grid, 0, 0);\n drawFinder(grid, grid.size - 7, 0);\n drawFinder(grid, 0, grid.size - 7);\n drawTiming(grid);\n const positions = alignmentPatternPositions(version);\n for (const cy of positions)\n for (const cx of positions) {\n // Skip the three corners covered by finder patterns.\n const isCorner =\n (cx === 6 && cy === 6) || (cx === 6 && cy === grid.size - 7) || (cx === grid.size - 7 && cy === 6);\n if (!isCorner) drawAlignment(grid, cx, cy);\n }\n reserveFormatAreas(grid);\n reserveVersionAreas(grid, version);\n}\n\n/** Place codeword bits into non-function modules via the zigzag scan. */\nexport function placeData(grid: QrGrid, codewords: readonly number[]): void {\n const size = grid.size;\n const totalBits = codewords.length * 8;\n let bitIndex = 0;\n let upward = true;\n for (let right = size - 1; right >= 1; right -= 2) {\n if (right === 6) right = 5; // skip the vertical timing column\n for (let vert = 0; vert < size; vert++) {\n for (let j = 0; j < 2; j++) {\n const x = right - j;\n const y = upward ? size - 1 - vert : vert;\n if (grid.isFunction[y][x]) continue;\n grid.modules[y][x] = bitIndex < totalBits && ((codewords[bitIndex >>> 3] >>> (7 - (bitIndex & 7))) & 1) === 1;\n bitIndex++;\n }\n }\n upward = !upward;\n }\n}\n"],"mappings":"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"}
|
package/dist/_segments.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_segments.cjs","names":[],"sources":["../src/_segments.ts"],"sourcesContent":["import { ALPHANUMERIC_CHARSET, CHAR_COUNT_BITS, dataCodewords, MODE_BITS, versionGroup } from './_tables';\nimport type { QrErrorCorrection, QrMode } from './types';\n\n/**\n * Data-segment assembly: one segment (single mode) covering the whole input,\n * followed by terminator, byte alignment, and 0xEC/0x11 padding (§7.4–7.5).\n * Kanji and multi-segment optimization are out of scope.\n */\n\nconst textEncoder = new TextEncoder();\n\n/**\n * Payload prepared for its mode: text for numeric/alphanumeric, raw bytes for\n * byte mode. Byte mode never round-trips through a string, so invalid UTF-8\n * input survives encoding untouched.\n */\nexport type QrPayload =\n | { readonly mode: 'numeric' | 'alphanumeric'; readonly text: string }\n | { readonly mode: 'byte'; readonly bytes: Uint8Array };\n\n/** Interpret `text` as `mode
|
|
1
|
+
{"version":3,"file":"_segments.cjs","names":[],"sources":["../src/_segments.ts"],"sourcesContent":["import { ALPHANUMERIC_CHARSET, CHAR_COUNT_BITS, dataCodewords, MODE_BITS, versionGroup } from './_tables';\nimport type { QrErrorCorrection, QrMode } from './types';\n\n/**\n * Data-segment assembly: one segment (single mode) covering the whole input,\n * followed by terminator, byte alignment, and 0xEC/0x11 padding (§7.4–7.5).\n * Kanji and multi-segment optimization are out of scope.\n */\n\nconst textEncoder = new TextEncoder();\n\n/**\n * Payload prepared for its mode: text for numeric/alphanumeric, raw bytes for\n * byte mode. Byte mode never round-trips through a string, so invalid UTF-8\n * input survives encoding untouched.\n */\nexport type QrPayload =\n | { readonly mode: 'numeric' | 'alphanumeric'; readonly text: string }\n | { readonly mode: 'byte'; readonly bytes: Uint8Array };\n\n/** Interpret `text` as `mode`: UTF-8-encoding only for byte mode. */\nexport const payloadFromText = (text: string, mode: QrMode): QrPayload =>\n mode === 'byte' ? { bytes: textEncoder.encode(text), mode: 'byte' } : { mode, text };\n\n/** Raw binary payload; always byte mode. */\nexport const payloadFromBytes = (bytes: Uint8Array): QrPayload => ({ bytes, mode: 'byte' });\n\n/** Value carried in the character-count field. */\nexport function payloadLength(payload: QrPayload): number {\n return payload.mode === 'byte' ? payload.bytes.length : payload.text.length;\n}\n\n/** Growable bit stream; `bytes` is valid only after `padToByte()`. */\nexport class BitStream {\n private bits: number[] = [];\n\n get length(): number {\n return this.bits.length;\n }\n\n append(value: number, width: number): void {\n for (let i = width - 1; i >= 0; i--) this.bits.push((value >>> i) & 1);\n }\n\n padToByte(): void {\n while (this.bits.length % 8 !== 0) this.bits.push(0);\n }\n\n toBytes(): number[] {\n const out: number[] = [];\n for (let i = 0; i < this.bits.length; i += 8) {\n let b = 0;\n for (let j = 0; j < 8; j++) b = (b << 1) | this.bits[i + j];\n out.push(b);\n }\n return out;\n }\n}\n\n/** Most compact mode able to encode the whole text. */\nexport function detectMode(text: string): QrMode {\n if (/^\\d+$/.test(text)) return 'numeric';\n for (const ch of text) if (!ALPHANUMERIC_CHARSET.includes(ch)) return 'byte';\n return 'alphanumeric';\n}\n\n/** Payload bits for the segment body (without mode/count headers). */\nexport function dataBitLength(payload: QrPayload): number {\n switch (payload.mode) {\n case 'numeric':\n return (\n Math.floor(payload.text.length / 3) * 10 +\n (payload.text.length % 3 === 1 ? 4 : payload.text.length % 3 === 2 ? 7 : 0)\n );\n case 'alphanumeric':\n return Math.floor(payload.text.length / 2) * 11 + (payload.text.length % 2) * 6;\n case 'byte':\n return payload.bytes.length * 8;\n }\n}\n\n/** Append mode indicator, char count, and payload bits. */\nexport function appendSegment(stream: BitStream, payload: QrPayload, version: number): void {\n stream.append(MODE_BITS[payload.mode], 4);\n stream.append(payloadLength(payload), CHAR_COUNT_BITS[payload.mode][versionGroup(version)]);\n switch (payload.mode) {\n case 'numeric':\n for (let i = 0; i < payload.text.length; ) {\n const n = Math.min(3, payload.text.length - i);\n stream.append(Number.parseInt(payload.text.slice(i, i + n), 10), n === 3 ? 10 : n === 2 ? 7 : 4);\n i += n;\n }\n break;\n case 'alphanumeric':\n for (let i = 0; i < payload.text.length; ) {\n if (i + 1 < payload.text.length) {\n stream.append(\n ALPHANUMERIC_CHARSET.indexOf(payload.text[i]) * 45 + ALPHANUMERIC_CHARSET.indexOf(payload.text[i + 1]),\n 11,\n );\n i += 2;\n } else {\n stream.append(ALPHANUMERIC_CHARSET.indexOf(payload.text[i]), 6);\n i += 1;\n }\n }\n break;\n case 'byte':\n for (const b of payload.bytes) stream.append(b, 8);\n break;\n }\n}\n\n/** Capacity in bits for the data area of (version, level). */\nexport const dataCapacityBits = (version: number, level: QrErrorCorrection): number =>\n dataCodewords(version, level) * 8;\n\n/** Bits a segment occupies at `version`: header + payload, before terminator. */\nexport function segmentBits(payload: QrPayload, version: number): number {\n return 4 + CHAR_COUNT_BITS[payload.mode][versionGroup(version)] + dataBitLength(payload);\n}\n\n/**\n * Full data-codeword sequence for (version, level): segment + terminator +\n * alignment + pad bytes. Caller guarantees the segment fits.\n */\nexport function buildDataCodewords(payload: QrPayload, version: number, level: QrErrorCorrection): number[] {\n const stream = new BitStream();\n appendSegment(stream, payload, version);\n const capacity = dataCapacityBits(version, level);\n stream.append(0, Math.min(4, capacity - stream.length)); // terminator\n stream.padToByte();\n const bytes = stream.toBytes();\n const pad = [0xec, 0x11];\n for (let i = 0; bytes.length < dataCodewords(version, level); i++) bytes.push(pad[i % 2]);\n return bytes;\n}\n"],"mappings":"iCASA,IAAM,EAAc,IAAI,YAYX,iBAAmB,EAAc,IAC5C,IAAS,OAAS,CAAE,MAAO,EAAY,OAAO,CAAI,EAAG,KAAM,MAAO,EAAI,CAAE,OAAM,MAAK,EAGxE,iBAAoB,IAAkC,CAAE,QAAO,KAAM,MAAO,GAGzF,SAAgB,cAAc,EAA4B,CACxD,OAAO,EAAQ,OAAS,OAAS,EAAQ,MAAM,OAAS,EAAQ,KAAK,MACvE,CAGA,IAAa,UAAb,KAAuB,CACrB,KAAyB,CAAC,EAE1B,IAAI,QAAiB,CACnB,OAAO,KAAK,KAAK,MACnB,CAEA,OAAO,EAAe,EAAqB,CACzC,IAAK,IAAI,EAAI,EAAQ,EAAG,GAAK,EAAG,IAAK,KAAK,KAAK,KAAM,IAAU,EAAK,CAAC,CACvE,CAEA,WAAkB,CAChB,KAAO,KAAK,KAAK,OAAS,GAAM,GAAG,KAAK,KAAK,KAAK,CAAC,CACrD,CAEA,SAAoB,CAClB,IAAM,EAAgB,CAAC,EACvB,IAAK,IAAI,EAAI,EAAG,EAAI,KAAK,KAAK,OAAQ,GAAK,EAAG,CAC5C,IAAI,EAAI,EACR,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,IAAK,EAAK,GAAK,EAAK,KAAK,KAAK,EAAI,GACzD,EAAI,KAAK,CAAC,CACZ,CACA,OAAO,CACT,CACF,EAGA,SAAgB,WAAW,EAAsB,CAC/C,GAAI,QAAQ,KAAK,CAAI,EAAG,MAAO,UAC/B,IAAK,IAAM,KAAM,EAAM,GAAI,CAAA,gDAAsB,SAAS,CAAE,EAAG,MAAO,OACtE,MAAO,cACT,CAGA,SAAgB,cAAc,EAA4B,CACxD,OAAQ,EAAQ,KAAhB,CACE,IAAK,UACH,OACE,KAAK,MAAM,EAAQ,KAAK,OAAS,CAAC,EAAI,IACrC,EAAQ,KAAK,OAAS,GAAM,EAAI,EAAI,EAAQ,KAAK,OAAS,GAAM,EAAI,EAAI,GAE7E,IAAK,eACH,OAAO,KAAK,MAAM,EAAQ,KAAK,OAAS,CAAC,EAAI,GAAM,EAAQ,KAAK,OAAS,EAAK,EAChF,IAAK,OACH,OAAO,EAAQ,MAAM,OAAS,CAClC,CACF,CAGA,SAAgB,cAAc,EAAmB,EAAoB,EAAuB,CAG1F,OAFA,EAAO,OAAO,EAAA,UAAU,EAAQ,MAAO,CAAC,EACxC,EAAO,OAAO,cAAc,CAAO,EAAG,EAAA,gBAAgB,EAAQ,KAAK,CAAC,EAAA,aAAa,CAAO,EAAE,EAClF,EAAQ,KAAhB,CACE,IAAK,UACH,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,KAAK,QAAU,CACzC,IAAM,EAAI,KAAK,IAAI,EAAG,EAAQ,KAAK,OAAS,CAAC,EAC7C,EAAO,OAAO,OAAO,SAAS,EAAQ,KAAK,MAAM,EAAG,EAAI,CAAC,EAAG,EAAE,EAAG,IAAM,EAAI,GAAK,IAAM,EAAI,EAAI,CAAC,EAC/F,GAAK,CACP,CACA,MACF,IAAK,eACH,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,KAAK,QAC3B,EAAI,EAAI,EAAQ,KAAK,QACvB,EAAO,OACL,EAAA,qBAAqB,QAAQ,EAAQ,KAAK,EAAE,EAAI,GAAK,EAAA,qBAAqB,QAAQ,EAAQ,KAAK,EAAI,EAAE,EACrG,EACF,EACA,GAAK,IAEL,EAAO,OAAO,EAAA,qBAAqB,QAAQ,EAAQ,KAAK,EAAE,EAAG,CAAC,EAC9D,GAAK,GAGT,MACF,IAAK,OACH,IAAK,IAAM,KAAK,EAAQ,MAAO,EAAO,OAAO,EAAG,CAAC,CAErD,CACF,CAGA,IAAa,kBAAoB,EAAiB,IAChD,EAAA,cAAc,EAAS,CAAK,EAAI,EAGlC,SAAgB,YAAY,EAAoB,EAAyB,CACvE,MAAO,GAAI,EAAA,gBAAgB,EAAQ,KAAK,CAAC,EAAA,aAAa,CAAO,GAAK,cAAc,CAAO,CACzF,CAMA,SAAgB,mBAAmB,EAAoB,EAAiB,EAAoC,CAC1G,IAAM,EAAS,IAAI,UACnB,cAAc,EAAQ,EAAS,CAAO,EACtC,IAAM,EAAW,iBAAiB,EAAS,CAAK,EAChD,EAAO,OAAO,EAAG,KAAK,IAAI,EAAG,EAAW,EAAO,MAAM,CAAC,EACtD,EAAO,UAAU,EACjB,IAAM,EAAQ,EAAO,QAAQ,EACvB,EAAM,CAAC,IAAM,EAAI,EACvB,IAAK,IAAI,EAAI,EAAG,EAAM,OAAS,EAAA,cAAc,EAAS,CAAK,EAAG,IAAK,EAAM,KAAK,EAAI,EAAI,EAAE,EACxF,OAAO,CACT"}
|
package/dist/_segments.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type QrPayload = {
|
|
|
11
11
|
readonly mode: 'byte';
|
|
12
12
|
readonly bytes: Uint8Array;
|
|
13
13
|
};
|
|
14
|
-
/** Interpret `text` as `mode
|
|
14
|
+
/** Interpret `text` as `mode`: UTF-8-encoding only for byte mode. */
|
|
15
15
|
export declare const payloadFromText: (text: string, mode: QrMode) => QrPayload;
|
|
16
16
|
/** Raw binary payload; always byte mode. */
|
|
17
17
|
export declare const payloadFromBytes: (bytes: Uint8Array) => QrPayload;
|
package/dist/_segments.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_segments.d.ts","sourceRoot":"","sources":["../src/_segments.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAUzD;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAE1D,
|
|
1
|
+
{"version":3,"file":"_segments.d.ts","sourceRoot":"","sources":["../src/_segments.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAUzD;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAE1D,qEAAqE;AACrE,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,SACyB,CAAC;AAEvF,4CAA4C;AAC5C,eAAO,MAAM,gBAAgB,GAAI,OAAO,UAAU,KAAG,SAAsC,CAAC;AAE5F,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,CAExD;AAED,sEAAsE;AACtE,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAgB;IAE5B,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI1C,SAAS,IAAI,IAAI;IAIjB,OAAO,IAAI,MAAM,EAAE;CASpB;AAED,uDAAuD;AACvD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,CAYxD;AAED,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CA6B1F;AAED,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,OAAO,iBAAiB,KAAG,MAC1C,CAAC;AAEpC,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAU1G"}
|
package/dist/_segments.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_segments.js","names":[],"sources":["../src/_segments.ts"],"sourcesContent":["import { ALPHANUMERIC_CHARSET, CHAR_COUNT_BITS, dataCodewords, MODE_BITS, versionGroup } from './_tables';\nimport type { QrErrorCorrection, QrMode } from './types';\n\n/**\n * Data-segment assembly: one segment (single mode) covering the whole input,\n * followed by terminator, byte alignment, and 0xEC/0x11 padding (§7.4–7.5).\n * Kanji and multi-segment optimization are out of scope.\n */\n\nconst textEncoder = new TextEncoder();\n\n/**\n * Payload prepared for its mode: text for numeric/alphanumeric, raw bytes for\n * byte mode. Byte mode never round-trips through a string, so invalid UTF-8\n * input survives encoding untouched.\n */\nexport type QrPayload =\n | { readonly mode: 'numeric' | 'alphanumeric'; readonly text: string }\n | { readonly mode: 'byte'; readonly bytes: Uint8Array };\n\n/** Interpret `text` as `mode
|
|
1
|
+
{"version":3,"file":"_segments.js","names":[],"sources":["../src/_segments.ts"],"sourcesContent":["import { ALPHANUMERIC_CHARSET, CHAR_COUNT_BITS, dataCodewords, MODE_BITS, versionGroup } from './_tables';\nimport type { QrErrorCorrection, QrMode } from './types';\n\n/**\n * Data-segment assembly: one segment (single mode) covering the whole input,\n * followed by terminator, byte alignment, and 0xEC/0x11 padding (§7.4–7.5).\n * Kanji and multi-segment optimization are out of scope.\n */\n\nconst textEncoder = new TextEncoder();\n\n/**\n * Payload prepared for its mode: text for numeric/alphanumeric, raw bytes for\n * byte mode. Byte mode never round-trips through a string, so invalid UTF-8\n * input survives encoding untouched.\n */\nexport type QrPayload =\n | { readonly mode: 'numeric' | 'alphanumeric'; readonly text: string }\n | { readonly mode: 'byte'; readonly bytes: Uint8Array };\n\n/** Interpret `text` as `mode`: UTF-8-encoding only for byte mode. */\nexport const payloadFromText = (text: string, mode: QrMode): QrPayload =>\n mode === 'byte' ? { bytes: textEncoder.encode(text), mode: 'byte' } : { mode, text };\n\n/** Raw binary payload; always byte mode. */\nexport const payloadFromBytes = (bytes: Uint8Array): QrPayload => ({ bytes, mode: 'byte' });\n\n/** Value carried in the character-count field. */\nexport function payloadLength(payload: QrPayload): number {\n return payload.mode === 'byte' ? payload.bytes.length : payload.text.length;\n}\n\n/** Growable bit stream; `bytes` is valid only after `padToByte()`. */\nexport class BitStream {\n private bits: number[] = [];\n\n get length(): number {\n return this.bits.length;\n }\n\n append(value: number, width: number): void {\n for (let i = width - 1; i >= 0; i--) this.bits.push((value >>> i) & 1);\n }\n\n padToByte(): void {\n while (this.bits.length % 8 !== 0) this.bits.push(0);\n }\n\n toBytes(): number[] {\n const out: number[] = [];\n for (let i = 0; i < this.bits.length; i += 8) {\n let b = 0;\n for (let j = 0; j < 8; j++) b = (b << 1) | this.bits[i + j];\n out.push(b);\n }\n return out;\n }\n}\n\n/** Most compact mode able to encode the whole text. */\nexport function detectMode(text: string): QrMode {\n if (/^\\d+$/.test(text)) return 'numeric';\n for (const ch of text) if (!ALPHANUMERIC_CHARSET.includes(ch)) return 'byte';\n return 'alphanumeric';\n}\n\n/** Payload bits for the segment body (without mode/count headers). */\nexport function dataBitLength(payload: QrPayload): number {\n switch (payload.mode) {\n case 'numeric':\n return (\n Math.floor(payload.text.length / 3) * 10 +\n (payload.text.length % 3 === 1 ? 4 : payload.text.length % 3 === 2 ? 7 : 0)\n );\n case 'alphanumeric':\n return Math.floor(payload.text.length / 2) * 11 + (payload.text.length % 2) * 6;\n case 'byte':\n return payload.bytes.length * 8;\n }\n}\n\n/** Append mode indicator, char count, and payload bits. */\nexport function appendSegment(stream: BitStream, payload: QrPayload, version: number): void {\n stream.append(MODE_BITS[payload.mode], 4);\n stream.append(payloadLength(payload), CHAR_COUNT_BITS[payload.mode][versionGroup(version)]);\n switch (payload.mode) {\n case 'numeric':\n for (let i = 0; i < payload.text.length; ) {\n const n = Math.min(3, payload.text.length - i);\n stream.append(Number.parseInt(payload.text.slice(i, i + n), 10), n === 3 ? 10 : n === 2 ? 7 : 4);\n i += n;\n }\n break;\n case 'alphanumeric':\n for (let i = 0; i < payload.text.length; ) {\n if (i + 1 < payload.text.length) {\n stream.append(\n ALPHANUMERIC_CHARSET.indexOf(payload.text[i]) * 45 + ALPHANUMERIC_CHARSET.indexOf(payload.text[i + 1]),\n 11,\n );\n i += 2;\n } else {\n stream.append(ALPHANUMERIC_CHARSET.indexOf(payload.text[i]), 6);\n i += 1;\n }\n }\n break;\n case 'byte':\n for (const b of payload.bytes) stream.append(b, 8);\n break;\n }\n}\n\n/** Capacity in bits for the data area of (version, level). */\nexport const dataCapacityBits = (version: number, level: QrErrorCorrection): number =>\n dataCodewords(version, level) * 8;\n\n/** Bits a segment occupies at `version`: header + payload, before terminator. */\nexport function segmentBits(payload: QrPayload, version: number): number {\n return 4 + CHAR_COUNT_BITS[payload.mode][versionGroup(version)] + dataBitLength(payload);\n}\n\n/**\n * Full data-codeword sequence for (version, level): segment + terminator +\n * alignment + pad bytes. Caller guarantees the segment fits.\n */\nexport function buildDataCodewords(payload: QrPayload, version: number, level: QrErrorCorrection): number[] {\n const stream = new BitStream();\n appendSegment(stream, payload, version);\n const capacity = dataCapacityBits(version, level);\n stream.append(0, Math.min(4, capacity - stream.length)); // terminator\n stream.padToByte();\n const bytes = stream.toBytes();\n const pad = [0xec, 0x11];\n for (let i = 0; bytes.length < dataCodewords(version, level); i++) bytes.push(pad[i % 2]);\n return bytes;\n}\n"],"mappings":"6HASA,IAAM,EAAc,IAAI,YAYX,iBAAmB,EAAc,IAC5C,IAAS,OAAS,CAAE,MAAO,EAAY,OAAO,CAAI,EAAG,KAAM,MAAO,EAAI,CAAE,OAAM,MAAK,EAGxE,iBAAoB,IAAkC,CAAE,QAAO,KAAM,MAAO,GAGzF,SAAgB,cAAc,EAA4B,CACxD,OAAO,EAAQ,OAAS,OAAS,EAAQ,MAAM,OAAS,EAAQ,KAAK,MACvE,CAGA,IAAa,UAAb,KAAuB,CACrB,KAAyB,CAAC,EAE1B,IAAI,QAAiB,CACnB,OAAO,KAAK,KAAK,MACnB,CAEA,OAAO,EAAe,EAAqB,CACzC,IAAK,IAAI,EAAI,EAAQ,EAAG,GAAK,EAAG,IAAK,KAAK,KAAK,KAAM,IAAU,EAAK,CAAC,CACvE,CAEA,WAAkB,CAChB,KAAO,KAAK,KAAK,OAAS,GAAM,GAAG,KAAK,KAAK,KAAK,CAAC,CACrD,CAEA,SAAoB,CAClB,IAAM,EAAgB,CAAC,EACvB,IAAK,IAAI,EAAI,EAAG,EAAI,KAAK,KAAK,OAAQ,GAAK,EAAG,CAC5C,IAAI,EAAI,EACR,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,IAAK,EAAK,GAAK,EAAK,KAAK,KAAK,EAAI,GACzD,EAAI,KAAK,CAAC,CACZ,CACA,OAAO,CACT,CACF,EAGA,SAAgB,WAAW,EAAsB,CAC/C,GAAI,QAAQ,KAAK,CAAI,EAAG,MAAO,UAC/B,IAAK,IAAM,KAAM,EAAM,GAAI,CAAA,gDAAsB,SAAS,CAAE,EAAG,MAAO,OACtE,MAAO,cACT,CAGA,SAAgB,cAAc,EAA4B,CACxD,OAAQ,EAAQ,KAAhB,CACE,IAAK,UACH,OACE,KAAK,MAAM,EAAQ,KAAK,OAAS,CAAC,EAAI,IACrC,EAAQ,KAAK,OAAS,GAAM,EAAI,EAAI,EAAQ,KAAK,OAAS,GAAM,EAAI,EAAI,GAE7E,IAAK,eACH,OAAO,KAAK,MAAM,EAAQ,KAAK,OAAS,CAAC,EAAI,GAAM,EAAQ,KAAK,OAAS,EAAK,EAChF,IAAK,OACH,OAAO,EAAQ,MAAM,OAAS,CAClC,CACF,CAGA,SAAgB,cAAc,EAAmB,EAAoB,EAAuB,CAG1F,OAFA,EAAO,OAAO,EAAU,EAAQ,MAAO,CAAC,EACxC,EAAO,OAAO,cAAc,CAAO,EAAG,EAAgB,EAAQ,KAAK,CAAC,EAAa,CAAO,EAAE,EAClF,EAAQ,KAAhB,CACE,IAAK,UACH,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,KAAK,QAAU,CACzC,IAAM,EAAI,KAAK,IAAI,EAAG,EAAQ,KAAK,OAAS,CAAC,EAC7C,EAAO,OAAO,OAAO,SAAS,EAAQ,KAAK,MAAM,EAAG,EAAI,CAAC,EAAG,EAAE,EAAG,IAAM,EAAI,GAAK,IAAM,EAAI,EAAI,CAAC,EAC/F,GAAK,CACP,CACA,MACF,IAAK,eACH,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,KAAK,QAC3B,EAAI,EAAI,EAAQ,KAAK,QACvB,EAAO,OACL,EAAqB,QAAQ,EAAQ,KAAK,EAAE,EAAI,GAAK,EAAqB,QAAQ,EAAQ,KAAK,EAAI,EAAE,EACrG,EACF,EACA,GAAK,IAEL,EAAO,OAAO,EAAqB,QAAQ,EAAQ,KAAK,EAAE,EAAG,CAAC,EAC9D,GAAK,GAGT,MACF,IAAK,OACH,IAAK,IAAM,KAAK,EAAQ,MAAO,EAAO,OAAO,EAAG,CAAC,CAErD,CACF,CAGA,IAAa,kBAAoB,EAAiB,IAChD,EAAc,EAAS,CAAK,EAAI,EAGlC,SAAgB,YAAY,EAAoB,EAAyB,CACvE,MAAO,GAAI,EAAgB,EAAQ,KAAK,CAAC,EAAa,CAAO,GAAK,cAAc,CAAO,CACzF,CAMA,SAAgB,mBAAmB,EAAoB,EAAiB,EAAoC,CAC1G,IAAM,EAAS,IAAI,UACnB,cAAc,EAAQ,EAAS,CAAO,EACtC,IAAM,EAAW,iBAAiB,EAAS,CAAK,EAChD,EAAO,OAAO,EAAG,KAAK,IAAI,EAAG,EAAW,EAAO,MAAM,CAAC,EACtD,EAAO,UAAU,EACjB,IAAM,EAAQ,EAAO,QAAQ,EACvB,EAAM,CAAC,IAAM,EAAI,EACvB,IAAK,IAAI,EAAI,EAAG,EAAM,OAAS,EAAc,EAAS,CAAK,EAAG,IAAK,EAAM,KAAK,EAAI,EAAI,EAAE,EACxF,OAAO,CACT"}
|
package/dist/_tables.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_tables.cjs","names":[],"sources":["../src/_tables.ts"],"sourcesContent":["import type { QrErrorCorrection, QrMode } from './types';\n\n/**\n * QR Model 2 lookup tables, transcribed from ISO/IEC 18004:2015:\n * - `EC_CODEWORDS_PER_BLOCK` / `NUM_EC_BLOCKS
|
|
1
|
+
{"version":3,"file":"_tables.cjs","names":[],"sources":["../src/_tables.ts"],"sourcesContent":["import type { QrErrorCorrection, QrMode } from './types';\n\n/**\n * QR Model 2 lookup tables, transcribed from ISO/IEC 18004:2015:\n * - `EC_CODEWORDS_PER_BLOCK` / `NUM_EC_BLOCKS`: Table 9 (error-correction\n * characteristics). Stored as per-block EC codewords and block count; the\n * group-1/group-2 split is derived, since all blocks share one EC length.\n * - `alignmentPatternPositions`: Table E.1, computed by the spec formula.\n * - `CHAR_COUNT_BITS`: Table 3 (character-count indicator bit widths).\n * - `FORMAT_EC_BITS`: Table 10 (2-bit level field inside format information).\n *\n * `tables.test.ts` cross-checks every entry against the raw-module formula, so\n * a transcription slip fails the consistency test before the decode oracle runs.\n */\n\n/** Index order used by the table rows below. */\nexport const EC_LEVELS = ['L', 'M', 'Q', 'H'] as const;\n\nexport const ALPHANUMERIC_CHARSET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';\n\n/** Mode indicators (Table 2). */\nexport const MODE_BITS: Record<QrMode, number> = {\n alphanumeric: 0b0010,\n byte: 0b0100,\n numeric: 0b0001,\n};\n\n/** Character-count indicator widths for version groups 1–9 / 10–26 / 27–40. */\nexport const CHAR_COUNT_BITS: Record<QrMode, readonly [number, number, number]> = {\n alphanumeric: [9, 11, 13],\n byte: [8, 16, 16],\n numeric: [10, 12, 14],\n};\n\n/** EC level bits inside format information (L=01, M=00, Q=11, H=10). */\nexport const FORMAT_EC_BITS: Record<QrErrorCorrection, number> = { H: 0b10, L: 0b01, M: 0b00, Q: 0b11 };\n\n/** Row 0 = L, row 1 = M, row 2 = Q, row 3 = H; column 0 unused (versions start at 1). */\nexport const EC_CODEWORDS_PER_BLOCK: ReadonlyArray<ReadonlyArray<number>> = [\n // prettier-ignore\n [\n -1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30,\n 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,\n ],\n // prettier-ignore\n [\n -1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28,\n 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n ],\n // prettier-ignore\n [\n -1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30,\n 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,\n ],\n // prettier-ignore\n [\n -1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30,\n 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,\n ],\n];\n\nexport const NUM_EC_BLOCKS: ReadonlyArray<ReadonlyArray<number>> = [\n // prettier-ignore\n [\n -1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19,\n 19, 20, 21, 22, 24, 25,\n ],\n // prettier-ignore\n [\n -1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31,\n 33, 35, 37, 38, 40, 43, 45, 47, 49,\n ],\n // prettier-ignore\n [\n -1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43,\n 45, 48, 51, 53, 56, 59, 62, 65, 68,\n ],\n // prettier-ignore\n [\n -1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48,\n 51, 56, 59, 62, 65, 68, 71, 74, 77, 81,\n ],\n];\n\nconst ecIndex = (level: QrErrorCorrection): number => EC_LEVELS.indexOf(level);\n\n/** Total modules per side. */\nexport const matrixSize = (version: number): number => version * 4 + 17;\n\n/** Alignment-pattern center coordinates (Table E.1 formula). */\nexport function alignmentPatternPositions(version: number): readonly number[] {\n if (version === 1) return [];\n const numAlign = Math.floor(version / 7) + 2;\n const step = version === 32 ? 26 : Math.ceil((version * 4 + 4) / (numAlign * 2 - 2)) * 2;\n const result = [6];\n for (let pos = version * 4 + 10; result.length < numAlign; pos -= step) result.splice(1, 0, pos);\n return result;\n}\n\n/**\n * Total raw modules available for data + EC + remainder bits, derived from the\n * symbol geometry (Table 1 / Annex A): full grid minus finders, separators,\n * timing, alignment, dark module, format and version information.\n */\nexport function rawDataModules(version: number): number {\n let result = (16 * version + 128) * version + 64;\n if (version >= 2) {\n const numAlign = Math.floor(version / 7) + 2;\n result -= (25 * numAlign - 10) * numAlign - 55;\n if (version >= 7) result -= 36;\n }\n return result;\n}\n\n/** Total codewords (data + EC) for a version. */\nexport const totalCodewords = (version: number): number => Math.floor(rawDataModules(version) / 8);\n\n/** Leftover bits after the codeword stream (0, 3, 4, or 7 by version). */\nexport const remainderBits = (version: number): number => rawDataModules(version) % 8;\n\nexport function ecCodewordsPerBlock(version: number, level: QrErrorCorrection): number {\n return EC_CODEWORDS_PER_BLOCK[ecIndex(level)][version];\n}\n\nexport function numEcBlocks(version: number, level: QrErrorCorrection): number {\n return NUM_EC_BLOCKS[ecIndex(level)][version];\n}\n\n/** Data codewords for a (version, level) pair. */\nexport function dataCodewords(version: number, level: QrErrorCorrection): number {\n return totalCodewords(version) - ecCodewordsPerBlock(version, level) * numEcBlocks(version, level);\n}\n\n/** Version group for the character-count indicator: 0 → 1–9, 1 → 10–26, 2 → 27–40. */\nexport function versionGroup(version: number): 0 | 1 | 2 {\n return version <= 9 ? 0 : version <= 26 ? 1 : 2;\n}\n"],"mappings":"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"}
|
package/dist/_tables.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { QrErrorCorrection, QrMode } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* QR Model 2 lookup tables, transcribed from ISO/IEC 18004:2015:
|
|
4
|
-
* - `EC_CODEWORDS_PER_BLOCK` / `NUM_EC_BLOCKS
|
|
4
|
+
* - `EC_CODEWORDS_PER_BLOCK` / `NUM_EC_BLOCKS`: Table 9 (error-correction
|
|
5
5
|
* characteristics). Stored as per-block EC codewords and block count; the
|
|
6
6
|
* group-1/group-2 split is derived, since all blocks share one EC length.
|
|
7
|
-
* - `alignmentPatternPositions
|
|
8
|
-
* - `CHAR_COUNT_BITS
|
|
9
|
-
* - `FORMAT_EC_BITS
|
|
7
|
+
* - `alignmentPatternPositions`: Table E.1, computed by the spec formula.
|
|
8
|
+
* - `CHAR_COUNT_BITS`: Table 3 (character-count indicator bit widths).
|
|
9
|
+
* - `FORMAT_EC_BITS`: Table 10 (2-bit level field inside format information).
|
|
10
10
|
*
|
|
11
11
|
* `tables.test.ts` cross-checks every entry against the raw-module formula, so
|
|
12
12
|
* a transcription slip fails the consistency test before the decode oracle runs.
|
package/dist/_tables.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_tables.js","names":[],"sources":["../src/_tables.ts"],"sourcesContent":["import type { QrErrorCorrection, QrMode } from './types';\n\n/**\n * QR Model 2 lookup tables, transcribed from ISO/IEC 18004:2015:\n * - `EC_CODEWORDS_PER_BLOCK` / `NUM_EC_BLOCKS
|
|
1
|
+
{"version":3,"file":"_tables.js","names":[],"sources":["../src/_tables.ts"],"sourcesContent":["import type { QrErrorCorrection, QrMode } from './types';\n\n/**\n * QR Model 2 lookup tables, transcribed from ISO/IEC 18004:2015:\n * - `EC_CODEWORDS_PER_BLOCK` / `NUM_EC_BLOCKS`: Table 9 (error-correction\n * characteristics). Stored as per-block EC codewords and block count; the\n * group-1/group-2 split is derived, since all blocks share one EC length.\n * - `alignmentPatternPositions`: Table E.1, computed by the spec formula.\n * - `CHAR_COUNT_BITS`: Table 3 (character-count indicator bit widths).\n * - `FORMAT_EC_BITS`: Table 10 (2-bit level field inside format information).\n *\n * `tables.test.ts` cross-checks every entry against the raw-module formula, so\n * a transcription slip fails the consistency test before the decode oracle runs.\n */\n\n/** Index order used by the table rows below. */\nexport const EC_LEVELS = ['L', 'M', 'Q', 'H'] as const;\n\nexport const ALPHANUMERIC_CHARSET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';\n\n/** Mode indicators (Table 2). */\nexport const MODE_BITS: Record<QrMode, number> = {\n alphanumeric: 0b0010,\n byte: 0b0100,\n numeric: 0b0001,\n};\n\n/** Character-count indicator widths for version groups 1–9 / 10–26 / 27–40. */\nexport const CHAR_COUNT_BITS: Record<QrMode, readonly [number, number, number]> = {\n alphanumeric: [9, 11, 13],\n byte: [8, 16, 16],\n numeric: [10, 12, 14],\n};\n\n/** EC level bits inside format information (L=01, M=00, Q=11, H=10). */\nexport const FORMAT_EC_BITS: Record<QrErrorCorrection, number> = { H: 0b10, L: 0b01, M: 0b00, Q: 0b11 };\n\n/** Row 0 = L, row 1 = M, row 2 = Q, row 3 = H; column 0 unused (versions start at 1). */\nexport const EC_CODEWORDS_PER_BLOCK: ReadonlyArray<ReadonlyArray<number>> = [\n // prettier-ignore\n [\n -1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30,\n 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,\n ],\n // prettier-ignore\n [\n -1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28,\n 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n ],\n // prettier-ignore\n [\n -1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30,\n 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,\n ],\n // prettier-ignore\n [\n -1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30,\n 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,\n ],\n];\n\nexport const NUM_EC_BLOCKS: ReadonlyArray<ReadonlyArray<number>> = [\n // prettier-ignore\n [\n -1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19,\n 19, 20, 21, 22, 24, 25,\n ],\n // prettier-ignore\n [\n -1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31,\n 33, 35, 37, 38, 40, 43, 45, 47, 49,\n ],\n // prettier-ignore\n [\n -1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43,\n 45, 48, 51, 53, 56, 59, 62, 65, 68,\n ],\n // prettier-ignore\n [\n -1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48,\n 51, 56, 59, 62, 65, 68, 71, 74, 77, 81,\n ],\n];\n\nconst ecIndex = (level: QrErrorCorrection): number => EC_LEVELS.indexOf(level);\n\n/** Total modules per side. */\nexport const matrixSize = (version: number): number => version * 4 + 17;\n\n/** Alignment-pattern center coordinates (Table E.1 formula). */\nexport function alignmentPatternPositions(version: number): readonly number[] {\n if (version === 1) return [];\n const numAlign = Math.floor(version / 7) + 2;\n const step = version === 32 ? 26 : Math.ceil((version * 4 + 4) / (numAlign * 2 - 2)) * 2;\n const result = [6];\n for (let pos = version * 4 + 10; result.length < numAlign; pos -= step) result.splice(1, 0, pos);\n return result;\n}\n\n/**\n * Total raw modules available for data + EC + remainder bits, derived from the\n * symbol geometry (Table 1 / Annex A): full grid minus finders, separators,\n * timing, alignment, dark module, format and version information.\n */\nexport function rawDataModules(version: number): number {\n let result = (16 * version + 128) * version + 64;\n if (version >= 2) {\n const numAlign = Math.floor(version / 7) + 2;\n result -= (25 * numAlign - 10) * numAlign - 55;\n if (version >= 7) result -= 36;\n }\n return result;\n}\n\n/** Total codewords (data + EC) for a version. */\nexport const totalCodewords = (version: number): number => Math.floor(rawDataModules(version) / 8);\n\n/** Leftover bits after the codeword stream (0, 3, 4, or 7 by version). */\nexport const remainderBits = (version: number): number => rawDataModules(version) % 8;\n\nexport function ecCodewordsPerBlock(version: number, level: QrErrorCorrection): number {\n return EC_CODEWORDS_PER_BLOCK[ecIndex(level)][version];\n}\n\nexport function numEcBlocks(version: number, level: QrErrorCorrection): number {\n return NUM_EC_BLOCKS[ecIndex(level)][version];\n}\n\n/** Data codewords for a (version, level) pair. */\nexport function dataCodewords(version: number, level: QrErrorCorrection): number {\n return totalCodewords(version) - ecCodewordsPerBlock(version, level) * numEcBlocks(version, level);\n}\n\n/** Version group for the character-count indicator: 0 → 1–9, 1 → 10–26, 2 → 27–40. */\nexport function versionGroup(version: number): 0 | 1 | 2 {\n return version <= 9 ? 0 : version <= 26 ? 1 : 2;\n}\n"],"mappings":"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"}
|
package/dist/canvas.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas.cjs","names":[],"sources":["../src/canvas.ts"],"sourcesContent":["import { SigilUnsupportedError } from './errors';\nimport type { QrCanvasOptions, QrMatrix } from './types';\n\n/**\n * Canvas rendering
|
|
1
|
+
{"version":3,"file":"canvas.cjs","names":[],"sources":["../src/canvas.ts"],"sourcesContent":["import { SigilUnsupportedError } from './errors';\nimport type { QrCanvasOptions, QrMatrix } from './types';\n\n/**\n * Canvas rendering: the only DOM-touching output path.\n * Resizes the canvas to `(size + 2*margin) * scale` CSS pixels, backing-store\n * scaled by `devicePixelRatio`, and paints one `fillRect` per dark module.\n * Returns the CSS pixel size so callers can size wrappers.\n */\nexport function drawToCanvas(matrix: QrMatrix, canvas: HTMLCanvasElement, options: QrCanvasOptions = {}): number {\n const margin = options.margin ?? 4;\n const scale = options.scale ?? 1;\n const dark = options.dark ?? '#000000';\n const light = options.light ?? '#ffffff';\n const cssSize = (matrix.size + margin * 2) * scale;\n const dpr = globalThis.devicePixelRatio || 1;\n\n canvas.width = cssSize * dpr;\n canvas.height = cssSize * dpr;\n canvas.style.width = `${cssSize}px`;\n canvas.style.height = `${cssSize}px`;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new SigilUnsupportedError('Canvas 2D context unavailable');\n ctx.scale(dpr, dpr);\n ctx.fillStyle = light;\n ctx.fillRect(0, 0, cssSize, cssSize);\n ctx.fillStyle = dark;\n for (let y = 0; y < matrix.size; y++)\n for (let x = 0; x < matrix.size; x++)\n if (matrix.get(x, y)) ctx.fillRect((x + margin) * scale, (y + margin) * scale, scale, scale);\n return cssSize;\n}\n"],"mappings":"gCASA,SAAgB,aAAa,EAAkB,EAA2B,EAA2B,CAAC,EAAW,CAC/G,IAAM,EAAS,EAAQ,QAAU,EAC3B,EAAQ,EAAQ,OAAS,EACzB,EAAO,EAAQ,MAAQ,UACvB,EAAQ,EAAQ,OAAS,UACzB,GAAW,EAAO,KAAO,EAAS,GAAK,EACvC,EAAM,WAAW,kBAAoB,EAE3C,EAAO,MAAQ,EAAU,EACzB,EAAO,OAAS,EAAU,EAC1B,EAAO,MAAM,MAAQ,GAAG,EAAQ,IAChC,EAAO,MAAM,OAAS,GAAG,EAAQ,IAEjC,IAAM,EAAM,EAAO,WAAW,IAAI,EAClC,GAAI,CAAC,EAAK,MAAM,IAAI,EAAA,sBAAsB,+BAA+B,EACzE,EAAI,MAAM,EAAK,CAAG,EAClB,EAAI,UAAY,EAChB,EAAI,SAAS,EAAG,EAAG,EAAS,CAAO,EACnC,EAAI,UAAY,EAChB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,KAAM,IAC/B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,KAAM,IAC3B,EAAO,IAAI,EAAG,CAAC,GAAG,EAAI,UAAU,EAAI,GAAU,GAAQ,EAAI,GAAU,EAAO,EAAO,CAAK,EAC/F,OAAO,CACT"}
|
package/dist/canvas.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { QrCanvasOptions, QrMatrix } from './types';
|
|
2
2
|
/**
|
|
3
|
-
* Canvas rendering
|
|
3
|
+
* Canvas rendering: the only DOM-touching output path.
|
|
4
4
|
* Resizes the canvas to `(size + 2*margin) * scale` CSS pixels, backing-store
|
|
5
5
|
* scaled by `devicePixelRatio`, and paints one `fillRect` per dark module.
|
|
6
6
|
* Returns the CSS pixel size so callers can size wrappers.
|
package/dist/canvas.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas.js","names":[],"sources":["../src/canvas.ts"],"sourcesContent":["import { SigilUnsupportedError } from './errors';\nimport type { QrCanvasOptions, QrMatrix } from './types';\n\n/**\n * Canvas rendering
|
|
1
|
+
{"version":3,"file":"canvas.js","names":[],"sources":["../src/canvas.ts"],"sourcesContent":["import { SigilUnsupportedError } from './errors';\nimport type { QrCanvasOptions, QrMatrix } from './types';\n\n/**\n * Canvas rendering: the only DOM-touching output path.\n * Resizes the canvas to `(size + 2*margin) * scale` CSS pixels, backing-store\n * scaled by `devicePixelRatio`, and paints one `fillRect` per dark module.\n * Returns the CSS pixel size so callers can size wrappers.\n */\nexport function drawToCanvas(matrix: QrMatrix, canvas: HTMLCanvasElement, options: QrCanvasOptions = {}): number {\n const margin = options.margin ?? 4;\n const scale = options.scale ?? 1;\n const dark = options.dark ?? '#000000';\n const light = options.light ?? '#ffffff';\n const cssSize = (matrix.size + margin * 2) * scale;\n const dpr = globalThis.devicePixelRatio || 1;\n\n canvas.width = cssSize * dpr;\n canvas.height = cssSize * dpr;\n canvas.style.width = `${cssSize}px`;\n canvas.style.height = `${cssSize}px`;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new SigilUnsupportedError('Canvas 2D context unavailable');\n ctx.scale(dpr, dpr);\n ctx.fillStyle = light;\n ctx.fillRect(0, 0, cssSize, cssSize);\n ctx.fillStyle = dark;\n for (let y = 0; y < matrix.size; y++)\n for (let x = 0; x < matrix.size; x++)\n if (matrix.get(x, y)) ctx.fillRect((x + margin) * scale, (y + margin) * scale, scale, scale);\n return cssSize;\n}\n"],"mappings":"oDASA,SAAgB,aAAa,EAAkB,EAA2B,EAA2B,CAAC,EAAW,CAC/G,IAAM,EAAS,EAAQ,QAAU,EAC3B,EAAQ,EAAQ,OAAS,EACzB,EAAO,EAAQ,MAAQ,UACvB,EAAQ,EAAQ,OAAS,UACzB,GAAW,EAAO,KAAO,EAAS,GAAK,EACvC,EAAM,WAAW,kBAAoB,EAE3C,EAAO,MAAQ,EAAU,EACzB,EAAO,OAAS,EAAU,EAC1B,EAAO,MAAM,MAAQ,GAAG,EAAQ,IAChC,EAAO,MAAM,OAAS,GAAG,EAAQ,IAEjC,IAAM,EAAM,EAAO,WAAW,IAAI,EAClC,GAAI,CAAC,EAAK,MAAM,IAAI,EAAsB,+BAA+B,EACzE,EAAI,MAAM,EAAK,CAAG,EAClB,EAAI,UAAY,EAChB,EAAI,SAAS,EAAG,EAAG,EAAS,CAAO,EACnC,EAAI,UAAY,EAChB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,KAAM,IAC/B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,KAAM,IAC3B,EAAO,IAAI,EAAG,CAAC,GAAG,EAAI,UAAU,EAAI,GAAU,GAAQ,EAAI,GAAU,EAAO,EAAO,CAAK,EAC/F,OAAO,CACT"}
|
package/dist/encode.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encode.cjs","names":[],"sources":["../src/encode.ts"],"sourcesContent":["import { drawFormatInfo, drawVersionInfo } from './_format';\nimport { applyMask, penaltyScore } from './_mask';\nimport { createGrid, drawFunctionPatterns, placeData } from './_matrix';\nimport { ecCodewords } from './_reed-solomon';\nimport {\n buildDataCodewords,\n detectMode,\n payloadFromBytes,\n payloadFromText,\n payloadLength,\n type QrPayload,\n segmentBits,\n} from './_segments';\nimport {\n ALPHANUMERIC_CHARSET,\n CHAR_COUNT_BITS,\n dataCodewords,\n ecCodewordsPerBlock,\n matrixSize,\n numEcBlocks,\n totalCodewords,\n versionGroup,\n} from './_tables';\nimport { SigilCapacityError, SigilOptionError } from './errors';\nimport type { QrEncodeOptions, QrErrorCorrection, QrMatrix, QrMode } from './types';\n\nconst MAX_VERSION = 40;\n\nfunction checkOptions(options: QrEncodeOptions): void {\n const { version, minVersion, mask, errorCorrection } = options;\n const inRange = (v: number) => Number.isInteger(v) && v >= 1 && v <= MAX_VERSION;\n if (version !== undefined && !inRange(version))\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n if (minVersion !== undefined && !inRange(minVersion))\n throw new SigilOptionError(`minVersion must be an integer 1–${MAX_VERSION}, got ${minVersion}`);\n if (version !== undefined && minVersion !== undefined && minVersion > version)\n throw new SigilOptionError(`minVersion (${minVersion}) exceeds version (${version})`);\n if (mask !== undefined && (!Number.isInteger(mask) || mask < 0 || mask > 7))\n throw new SigilOptionError(`mask must be an integer 0–7, got ${mask}`);\n if (errorCorrection !== undefined && !'LMQH'.includes(errorCorrection))\n throw new SigilOptionError(`errorCorrection must be 'L', 'M', 'Q', or 'H'`);\n}\n\n/** Character capacity of (version, level, mode) — the `qrCapacity` core. */\nfunction capacityFor(version: number, level: QrErrorCorrection, mode: QrMode): number {\n const countBits = CHAR_COUNT_BITS[mode][versionGroup(version)];\n const usable = dataCodewords(version, level) * 8 - 4 - countBits;\n if (usable <= 0) return 0;\n switch (mode) {\n case 'numeric':\n return Math.floor(usable / 10) * 3 + (usable % 10 >= 7 ? 2 : usable % 10 >= 4 ? 1 : 0);\n case 'alphanumeric':\n return Math.floor(usable / 11) * 2 + (usable % 11 >= 6 ? 1 : 0);\n case 'byte':\n return Math.floor(usable / 8);\n }\n}\n\n/** Smallest version ≥ minVersion whose data area fits the segment, or `null`. */\nfunction pickVersion(payload: QrPayload, level: QrErrorCorrection, minVersion: number): number | null {\n for (let v = minVersion; v <= MAX_VERSION; v++) if (segmentBits(payload, v) <= dataCodewords(v, level) * 8) return v;\n return null;\n}\n\n/** The capacity error for a payload that does not fit at `version`. */\nfunction capacityError(payload: QrPayload, level: QrErrorCorrection, version: number): SigilCapacityError {\n const length = payloadLength(payload);\n const max = capacityFor(version, level, payload.mode);\n const unit = payload.mode === 'byte' ? 'bytes' : 'chars';\n return new SigilCapacityError(\n `Input of ${length} ${unit} exceeds QR capacity (${max} ${unit} at version ${version}-${level})`,\n length,\n max,\n version,\n );\n}\n\n/** Split data codewords into EC blocks and interleave data + EC (§7.6). */\nfunction interleaveBlocks(data: readonly number[], version: number, level: QrErrorCorrection): number[] {\n const numBlocks = numEcBlocks(version, level);\n const ecLen = ecCodewordsPerBlock(version, level);\n const rawLen = totalCodewords(version);\n const shortLen = Math.floor(rawLen / numBlocks) - ecLen; // data codewords in a short block\n const numLong = rawLen % numBlocks; // long blocks carry one extra data codeword\n\n const blocks: number[][] = [];\n let offset = 0;\n for (let b = 0; b < numBlocks; b++) {\n const isLong = b >= numBlocks - numLong;\n const dat = data.slice(offset, offset + shortLen + (isLong ? 1 : 0));\n offset += dat.length;\n const ecc = ecCodewords(dat, ecLen);\n // Short blocks get a pad slot so every block array shares one length;\n // the slot is skipped during interleave below.\n blocks.push(isLong ? [...dat, ...ecc] : [...dat, 0, ...ecc]);\n }\n\n const out: number[] = [];\n for (let i = 0; i < blocks[0].length; i++)\n for (let b = 0; b < numBlocks; b++) {\n // Skip the pad slot on short blocks (index = shortLen).\n if (i !== shortLen || b >= numBlocks - numLong) out.push(blocks[b][i]);\n }\n return out;\n}\n\nfunction freezeMatrix(grid: readonly (readonly boolean[])[], meta: Omit<QrMatrix, 'get'>): QrMatrix {\n const modules = grid.map((row) => Object.freeze([...row]));\n Object.freeze(modules);\n return Object.freeze({\n ...meta,\n get: (x: number, y: number) => (x >= 0 && y >= 0 && x < meta.size && y < meta.size ? modules[y][x] : false),\n });\n}\n\n/**\n * Encode `data` into a QR Model 2 symbol. Pure and synchronous.\n * Strings pick the most compact mode; `Uint8Array` is raw binary and always\n * byte mode, encoded as-is — no UTF-8 round-trip. Byte mode is UTF-8 without\n * an ECI header for string input — the industry-standard assumption.\n */\nexport function encodeQr(data: string | Uint8Array, options: QrEncodeOptions = {}): QrMatrix {\n checkOptions(options);\n if (data.length === 0) throw new SigilOptionError('Cannot encode an empty input');\n\n const level = options.errorCorrection ?? 'M';\n if (typeof data !== 'string' && options.mode !== undefined && options.mode !== 'byte')\n throw new SigilOptionError('Uint8Array input can only be encoded in byte mode');\n const mode = options.mode ?? (typeof data === 'string' ? detectMode(data) : 'byte');\n if (typeof data === 'string' && !isModeCompatible(data, mode))\n throw new SigilOptionError(`Input cannot be encoded in ${mode} mode`);\n const payload = typeof data === 'string' ? payloadFromText(data, mode) : payloadFromBytes(data);\n\n const version = options.version ?? pickVersion(payload, level, options.minVersion ?? 1);\n if (version === null || segmentBits(payload, version) > dataCodewords(version, level) * 8)\n throw capacityError(payload, level, options.version ?? MAX_VERSION);\n\n const codewords = interleaveBlocks(buildDataCodewords(payload, version, level), version, level);\n const grid = createGrid(matrixSize(version));\n drawFunctionPatterns(grid, version);\n placeData(grid, codewords);\n\n // Try every mask (or the forced one), keep the lowest penalty. Each candidate\n // is undone by the idempotent XOR, and the final drawFormatInfo below rewrites\n // every format module, so candidates never leak into each other.\n const candidates = options.mask !== undefined ? [options.mask] : [0, 1, 2, 3, 4, 5, 6, 7];\n let bestMask = candidates[0];\n let bestScore = Number.POSITIVE_INFINITY;\n for (const m of candidates) {\n applyMask(grid, m);\n drawFormatInfo(grid, level, m);\n const score = penaltyScore(grid);\n if (score < bestScore) {\n bestScore = score;\n bestMask = m;\n }\n applyMask(grid, m); // undo\n }\n\n // The grid is unmasked again — draw the winning candidate once, finally.\n applyMask(grid, bestMask);\n drawFormatInfo(grid, level, bestMask);\n drawVersionInfo(grid, version);\n\n return freezeMatrix(grid.modules, {\n errorCorrection: level,\n mask: bestMask,\n mode,\n size: grid.size,\n version,\n });\n}\n\n/** Whether `text` is representable in `mode` (used when the mode is forced). */\nfunction isModeCompatible(text: string, mode: QrMode): boolean {\n if (mode === 'numeric') return /^\\d+$/.test(text);\n if (mode === 'alphanumeric') return [...text].every((ch) => ALPHANUMERIC_CHARSET.includes(ch));\n return true;\n}\n\n/** Max characters/bytes encodable at (version, level, mode). */\nexport function qrCapacity(version: number, errorCorrection: QrErrorCorrection, mode: QrMode): number {\n if (!Number.isInteger(version) || version < 1 || version > MAX_VERSION)\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n return capacityFor(version, errorCorrection, mode);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"encode.cjs","names":[],"sources":["../src/encode.ts"],"sourcesContent":["import { drawFormatInfo, drawVersionInfo } from './_format';\nimport { applyMask, penaltyScore } from './_mask';\nimport { createGrid, drawFunctionPatterns, placeData } from './_matrix';\nimport { ecCodewords } from './_reed-solomon';\nimport {\n buildDataCodewords,\n detectMode,\n payloadFromBytes,\n payloadFromText,\n payloadLength,\n type QrPayload,\n segmentBits,\n} from './_segments';\nimport {\n ALPHANUMERIC_CHARSET,\n CHAR_COUNT_BITS,\n dataCodewords,\n ecCodewordsPerBlock,\n matrixSize,\n numEcBlocks,\n totalCodewords,\n versionGroup,\n} from './_tables';\nimport { SigilCapacityError, SigilOptionError } from './errors';\nimport type { QrEncodeOptions, QrErrorCorrection, QrMatrix, QrMode } from './types';\n\nconst MAX_VERSION = 40;\n\nfunction checkOptions(options: QrEncodeOptions): void {\n const { version, minVersion, mask, errorCorrection } = options;\n const inRange = (v: number) => Number.isInteger(v) && v >= 1 && v <= MAX_VERSION;\n if (version !== undefined && !inRange(version))\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n if (minVersion !== undefined && !inRange(minVersion))\n throw new SigilOptionError(`minVersion must be an integer 1–${MAX_VERSION}, got ${minVersion}`);\n if (version !== undefined && minVersion !== undefined && minVersion > version)\n throw new SigilOptionError(`minVersion (${minVersion}) exceeds version (${version})`);\n if (mask !== undefined && (!Number.isInteger(mask) || mask < 0 || mask > 7))\n throw new SigilOptionError(`mask must be an integer 0–7, got ${mask}`);\n if (errorCorrection !== undefined && !'LMQH'.includes(errorCorrection))\n throw new SigilOptionError(`errorCorrection must be 'L', 'M', 'Q', or 'H'`);\n}\n\n/** Character capacity of (version, level, mode): the `qrCapacity` core. */\nfunction capacityFor(version: number, level: QrErrorCorrection, mode: QrMode): number {\n const countBits = CHAR_COUNT_BITS[mode][versionGroup(version)];\n const usable = dataCodewords(version, level) * 8 - 4 - countBits;\n if (usable <= 0) return 0;\n switch (mode) {\n case 'numeric':\n return Math.floor(usable / 10) * 3 + (usable % 10 >= 7 ? 2 : usable % 10 >= 4 ? 1 : 0);\n case 'alphanumeric':\n return Math.floor(usable / 11) * 2 + (usable % 11 >= 6 ? 1 : 0);\n case 'byte':\n return Math.floor(usable / 8);\n }\n}\n\n/** Smallest version ≥ minVersion whose data area fits the segment, or `null`. */\nfunction pickVersion(payload: QrPayload, level: QrErrorCorrection, minVersion: number): number | null {\n for (let v = minVersion; v <= MAX_VERSION; v++) if (segmentBits(payload, v) <= dataCodewords(v, level) * 8) return v;\n return null;\n}\n\n/** The capacity error for a payload that does not fit at `version`. */\nfunction capacityError(payload: QrPayload, level: QrErrorCorrection, version: number): SigilCapacityError {\n const length = payloadLength(payload);\n const max = capacityFor(version, level, payload.mode);\n const unit = payload.mode === 'byte' ? 'bytes' : 'chars';\n return new SigilCapacityError(\n `Input of ${length} ${unit} exceeds QR capacity (${max} ${unit} at version ${version}-${level})`,\n length,\n max,\n version,\n );\n}\n\n/** Split data codewords into EC blocks and interleave data + EC (§7.6). */\nfunction interleaveBlocks(data: readonly number[], version: number, level: QrErrorCorrection): number[] {\n const numBlocks = numEcBlocks(version, level);\n const ecLen = ecCodewordsPerBlock(version, level);\n const rawLen = totalCodewords(version);\n const shortLen = Math.floor(rawLen / numBlocks) - ecLen; // data codewords in a short block\n const numLong = rawLen % numBlocks; // long blocks carry one extra data codeword\n\n const blocks: number[][] = [];\n let offset = 0;\n for (let b = 0; b < numBlocks; b++) {\n const isLong = b >= numBlocks - numLong;\n const dat = data.slice(offset, offset + shortLen + (isLong ? 1 : 0));\n offset += dat.length;\n const ecc = ecCodewords(dat, ecLen);\n // Short blocks get a pad slot so every block array shares one length;\n // the slot is skipped during interleave below.\n blocks.push(isLong ? [...dat, ...ecc] : [...dat, 0, ...ecc]);\n }\n\n const out: number[] = [];\n for (let i = 0; i < blocks[0].length; i++)\n for (let b = 0; b < numBlocks; b++) {\n // Skip the pad slot on short blocks (index = shortLen).\n if (i !== shortLen || b >= numBlocks - numLong) out.push(blocks[b][i]);\n }\n return out;\n}\n\nfunction freezeMatrix(grid: readonly (readonly boolean[])[], meta: Omit<QrMatrix, 'get'>): QrMatrix {\n const modules = grid.map((row) => Object.freeze([...row]));\n Object.freeze(modules);\n return Object.freeze({\n ...meta,\n get: (x: number, y: number) => (x >= 0 && y >= 0 && x < meta.size && y < meta.size ? modules[y][x] : false),\n });\n}\n\n/**\n * Encode `data` into a QR Model 2 symbol. Pure and synchronous.\n * Strings pick the most compact mode; `Uint8Array` is raw binary and always\n * byte mode, encoded as-is: no UTF-8 round-trip. Byte mode is UTF-8 without\n * an ECI header for string input: the industry-standard assumption.\n */\nexport function encodeQr(data: string | Uint8Array, options: QrEncodeOptions = {}): QrMatrix {\n checkOptions(options);\n if (data.length === 0) throw new SigilOptionError('Cannot encode an empty input');\n\n const level = options.errorCorrection ?? 'M';\n if (typeof data !== 'string' && options.mode !== undefined && options.mode !== 'byte')\n throw new SigilOptionError('Uint8Array input can only be encoded in byte mode');\n const mode = options.mode ?? (typeof data === 'string' ? detectMode(data) : 'byte');\n if (typeof data === 'string' && !isModeCompatible(data, mode))\n throw new SigilOptionError(`Input cannot be encoded in ${mode} mode`);\n const payload = typeof data === 'string' ? payloadFromText(data, mode) : payloadFromBytes(data);\n\n const version = options.version ?? pickVersion(payload, level, options.minVersion ?? 1);\n if (version === null || segmentBits(payload, version) > dataCodewords(version, level) * 8)\n throw capacityError(payload, level, options.version ?? MAX_VERSION);\n\n const codewords = interleaveBlocks(buildDataCodewords(payload, version, level), version, level);\n const grid = createGrid(matrixSize(version));\n drawFunctionPatterns(grid, version);\n placeData(grid, codewords);\n\n // Try every mask (or the forced one), keep the lowest penalty. Each candidate\n // is undone by the idempotent XOR, and the final drawFormatInfo below rewrites\n // every format module, so candidates never leak into each other.\n const candidates = options.mask !== undefined ? [options.mask] : [0, 1, 2, 3, 4, 5, 6, 7];\n let bestMask = candidates[0];\n let bestScore = Number.POSITIVE_INFINITY;\n for (const m of candidates) {\n applyMask(grid, m);\n drawFormatInfo(grid, level, m);\n const score = penaltyScore(grid);\n if (score < bestScore) {\n bestScore = score;\n bestMask = m;\n }\n applyMask(grid, m); // undo\n }\n\n // The grid is unmasked again: draw the winning candidate once, finally.\n applyMask(grid, bestMask);\n drawFormatInfo(grid, level, bestMask);\n drawVersionInfo(grid, version);\n\n return freezeMatrix(grid.modules, {\n errorCorrection: level,\n mask: bestMask,\n mode,\n size: grid.size,\n version,\n });\n}\n\n/** Whether `text` is representable in `mode` (used when the mode is forced). */\nfunction isModeCompatible(text: string, mode: QrMode): boolean {\n if (mode === 'numeric') return /^\\d+$/.test(text);\n if (mode === 'alphanumeric') return [...text].every((ch) => ALPHANUMERIC_CHARSET.includes(ch));\n return true;\n}\n\n/** Max characters/bytes encodable at (version, level, mode). */\nexport function qrCapacity(version: number, errorCorrection: QrErrorCorrection, mode: QrMode): number {\n if (!Number.isInteger(version) || version < 1 || version > MAX_VERSION)\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n return capacityFor(version, errorCorrection, mode);\n}\n"],"mappings":"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"}
|
package/dist/encode.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { QrEncodeOptions, QrErrorCorrection, QrMatrix, QrMode } from './typ
|
|
|
2
2
|
/**
|
|
3
3
|
* Encode `data` into a QR Model 2 symbol. Pure and synchronous.
|
|
4
4
|
* Strings pick the most compact mode; `Uint8Array` is raw binary and always
|
|
5
|
-
* byte mode, encoded as-is
|
|
6
|
-
* an ECI header for string input
|
|
5
|
+
* byte mode, encoded as-is: no UTF-8 round-trip. Byte mode is UTF-8 without
|
|
6
|
+
* an ECI header for string input: the industry-standard assumption.
|
|
7
7
|
*/
|
|
8
8
|
export declare function encodeQr(data: string | Uint8Array, options?: QrEncodeOptions): QrMatrix;
|
|
9
9
|
/** Max characters/bytes encodable at (version, level, mode). */
|
package/dist/encode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encode.js","names":[],"sources":["../src/encode.ts"],"sourcesContent":["import { drawFormatInfo, drawVersionInfo } from './_format';\nimport { applyMask, penaltyScore } from './_mask';\nimport { createGrid, drawFunctionPatterns, placeData } from './_matrix';\nimport { ecCodewords } from './_reed-solomon';\nimport {\n buildDataCodewords,\n detectMode,\n payloadFromBytes,\n payloadFromText,\n payloadLength,\n type QrPayload,\n segmentBits,\n} from './_segments';\nimport {\n ALPHANUMERIC_CHARSET,\n CHAR_COUNT_BITS,\n dataCodewords,\n ecCodewordsPerBlock,\n matrixSize,\n numEcBlocks,\n totalCodewords,\n versionGroup,\n} from './_tables';\nimport { SigilCapacityError, SigilOptionError } from './errors';\nimport type { QrEncodeOptions, QrErrorCorrection, QrMatrix, QrMode } from './types';\n\nconst MAX_VERSION = 40;\n\nfunction checkOptions(options: QrEncodeOptions): void {\n const { version, minVersion, mask, errorCorrection } = options;\n const inRange = (v: number) => Number.isInteger(v) && v >= 1 && v <= MAX_VERSION;\n if (version !== undefined && !inRange(version))\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n if (minVersion !== undefined && !inRange(minVersion))\n throw new SigilOptionError(`minVersion must be an integer 1–${MAX_VERSION}, got ${minVersion}`);\n if (version !== undefined && minVersion !== undefined && minVersion > version)\n throw new SigilOptionError(`minVersion (${minVersion}) exceeds version (${version})`);\n if (mask !== undefined && (!Number.isInteger(mask) || mask < 0 || mask > 7))\n throw new SigilOptionError(`mask must be an integer 0–7, got ${mask}`);\n if (errorCorrection !== undefined && !'LMQH'.includes(errorCorrection))\n throw new SigilOptionError(`errorCorrection must be 'L', 'M', 'Q', or 'H'`);\n}\n\n/** Character capacity of (version, level, mode) — the `qrCapacity` core. */\nfunction capacityFor(version: number, level: QrErrorCorrection, mode: QrMode): number {\n const countBits = CHAR_COUNT_BITS[mode][versionGroup(version)];\n const usable = dataCodewords(version, level) * 8 - 4 - countBits;\n if (usable <= 0) return 0;\n switch (mode) {\n case 'numeric':\n return Math.floor(usable / 10) * 3 + (usable % 10 >= 7 ? 2 : usable % 10 >= 4 ? 1 : 0);\n case 'alphanumeric':\n return Math.floor(usable / 11) * 2 + (usable % 11 >= 6 ? 1 : 0);\n case 'byte':\n return Math.floor(usable / 8);\n }\n}\n\n/** Smallest version ≥ minVersion whose data area fits the segment, or `null`. */\nfunction pickVersion(payload: QrPayload, level: QrErrorCorrection, minVersion: number): number | null {\n for (let v = minVersion; v <= MAX_VERSION; v++) if (segmentBits(payload, v) <= dataCodewords(v, level) * 8) return v;\n return null;\n}\n\n/** The capacity error for a payload that does not fit at `version`. */\nfunction capacityError(payload: QrPayload, level: QrErrorCorrection, version: number): SigilCapacityError {\n const length = payloadLength(payload);\n const max = capacityFor(version, level, payload.mode);\n const unit = payload.mode === 'byte' ? 'bytes' : 'chars';\n return new SigilCapacityError(\n `Input of ${length} ${unit} exceeds QR capacity (${max} ${unit} at version ${version}-${level})`,\n length,\n max,\n version,\n );\n}\n\n/** Split data codewords into EC blocks and interleave data + EC (§7.6). */\nfunction interleaveBlocks(data: readonly number[], version: number, level: QrErrorCorrection): number[] {\n const numBlocks = numEcBlocks(version, level);\n const ecLen = ecCodewordsPerBlock(version, level);\n const rawLen = totalCodewords(version);\n const shortLen = Math.floor(rawLen / numBlocks) - ecLen; // data codewords in a short block\n const numLong = rawLen % numBlocks; // long blocks carry one extra data codeword\n\n const blocks: number[][] = [];\n let offset = 0;\n for (let b = 0; b < numBlocks; b++) {\n const isLong = b >= numBlocks - numLong;\n const dat = data.slice(offset, offset + shortLen + (isLong ? 1 : 0));\n offset += dat.length;\n const ecc = ecCodewords(dat, ecLen);\n // Short blocks get a pad slot so every block array shares one length;\n // the slot is skipped during interleave below.\n blocks.push(isLong ? [...dat, ...ecc] : [...dat, 0, ...ecc]);\n }\n\n const out: number[] = [];\n for (let i = 0; i < blocks[0].length; i++)\n for (let b = 0; b < numBlocks; b++) {\n // Skip the pad slot on short blocks (index = shortLen).\n if (i !== shortLen || b >= numBlocks - numLong) out.push(blocks[b][i]);\n }\n return out;\n}\n\nfunction freezeMatrix(grid: readonly (readonly boolean[])[], meta: Omit<QrMatrix, 'get'>): QrMatrix {\n const modules = grid.map((row) => Object.freeze([...row]));\n Object.freeze(modules);\n return Object.freeze({\n ...meta,\n get: (x: number, y: number) => (x >= 0 && y >= 0 && x < meta.size && y < meta.size ? modules[y][x] : false),\n });\n}\n\n/**\n * Encode `data` into a QR Model 2 symbol. Pure and synchronous.\n * Strings pick the most compact mode; `Uint8Array` is raw binary and always\n * byte mode, encoded as-is — no UTF-8 round-trip. Byte mode is UTF-8 without\n * an ECI header for string input — the industry-standard assumption.\n */\nexport function encodeQr(data: string | Uint8Array, options: QrEncodeOptions = {}): QrMatrix {\n checkOptions(options);\n if (data.length === 0) throw new SigilOptionError('Cannot encode an empty input');\n\n const level = options.errorCorrection ?? 'M';\n if (typeof data !== 'string' && options.mode !== undefined && options.mode !== 'byte')\n throw new SigilOptionError('Uint8Array input can only be encoded in byte mode');\n const mode = options.mode ?? (typeof data === 'string' ? detectMode(data) : 'byte');\n if (typeof data === 'string' && !isModeCompatible(data, mode))\n throw new SigilOptionError(`Input cannot be encoded in ${mode} mode`);\n const payload = typeof data === 'string' ? payloadFromText(data, mode) : payloadFromBytes(data);\n\n const version = options.version ?? pickVersion(payload, level, options.minVersion ?? 1);\n if (version === null || segmentBits(payload, version) > dataCodewords(version, level) * 8)\n throw capacityError(payload, level, options.version ?? MAX_VERSION);\n\n const codewords = interleaveBlocks(buildDataCodewords(payload, version, level), version, level);\n const grid = createGrid(matrixSize(version));\n drawFunctionPatterns(grid, version);\n placeData(grid, codewords);\n\n // Try every mask (or the forced one), keep the lowest penalty. Each candidate\n // is undone by the idempotent XOR, and the final drawFormatInfo below rewrites\n // every format module, so candidates never leak into each other.\n const candidates = options.mask !== undefined ? [options.mask] : [0, 1, 2, 3, 4, 5, 6, 7];\n let bestMask = candidates[0];\n let bestScore = Number.POSITIVE_INFINITY;\n for (const m of candidates) {\n applyMask(grid, m);\n drawFormatInfo(grid, level, m);\n const score = penaltyScore(grid);\n if (score < bestScore) {\n bestScore = score;\n bestMask = m;\n }\n applyMask(grid, m); // undo\n }\n\n // The grid is unmasked again — draw the winning candidate once, finally.\n applyMask(grid, bestMask);\n drawFormatInfo(grid, level, bestMask);\n drawVersionInfo(grid, version);\n\n return freezeMatrix(grid.modules, {\n errorCorrection: level,\n mask: bestMask,\n mode,\n size: grid.size,\n version,\n });\n}\n\n/** Whether `text` is representable in `mode` (used when the mode is forced). */\nfunction isModeCompatible(text: string, mode: QrMode): boolean {\n if (mode === 'numeric') return /^\\d+$/.test(text);\n if (mode === 'alphanumeric') return [...text].every((ch) => ALPHANUMERIC_CHARSET.includes(ch));\n return true;\n}\n\n/** Max characters/bytes encodable at (version, level, mode). */\nexport function qrCapacity(version: number, errorCorrection: QrErrorCorrection, mode: QrMode): number {\n if (!Number.isInteger(version) || version < 1 || version > MAX_VERSION)\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n return capacityFor(version, errorCorrection, mode);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"encode.js","names":[],"sources":["../src/encode.ts"],"sourcesContent":["import { drawFormatInfo, drawVersionInfo } from './_format';\nimport { applyMask, penaltyScore } from './_mask';\nimport { createGrid, drawFunctionPatterns, placeData } from './_matrix';\nimport { ecCodewords } from './_reed-solomon';\nimport {\n buildDataCodewords,\n detectMode,\n payloadFromBytes,\n payloadFromText,\n payloadLength,\n type QrPayload,\n segmentBits,\n} from './_segments';\nimport {\n ALPHANUMERIC_CHARSET,\n CHAR_COUNT_BITS,\n dataCodewords,\n ecCodewordsPerBlock,\n matrixSize,\n numEcBlocks,\n totalCodewords,\n versionGroup,\n} from './_tables';\nimport { SigilCapacityError, SigilOptionError } from './errors';\nimport type { QrEncodeOptions, QrErrorCorrection, QrMatrix, QrMode } from './types';\n\nconst MAX_VERSION = 40;\n\nfunction checkOptions(options: QrEncodeOptions): void {\n const { version, minVersion, mask, errorCorrection } = options;\n const inRange = (v: number) => Number.isInteger(v) && v >= 1 && v <= MAX_VERSION;\n if (version !== undefined && !inRange(version))\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n if (minVersion !== undefined && !inRange(minVersion))\n throw new SigilOptionError(`minVersion must be an integer 1–${MAX_VERSION}, got ${minVersion}`);\n if (version !== undefined && minVersion !== undefined && minVersion > version)\n throw new SigilOptionError(`minVersion (${minVersion}) exceeds version (${version})`);\n if (mask !== undefined && (!Number.isInteger(mask) || mask < 0 || mask > 7))\n throw new SigilOptionError(`mask must be an integer 0–7, got ${mask}`);\n if (errorCorrection !== undefined && !'LMQH'.includes(errorCorrection))\n throw new SigilOptionError(`errorCorrection must be 'L', 'M', 'Q', or 'H'`);\n}\n\n/** Character capacity of (version, level, mode): the `qrCapacity` core. */\nfunction capacityFor(version: number, level: QrErrorCorrection, mode: QrMode): number {\n const countBits = CHAR_COUNT_BITS[mode][versionGroup(version)];\n const usable = dataCodewords(version, level) * 8 - 4 - countBits;\n if (usable <= 0) return 0;\n switch (mode) {\n case 'numeric':\n return Math.floor(usable / 10) * 3 + (usable % 10 >= 7 ? 2 : usable % 10 >= 4 ? 1 : 0);\n case 'alphanumeric':\n return Math.floor(usable / 11) * 2 + (usable % 11 >= 6 ? 1 : 0);\n case 'byte':\n return Math.floor(usable / 8);\n }\n}\n\n/** Smallest version ≥ minVersion whose data area fits the segment, or `null`. */\nfunction pickVersion(payload: QrPayload, level: QrErrorCorrection, minVersion: number): number | null {\n for (let v = minVersion; v <= MAX_VERSION; v++) if (segmentBits(payload, v) <= dataCodewords(v, level) * 8) return v;\n return null;\n}\n\n/** The capacity error for a payload that does not fit at `version`. */\nfunction capacityError(payload: QrPayload, level: QrErrorCorrection, version: number): SigilCapacityError {\n const length = payloadLength(payload);\n const max = capacityFor(version, level, payload.mode);\n const unit = payload.mode === 'byte' ? 'bytes' : 'chars';\n return new SigilCapacityError(\n `Input of ${length} ${unit} exceeds QR capacity (${max} ${unit} at version ${version}-${level})`,\n length,\n max,\n version,\n );\n}\n\n/** Split data codewords into EC blocks and interleave data + EC (§7.6). */\nfunction interleaveBlocks(data: readonly number[], version: number, level: QrErrorCorrection): number[] {\n const numBlocks = numEcBlocks(version, level);\n const ecLen = ecCodewordsPerBlock(version, level);\n const rawLen = totalCodewords(version);\n const shortLen = Math.floor(rawLen / numBlocks) - ecLen; // data codewords in a short block\n const numLong = rawLen % numBlocks; // long blocks carry one extra data codeword\n\n const blocks: number[][] = [];\n let offset = 0;\n for (let b = 0; b < numBlocks; b++) {\n const isLong = b >= numBlocks - numLong;\n const dat = data.slice(offset, offset + shortLen + (isLong ? 1 : 0));\n offset += dat.length;\n const ecc = ecCodewords(dat, ecLen);\n // Short blocks get a pad slot so every block array shares one length;\n // the slot is skipped during interleave below.\n blocks.push(isLong ? [...dat, ...ecc] : [...dat, 0, ...ecc]);\n }\n\n const out: number[] = [];\n for (let i = 0; i < blocks[0].length; i++)\n for (let b = 0; b < numBlocks; b++) {\n // Skip the pad slot on short blocks (index = shortLen).\n if (i !== shortLen || b >= numBlocks - numLong) out.push(blocks[b][i]);\n }\n return out;\n}\n\nfunction freezeMatrix(grid: readonly (readonly boolean[])[], meta: Omit<QrMatrix, 'get'>): QrMatrix {\n const modules = grid.map((row) => Object.freeze([...row]));\n Object.freeze(modules);\n return Object.freeze({\n ...meta,\n get: (x: number, y: number) => (x >= 0 && y >= 0 && x < meta.size && y < meta.size ? modules[y][x] : false),\n });\n}\n\n/**\n * Encode `data` into a QR Model 2 symbol. Pure and synchronous.\n * Strings pick the most compact mode; `Uint8Array` is raw binary and always\n * byte mode, encoded as-is: no UTF-8 round-trip. Byte mode is UTF-8 without\n * an ECI header for string input: the industry-standard assumption.\n */\nexport function encodeQr(data: string | Uint8Array, options: QrEncodeOptions = {}): QrMatrix {\n checkOptions(options);\n if (data.length === 0) throw new SigilOptionError('Cannot encode an empty input');\n\n const level = options.errorCorrection ?? 'M';\n if (typeof data !== 'string' && options.mode !== undefined && options.mode !== 'byte')\n throw new SigilOptionError('Uint8Array input can only be encoded in byte mode');\n const mode = options.mode ?? (typeof data === 'string' ? detectMode(data) : 'byte');\n if (typeof data === 'string' && !isModeCompatible(data, mode))\n throw new SigilOptionError(`Input cannot be encoded in ${mode} mode`);\n const payload = typeof data === 'string' ? payloadFromText(data, mode) : payloadFromBytes(data);\n\n const version = options.version ?? pickVersion(payload, level, options.minVersion ?? 1);\n if (version === null || segmentBits(payload, version) > dataCodewords(version, level) * 8)\n throw capacityError(payload, level, options.version ?? MAX_VERSION);\n\n const codewords = interleaveBlocks(buildDataCodewords(payload, version, level), version, level);\n const grid = createGrid(matrixSize(version));\n drawFunctionPatterns(grid, version);\n placeData(grid, codewords);\n\n // Try every mask (or the forced one), keep the lowest penalty. Each candidate\n // is undone by the idempotent XOR, and the final drawFormatInfo below rewrites\n // every format module, so candidates never leak into each other.\n const candidates = options.mask !== undefined ? [options.mask] : [0, 1, 2, 3, 4, 5, 6, 7];\n let bestMask = candidates[0];\n let bestScore = Number.POSITIVE_INFINITY;\n for (const m of candidates) {\n applyMask(grid, m);\n drawFormatInfo(grid, level, m);\n const score = penaltyScore(grid);\n if (score < bestScore) {\n bestScore = score;\n bestMask = m;\n }\n applyMask(grid, m); // undo\n }\n\n // The grid is unmasked again: draw the winning candidate once, finally.\n applyMask(grid, bestMask);\n drawFormatInfo(grid, level, bestMask);\n drawVersionInfo(grid, version);\n\n return freezeMatrix(grid.modules, {\n errorCorrection: level,\n mask: bestMask,\n mode,\n size: grid.size,\n version,\n });\n}\n\n/** Whether `text` is representable in `mode` (used when the mode is forced). */\nfunction isModeCompatible(text: string, mode: QrMode): boolean {\n if (mode === 'numeric') return /^\\d+$/.test(text);\n if (mode === 'alphanumeric') return [...text].every((ch) => ALPHANUMERIC_CHARSET.includes(ch));\n return true;\n}\n\n/** Max characters/bytes encodable at (version, level, mode). */\nexport function qrCapacity(version: number, errorCorrection: QrErrorCorrection, mode: QrMode): number {\n if (!Number.isInteger(version) || version < 1 || version > MAX_VERSION)\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n return capacityFor(version, errorCorrection, mode);\n}\n"],"mappings":"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"}
|