@sythos/js_barcode_universal 1.5.7 → 1.5.9
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/LICENSE +5 -4
- package/NOTICE.md +2 -2
- package/README.md +50 -37
- package/bundle/sythos-barcode.esm.js +12051 -11484
- package/bundle/sythos-barcode.js +12051 -11484
- package/package.json +52 -45
- package/src/index.d.ts +363 -0
- package/src/index.js +573 -428
- package/src/js/aztec/decoder.js +326 -0
- package/src/js/aztec/detector.js +251 -0
- package/src/js/aztec/encoder.js +276 -0
- package/src/js/aztec/high-level.js +216 -0
- package/src/js/aztec/index.js +34 -0
- package/src/js/aztec/tables.js +196 -0
- package/src/js/aztecrune/decoder.js +146 -0
- package/src/js/aztecrune/detector.js +180 -0
- package/src/js/aztecrune/encoder.js +103 -0
- package/src/js/aztecrune/index.js +34 -0
- package/src/js/aztecrune/tables.js +142 -0
- package/src/js/compactpdf417/decoder.js +123 -0
- package/src/js/compactpdf417/detector.js +138 -0
- package/src/js/compactpdf417/encoder.js +127 -0
- package/src/js/compactpdf417/index.js +5 -0
- package/src/js/compactpdf417/tables.js +164 -0
- package/src/js/core/bit-buffer.js +158 -0
- package/src/js/core/bit-matrix.js +243 -0
- package/src/js/core/errors.js +59 -0
- package/src/js/core/galois-field.js +193 -0
- package/src/js/core/index.js +39 -0
- package/src/js/core/reed-solomon.js +318 -0
- package/src/js/databar/codec.js +166 -0
- package/src/js/databar/decoder.js +224 -0
- package/src/js/databar/encoder.js +88 -0
- package/src/js/databar/gs1.js +176 -0
- package/src/js/databar/index.js +36 -0
- package/src/js/databar/patterns.js +139 -0
- package/src/js/databar/tables.js +123 -0
- package/src/js/datamatrix/decoder.js +296 -0
- package/src/js/datamatrix/detector.js +254 -0
- package/src/js/datamatrix/encoder.js +250 -0
- package/src/js/datamatrix/index.js +34 -0
- package/src/js/datamatrix/tables.js +122 -0
- package/src/js/frameqr/decoder.js +216 -0
- package/src/js/frameqr/detector.js +199 -0
- package/src/js/frameqr/encoder.js +143 -0
- package/src/js/frameqr/index.js +33 -0
- package/src/js/frameqr/tables.js +252 -0
- package/src/js/image/binarizer.js +254 -0
- package/src/js/image/grid-sampler.js +148 -0
- package/src/js/image/index.js +38 -0
- package/src/js/image/luminance.js +185 -0
- package/src/js/image/perspective.js +158 -0
- package/src/js/micropdf417/compaction.js +115 -0
- package/src/js/micropdf417/decoder.js +180 -0
- package/src/js/micropdf417/detector.js +152 -0
- package/src/js/micropdf417/encoder.js +184 -0
- package/src/js/micropdf417/error-correction.js +50 -0
- package/src/js/micropdf417/index.js +35 -0
- package/src/js/micropdf417/tables.js +197 -0
- package/src/js/microqr/decoder.js +240 -0
- package/src/js/microqr/detector.js +339 -0
- package/src/js/microqr/encoder.js +314 -0
- package/src/js/microqr/index.js +34 -0
- package/src/js/microqr/tables.js +324 -0
- package/src/js/oned/addons.js +396 -0
- package/src/js/oned/index.js +75 -0
- package/src/js/oned/patterns.js +365 -0
- package/src/js/oned/reader.js +1383 -0
- package/src/js/oned/writers.js +691 -0
- package/src/js/pdf417/compaction.js +391 -0
- package/src/js/pdf417/decoder.js +110 -0
- package/src/js/pdf417/detector.js +484 -0
- package/src/js/pdf417/encoder.js +102 -0
- package/src/js/pdf417/error-correction.js +44 -0
- package/src/{pdf417 → js/pdf417}/index.js +0 -5
- package/src/js/pdf417/tables.js +315 -0
- package/src/js/qr/decoder.js +539 -0
- package/src/js/qr/detector.js +613 -0
- package/src/js/qr/encoder.js +873 -0
- package/src/js/qr/index.js +42 -0
- package/src/js/qr/tables.js +690 -0
- package/src/js/render/image-data.js +120 -0
- package/src/js/render/index.js +128 -0
- package/src/js/render/options.js +152 -0
- package/src/js/render/png.js +270 -0
- package/src/js/render/svg.js +117 -0
- package/src/js/render/webgl.js +200 -0
- package/src/js/render/webgpu.js +357 -0
- package/src/js/rmqr/decoder.js +209 -0
- package/src/js/rmqr/detector.js +122 -0
- package/src/js/rmqr/encoder.js +321 -0
- package/src/js/rmqr/index.js +33 -0
- package/src/js/rmqr/tables.js +177 -0
- package/src/{aztec/decoder.js → ts/aztec/decoder.ts} +0 -1
- package/{typings → src/ts}/aztec/detector.d.ts +2 -2
- package/src/{aztec/detector.js → ts/aztec/detector.ts} +0 -1
- package/src/{aztec/encoder.js → ts/aztec/encoder.ts} +0 -1
- package/src/{aztec/high-level.js → ts/aztec/high-level.ts} +0 -1
- package/src/{aztec/index.js → ts/aztec/index.ts} +0 -1
- package/src/{aztec/tables.js → ts/aztec/tables.ts} +0 -1
- package/src/{aztecrune/decoder.js → ts/aztecrune/decoder.ts} +0 -1
- package/src/{aztecrune/detector.js → ts/aztecrune/detector.ts} +0 -1
- package/src/{aztecrune/encoder.js → ts/aztecrune/encoder.ts} +0 -1
- package/src/{aztecrune/index.js → ts/aztecrune/index.ts} +0 -1
- package/src/{aztecrune/tables.js → ts/aztecrune/tables.ts} +0 -1
- package/src/{compactpdf417/decoder.js → ts/compactpdf417/decoder.ts} +0 -1
- package/src/{compactpdf417/detector.js → ts/compactpdf417/detector.ts} +0 -1
- package/src/{compactpdf417/encoder.js → ts/compactpdf417/encoder.ts} +0 -1
- package/src/{compactpdf417/index.js → ts/compactpdf417/index.ts} +0 -5
- package/src/{compactpdf417/tables.js → ts/compactpdf417/tables.ts} +0 -1
- package/src/{core/bit-buffer.js → ts/core/bit-buffer.ts} +0 -1
- package/src/{core/bit-matrix.js → ts/core/bit-matrix.ts} +0 -1
- package/src/{core/errors.js → ts/core/errors.ts} +0 -1
- package/src/{core/galois-field.js → ts/core/galois-field.ts} +0 -1
- package/src/{core/index.js → ts/core/index.ts} +0 -1
- package/src/{core/reed-solomon.js → ts/core/reed-solomon.ts} +0 -1
- package/src/{databar/codec.js → ts/databar/codec.ts} +0 -1
- package/src/{databar/decoder.js → ts/databar/decoder.ts} +0 -1
- package/src/{databar/encoder.js → ts/databar/encoder.ts} +0 -1
- package/src/{databar/gs1.js → ts/databar/gs1.ts} +0 -1
- package/src/{databar/index.js → ts/databar/index.ts} +0 -1
- package/src/{databar/patterns.js → ts/databar/patterns.ts} +0 -1
- package/src/{databar/tables.js → ts/databar/tables.ts} +0 -1
- package/src/{datamatrix/decoder.js → ts/datamatrix/decoder.ts} +0 -1
- package/{typings → src/ts}/datamatrix/detector.d.ts +2 -2
- package/src/{datamatrix/detector.js → ts/datamatrix/detector.ts} +0 -1
- package/src/{datamatrix/encoder.js → ts/datamatrix/encoder.ts} +0 -1
- package/src/{datamatrix/index.js → ts/datamatrix/index.ts} +0 -1
- package/src/{datamatrix/tables.js → ts/datamatrix/tables.ts} +0 -1
- package/src/{frameqr/decoder.js → ts/frameqr/decoder.ts} +15 -16
- package/src/{frameqr/detector.js → ts/frameqr/detector.ts} +2 -3
- package/src/{frameqr/encoder.js → ts/frameqr/encoder.ts} +7 -8
- package/src/{frameqr/index.js → ts/frameqr/index.ts} +0 -1
- package/src/{frameqr/tables.js → ts/frameqr/tables.ts} +10 -11
- package/src/{image/binarizer.js → ts/image/binarizer.ts} +0 -1
- package/src/{image/grid-sampler.js → ts/image/grid-sampler.ts} +0 -1
- package/src/{image/index.js → ts/image/index.ts} +0 -1
- package/src/{image/luminance.js → ts/image/luminance.ts} +0 -1
- package/src/{image/perspective.js → ts/image/perspective.ts} +0 -1
- package/{typings → src/ts}/index.d.ts +3 -3
- package/src/ts/index.ts +790 -0
- package/src/{micropdf417/compaction.js → ts/micropdf417/compaction.ts} +0 -1
- package/src/{micropdf417/decoder.js → ts/micropdf417/decoder.ts} +0 -1
- package/src/{micropdf417/detector.js → ts/micropdf417/detector.ts} +0 -1
- package/src/{micropdf417/encoder.js → ts/micropdf417/encoder.ts} +0 -1
- package/src/{micropdf417/error-correction.js → ts/micropdf417/error-correction.ts} +0 -1
- package/src/{micropdf417/index.js → ts/micropdf417/index.ts} +0 -1
- package/src/{micropdf417/tables.js → ts/micropdf417/tables.ts} +0 -1
- package/src/{microqr/decoder.js → ts/microqr/decoder.ts} +0 -1
- package/src/{microqr/detector.js → ts/microqr/detector.ts} +0 -1
- package/src/{microqr/encoder.js → ts/microqr/encoder.ts} +0 -1
- package/src/{microqr/index.js → ts/microqr/index.ts} +0 -1
- package/src/{microqr/tables.js → ts/microqr/tables.ts} +0 -1
- package/src/{oned/addons.js → ts/oned/addons.ts} +0 -1
- package/src/{oned/index.js → ts/oned/index.ts} +0 -1
- package/src/{oned/patterns.js → ts/oned/patterns.ts} +0 -1
- package/src/{oned/reader.js → ts/oned/reader.ts} +0 -1
- package/src/{oned/writers.js → ts/oned/writers.ts} +0 -1
- package/src/{pdf417/compaction.js → ts/pdf417/compaction.ts} +0 -1
- package/src/{pdf417/decoder.js → ts/pdf417/decoder.ts} +0 -1
- package/src/{pdf417/detector.js → ts/pdf417/detector.ts} +0 -1
- package/src/{pdf417/encoder.js → ts/pdf417/encoder.ts} +0 -1
- package/src/{pdf417/error-correction.js → ts/pdf417/error-correction.ts} +0 -1
- package/src/ts/pdf417/index.ts +6 -0
- package/src/{pdf417/tables.js → ts/pdf417/tables.ts} +0 -1
- package/src/{qr/decoder.js → ts/qr/decoder.ts} +0 -1
- package/src/{qr/detector.js → ts/qr/detector.ts} +0 -1
- package/src/{qr/encoder.js → ts/qr/encoder.ts} +0 -1
- package/src/{qr/index.js → ts/qr/index.ts} +0 -1
- package/src/{qr/tables.js → ts/qr/tables.ts} +0 -1
- package/src/{render/image-data.js → ts/render/image-data.ts} +0 -1
- package/src/{render/index.js → ts/render/index.ts} +0 -1
- package/src/{render/options.js → ts/render/options.ts} +0 -1
- package/src/{render/png.js → ts/render/png.ts} +0 -1
- package/src/{render/svg.js → ts/render/svg.ts} +0 -1
- package/src/{render/webgl.js → ts/render/webgl.ts} +0 -1
- package/src/{render/webgpu.js → ts/render/webgpu.ts} +0 -1
- package/src/{rmqr/decoder.js → ts/rmqr/decoder.ts} +0 -1
- package/src/{rmqr/detector.js → ts/rmqr/detector.ts} +0 -1
- package/src/{rmqr/encoder.js → ts/rmqr/encoder.ts} +0 -1
- package/src/{rmqr/index.js → ts/rmqr/index.ts} +0 -1
- package/src/{rmqr/tables.js → ts/rmqr/tables.ts} +0 -1
- /package/{typings → src/ts}/aztec/decoder.d.ts +0 -0
- /package/{typings → src/ts}/aztec/encoder.d.ts +0 -0
- /package/{typings → src/ts}/aztec/high-level.d.ts +0 -0
- /package/{typings → src/ts}/aztec/index.d.ts +0 -0
- /package/{typings → src/ts}/aztec/tables.d.ts +0 -0
- /package/{typings → src/ts}/aztecrune/decoder.d.ts +0 -0
- /package/{typings → src/ts}/aztecrune/detector.d.ts +0 -0
- /package/{typings → src/ts}/aztecrune/encoder.d.ts +0 -0
- /package/{typings → src/ts}/aztecrune/index.d.ts +0 -0
- /package/{typings → src/ts}/aztecrune/tables.d.ts +0 -0
- /package/{typings → src/ts}/bundle/sythos-barcode.d.ts +0 -0
- /package/{typings → src/ts}/bundle/sythos-barcode.esm.d.ts +0 -0
- /package/{typings → src/ts}/compactpdf417/decoder.d.ts +0 -0
- /package/{typings → src/ts}/compactpdf417/detector.d.ts +0 -0
- /package/{typings → src/ts}/compactpdf417/encoder.d.ts +0 -0
- /package/{typings → src/ts}/compactpdf417/index.d.ts +0 -0
- /package/{typings → src/ts}/compactpdf417/tables.d.ts +0 -0
- /package/{typings → src/ts}/core/bit-buffer.d.ts +0 -0
- /package/{typings → src/ts}/core/bit-matrix.d.ts +0 -0
- /package/{typings → src/ts}/core/errors.d.ts +0 -0
- /package/{typings → src/ts}/core/galois-field.d.ts +0 -0
- /package/{typings → src/ts}/core/index.d.ts +0 -0
- /package/{typings → src/ts}/core/reed-solomon.d.ts +0 -0
- /package/{typings → src/ts}/databar/codec.d.ts +0 -0
- /package/{typings → src/ts}/databar/decoder.d.ts +0 -0
- /package/{typings → src/ts}/databar/encoder.d.ts +0 -0
- /package/{typings → src/ts}/databar/gs1.d.ts +0 -0
- /package/{typings → src/ts}/databar/index.d.ts +0 -0
- /package/{typings → src/ts}/databar/patterns.d.ts +0 -0
- /package/{typings → src/ts}/databar/tables.d.ts +0 -0
- /package/{typings → src/ts}/datamatrix/decoder.d.ts +0 -0
- /package/{typings → src/ts}/datamatrix/encoder.d.ts +0 -0
- /package/{typings → src/ts}/datamatrix/index.d.ts +0 -0
- /package/{typings → src/ts}/datamatrix/tables.d.ts +0 -0
- /package/{typings → src/ts}/frameqr/decoder.d.ts +0 -0
- /package/{typings → src/ts}/frameqr/detector.d.ts +0 -0
- /package/{typings → src/ts}/frameqr/encoder.d.ts +0 -0
- /package/{typings → src/ts}/frameqr/index.d.ts +0 -0
- /package/{typings → src/ts}/frameqr/tables.d.ts +0 -0
- /package/{typings → src/ts}/image/binarizer.d.ts +0 -0
- /package/{typings → src/ts}/image/grid-sampler.d.ts +0 -0
- /package/{typings → src/ts}/image/index.d.ts +0 -0
- /package/{typings → src/ts}/image/luminance.d.ts +0 -0
- /package/{typings → src/ts}/image/perspective.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/compaction.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/decoder.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/detector.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/encoder.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/error-correction.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/index.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/tables.d.ts +0 -0
- /package/{typings → src/ts}/microqr/decoder.d.ts +0 -0
- /package/{typings → src/ts}/microqr/detector.d.ts +0 -0
- /package/{typings → src/ts}/microqr/encoder.d.ts +0 -0
- /package/{typings → src/ts}/microqr/index.d.ts +0 -0
- /package/{typings → src/ts}/microqr/tables.d.ts +0 -0
- /package/{typings → src/ts}/oned/addons.d.ts +0 -0
- /package/{typings → src/ts}/oned/index.d.ts +0 -0
- /package/{typings → src/ts}/oned/patterns.d.ts +0 -0
- /package/{typings → src/ts}/oned/reader.d.ts +0 -0
- /package/{typings → src/ts}/oned/writers.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/compaction.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/decoder.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/detector.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/encoder.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/error-correction.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/index.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/tables.d.ts +0 -0
- /package/{typings → src/ts}/qr/decoder.d.ts +0 -0
- /package/{typings → src/ts}/qr/detector.d.ts +0 -0
- /package/{typings → src/ts}/qr/encoder.d.ts +0 -0
- /package/{typings → src/ts}/qr/index.d.ts +0 -0
- /package/{typings → src/ts}/qr/tables.d.ts +0 -0
- /package/{typings → src/ts}/render/image-data.d.ts +0 -0
- /package/{typings → src/ts}/render/index.d.ts +0 -0
- /package/{typings → src/ts}/render/options.d.ts +0 -0
- /package/{typings → src/ts}/render/png.d.ts +0 -0
- /package/{typings → src/ts}/render/svg.d.ts +0 -0
- /package/{typings → src/ts}/render/webgl.d.ts +0 -0
- /package/{typings → src/ts}/render/webgpu.d.ts +0 -0
- /package/{typings → src/ts}/rmqr/decoder.d.ts +0 -0
- /package/{typings → src/ts}/rmqr/detector.d.ts +0 -0
- /package/{typings → src/ts}/rmqr/encoder.d.ts +0 -0
- /package/{typings → src/ts}/rmqr/index.d.ts +0 -0
- /package/{typings → src/ts}/rmqr/tables.d.ts +0 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Compact (truncated) PDF417 layout.
|
|
32
|
+
*
|
|
33
|
+
* Compact PDF417 is a geometric variant of PDF417, not a new high-level
|
|
34
|
+
* compaction mode. It keeps the same codeword, cluster, row-indicator,
|
|
35
|
+
* Reed–Solomon and Text/Byte/Numeric compaction rules, while omitting each
|
|
36
|
+
* row's right row indicator and replacing the normal stop pattern with a
|
|
37
|
+
* single dark module. The resulting symbol remains distinguishable from the
|
|
38
|
+
* ordinary PDF417 layout by its width and row terminator.
|
|
39
|
+
*
|
|
40
|
+
* @module compactpdf417/tables
|
|
41
|
+
*/
|
|
42
|
+
import { EncodeError } from '../core/errors.js';
|
|
43
|
+
/** PDF417 start pattern, in module widths. */
|
|
44
|
+
export const COMPACT_PDF417_START = '81111113';
|
|
45
|
+
/** Binary module representation of the start pattern. */
|
|
46
|
+
export const COMPACT_PDF417_START_BITS = '11111111010101000';
|
|
47
|
+
/** Compact PDF417's reduced stop is one dark module. */
|
|
48
|
+
export const COMPACT_PDF417_STOP_MODULES = 1;
|
|
49
|
+
/** Minimum/maximum number of rows and data columns. */
|
|
50
|
+
export const COMPACT_PDF417_LIMITS = Object.freeze({
|
|
51
|
+
minRows: 3,
|
|
52
|
+
maxRows: 90,
|
|
53
|
+
minColumns: 1,
|
|
54
|
+
maxColumns: 30,
|
|
55
|
+
maxCodewords: 928,
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Return the printed width in modules for a compact symbol.
|
|
59
|
+
*
|
|
60
|
+
* 17 start + 17 left indicator + 17 per codeword column + 1 reduced stop.
|
|
61
|
+
* @param {number} columns
|
|
62
|
+
*/
|
|
63
|
+
export function compactPdf417Width(columns) {
|
|
64
|
+
if (!Number.isInteger(columns) || columns < 1 || columns > 30) {
|
|
65
|
+
throw new RangeError(`Compact PDF417: columns must be an integer in 1..30, got ${columns}`);
|
|
66
|
+
}
|
|
67
|
+
return 35 + columns * 17;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Validate a compact matrix geometry and return its dimensions.
|
|
71
|
+
*
|
|
72
|
+
* @param {number} width
|
|
73
|
+
* @param {number} height
|
|
74
|
+
* @param {number} rowHeight
|
|
75
|
+
*/
|
|
76
|
+
export function compactPdf417Geometry(width, height, rowHeight = 3) {
|
|
77
|
+
if (!Number.isInteger(width) || !Number.isInteger(height)) {
|
|
78
|
+
throw new RangeError('Compact PDF417: matrix dimensions must be integers');
|
|
79
|
+
}
|
|
80
|
+
if (!Number.isInteger(rowHeight) || rowHeight < 1) {
|
|
81
|
+
throw new RangeError('Compact PDF417: rowHeight must be a positive integer');
|
|
82
|
+
}
|
|
83
|
+
if ((width - 35) % 17 !== 0) {
|
|
84
|
+
throw new RangeError(`Compact PDF417: width ${width} does not match the compact layout`);
|
|
85
|
+
}
|
|
86
|
+
const columns = (width - 35) / 17;
|
|
87
|
+
const rows = height / rowHeight;
|
|
88
|
+
if (!Number.isInteger(rows) || rows < 3 || rows > 90) {
|
|
89
|
+
throw new RangeError(`Compact PDF417: rows must be an integer in 3..90, got ${rows}`);
|
|
90
|
+
}
|
|
91
|
+
if (columns < 1 || columns > 30) {
|
|
92
|
+
throw new RangeError(`Compact PDF417: columns must be an integer in 1..30, got ${columns}`);
|
|
93
|
+
}
|
|
94
|
+
return { rows, columns, rowHeight, width, height };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validate encoder dimensions before codeword packing.
|
|
98
|
+
* @param {object} options
|
|
99
|
+
*/
|
|
100
|
+
export function validateCompactPdf417Options(options = {}) {
|
|
101
|
+
const { minRows, maxRows, minColumns, maxColumns } = COMPACT_PDF417_LIMITS;
|
|
102
|
+
const rowHeight = options.rowHeight ?? 3;
|
|
103
|
+
if (!Number.isInteger(rowHeight) || rowHeight < 3) {
|
|
104
|
+
throw new EncodeError('Compact PDF417: rowHeight must be an integer of at least 3');
|
|
105
|
+
}
|
|
106
|
+
for (const [name, value, min, max] of [
|
|
107
|
+
['rows', options.rows, minRows, maxRows],
|
|
108
|
+
['columns', options.columns, minColumns, maxColumns],
|
|
109
|
+
]) {
|
|
110
|
+
if (value !== undefined && (!Number.isInteger(value) || value < min || value > max)) {
|
|
111
|
+
throw new EncodeError(`Compact PDF417: ${name} must be an integer in ${min}..${max}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (options.aspectRatio !== undefined &&
|
|
115
|
+
(!Number.isFinite(options.aspectRatio) || options.aspectRatio <= 0)) {
|
|
116
|
+
throw new EncodeError('Compact PDF417: aspectRatio must be positive');
|
|
117
|
+
}
|
|
118
|
+
return rowHeight;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The row indicator values used by ordinary PDF417 are retained unchanged.
|
|
122
|
+
* Compact symbols omit only the right indicator, so the left indicator still
|
|
123
|
+
* carries the row group, row count, error-correction level and column count.
|
|
124
|
+
*/
|
|
125
|
+
export function compactPdf417Indicators(row, rows, columns, level) {
|
|
126
|
+
const group = Math.floor(row / 3);
|
|
127
|
+
const y = Math.floor((rows - 1) / 3);
|
|
128
|
+
const z = level * 3 + (rows - 1) % 3;
|
|
129
|
+
const v = columns - 1;
|
|
130
|
+
if (row % 3 === 0)
|
|
131
|
+
return 30 * group + y;
|
|
132
|
+
if (row % 3 === 1)
|
|
133
|
+
return 30 * group + z;
|
|
134
|
+
return 30 * group + v;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Return all standard ECC levels which agree with the observed left
|
|
138
|
+
* indicators. This is kept as a table helper so decoder and tests share the
|
|
139
|
+
* same compact-layout rule.
|
|
140
|
+
*/
|
|
141
|
+
export function compactPdf417MatchingLevels(leftIndicators, rows, columns) {
|
|
142
|
+
const matches = [];
|
|
143
|
+
for (let level = 0; level <= 8; level++) {
|
|
144
|
+
if (leftIndicators.every((value, row) => value === compactPdf417Indicators(row, rows, columns, level)))
|
|
145
|
+
matches.push(level);
|
|
146
|
+
}
|
|
147
|
+
return matches;
|
|
148
|
+
}
|
|
149
|
+
/** Validate representative layout invariants. */
|
|
150
|
+
export function validateCompactPdf417Tables() {
|
|
151
|
+
const problems = [];
|
|
152
|
+
for (const columns of [1, 2, 3, 10, 30]) {
|
|
153
|
+
const width = compactPdf417Width(columns);
|
|
154
|
+
if (width !== 35 + columns * 17)
|
|
155
|
+
problems.push(`columns ${columns}: width mismatch`);
|
|
156
|
+
}
|
|
157
|
+
for (const rows of [3, 4, 5, 6, 90]) {
|
|
158
|
+
const left = Array.from({ length: rows }, (_, row) => compactPdf417Indicators(row, rows, 3, 2));
|
|
159
|
+
if (compactPdf417MatchingLevels(left, rows, 3).length !== 1) {
|
|
160
|
+
problems.push(`rows ${rows}: row indicators do not identify one ECC level`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return problems;
|
|
164
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Bit-level writing and reading, MSB-first.
|
|
32
|
+
*
|
|
33
|
+
* Every 2D symbology serialises its payload as a bitstream that does not
|
|
34
|
+
* respect byte boundaries — QR alone mixes 4-bit mode indicators, 10-bit
|
|
35
|
+
* character-count fields and 11-bit alphanumeric pairs. These two classes are
|
|
36
|
+
* the write and read halves of that.
|
|
37
|
+
*
|
|
38
|
+
* @module core/bit-buffer
|
|
39
|
+
*/
|
|
40
|
+
import { FormatError } from './errors.js';
|
|
41
|
+
/** Growable MSB-first bit writer. */
|
|
42
|
+
export class BitWriter {
|
|
43
|
+
constructor() {
|
|
44
|
+
/** @type {number[]} Packed bytes; the last one may be partially filled. */
|
|
45
|
+
this.bytes = [];
|
|
46
|
+
this.bitLength = 0;
|
|
47
|
+
}
|
|
48
|
+
/** @returns {number} Bits written so far. */
|
|
49
|
+
get length() {
|
|
50
|
+
return this.bitLength;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Append the low `count` bits of `value`, most significant first.
|
|
54
|
+
*
|
|
55
|
+
* @param {number} value
|
|
56
|
+
* @param {number} count
|
|
57
|
+
*/
|
|
58
|
+
put(value, count) {
|
|
59
|
+
for (let i = count - 1; i >= 0; i--) {
|
|
60
|
+
this.putBit(((value >>> i) & 1) === 1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** @param {boolean} bit */
|
|
64
|
+
putBit(bit) {
|
|
65
|
+
const idx = this.bitLength >>> 3;
|
|
66
|
+
if (this.bytes.length <= idx)
|
|
67
|
+
this.bytes.push(0);
|
|
68
|
+
if (bit)
|
|
69
|
+
this.bytes[idx] |= 0x80 >>> (this.bitLength & 7);
|
|
70
|
+
this.bitLength++;
|
|
71
|
+
}
|
|
72
|
+
/** @param {ArrayLike<number>} data */
|
|
73
|
+
putBytes(data) {
|
|
74
|
+
for (let i = 0; i < data.length; i++)
|
|
75
|
+
this.put(data[i], 8);
|
|
76
|
+
}
|
|
77
|
+
/** Pad with zero bits until the length is a multiple of 8. */
|
|
78
|
+
padToByte() {
|
|
79
|
+
while (this.bitLength & 7)
|
|
80
|
+
this.putBit(false);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* @returns {Uint8Array} Byte view; trailing bits of the final byte are zero.
|
|
84
|
+
*/
|
|
85
|
+
toBytes() {
|
|
86
|
+
return Uint8Array.from(this.bytes);
|
|
87
|
+
}
|
|
88
|
+
/** @returns {string} Debug view, e.g. "0100 0011 0101". */
|
|
89
|
+
toString() {
|
|
90
|
+
let s = '';
|
|
91
|
+
for (let i = 0; i < this.bitLength; i++) {
|
|
92
|
+
if (i && i % 4 === 0)
|
|
93
|
+
s += ' ';
|
|
94
|
+
s += (this.bytes[i >>> 3] >>> (7 - (i & 7))) & 1;
|
|
95
|
+
}
|
|
96
|
+
return s;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** MSB-first bit reader over a byte array. */
|
|
100
|
+
export class BitReader {
|
|
101
|
+
/** @param {ArrayLike<number>} bytes */
|
|
102
|
+
constructor(bytes) {
|
|
103
|
+
this.bytes = bytes;
|
|
104
|
+
this.byteOffset = 0;
|
|
105
|
+
this.bitOffset = 0;
|
|
106
|
+
}
|
|
107
|
+
/** @returns {number} Bits not yet consumed. */
|
|
108
|
+
available() {
|
|
109
|
+
return 8 * (this.bytes.length - this.byteOffset) - this.bitOffset;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Read `count` bits (1..32) as an unsigned integer, most significant first.
|
|
113
|
+
*
|
|
114
|
+
* @param {number} count
|
|
115
|
+
* @returns {number}
|
|
116
|
+
* @throws {FormatError} If the stream is exhausted.
|
|
117
|
+
*/
|
|
118
|
+
read(count) {
|
|
119
|
+
if (count < 1 || count > 32) {
|
|
120
|
+
throw new FormatError(`BitReader: cannot read ${count} bits`);
|
|
121
|
+
}
|
|
122
|
+
if (count > this.available()) {
|
|
123
|
+
throw new FormatError(`BitReader: needed ${count} bits, ${this.available()} remain`);
|
|
124
|
+
}
|
|
125
|
+
let result = 0;
|
|
126
|
+
let remaining = count;
|
|
127
|
+
// Finish the partially consumed byte first, then take whole bytes.
|
|
128
|
+
if (this.bitOffset > 0) {
|
|
129
|
+
const inCurrent = 8 - this.bitOffset;
|
|
130
|
+
const take = Math.min(remaining, inCurrent);
|
|
131
|
+
const shift = inCurrent - take;
|
|
132
|
+
const mask = (0xff >> this.bitOffset) & ~((1 << shift) - 1);
|
|
133
|
+
result = (this.bytes[this.byteOffset] & mask) >> shift;
|
|
134
|
+
remaining -= take;
|
|
135
|
+
this.bitOffset += take;
|
|
136
|
+
if (this.bitOffset === 8) {
|
|
137
|
+
this.bitOffset = 0;
|
|
138
|
+
this.byteOffset++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
while (remaining >= 8) {
|
|
142
|
+
result = (result << 8) | (this.bytes[this.byteOffset] & 0xff);
|
|
143
|
+
this.byteOffset++;
|
|
144
|
+
remaining -= 8;
|
|
145
|
+
}
|
|
146
|
+
if (remaining > 0) {
|
|
147
|
+
const shift = 8 - remaining;
|
|
148
|
+
const mask = ~((1 << shift) - 1) & 0xff;
|
|
149
|
+
result = (result << remaining) | ((this.bytes[this.byteOffset] & mask) >> shift);
|
|
150
|
+
this.bitOffset += remaining;
|
|
151
|
+
}
|
|
152
|
+
return result >>> 0;
|
|
153
|
+
}
|
|
154
|
+
/** @returns {boolean} */
|
|
155
|
+
readBit() {
|
|
156
|
+
return this.read(1) === 1;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* A 2D bit grid — the common currency of this library.
|
|
32
|
+
*
|
|
33
|
+
* Every writer produces one; every reader consumes one; every renderer draws
|
|
34
|
+
* one. Keeping it as the single interchange type is what lets formats and
|
|
35
|
+
* output targets stay independent of each other.
|
|
36
|
+
*
|
|
37
|
+
* Storage is row-packed into a Uint32Array: one allocation, cache-friendly row
|
|
38
|
+
* scans, and cheap whole-row operations for the 1D readers.
|
|
39
|
+
*
|
|
40
|
+
* Convention: a set bit is a DARK module (ink). This matches how symbols are
|
|
41
|
+
* described in every specification, and renderers invert as needed.
|
|
42
|
+
*
|
|
43
|
+
* @module core/bit-matrix
|
|
44
|
+
*/
|
|
45
|
+
export class BitMatrix {
|
|
46
|
+
/**
|
|
47
|
+
* @param {number} width
|
|
48
|
+
* @param {number} height
|
|
49
|
+
*/
|
|
50
|
+
constructor(width, height = width) {
|
|
51
|
+
if (width < 1 || height < 1) {
|
|
52
|
+
throw new Error(`BitMatrix: dimensions must be positive, got ${width}x${height}`);
|
|
53
|
+
}
|
|
54
|
+
this.width = width;
|
|
55
|
+
this.height = height;
|
|
56
|
+
this.rowWords = Math.ceil(width / 32);
|
|
57
|
+
this.bits = new Uint32Array(this.rowWords * height);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* @param {number} x @param {number} y
|
|
61
|
+
* @returns {boolean} True if the module is dark.
|
|
62
|
+
*/
|
|
63
|
+
get(x, y) {
|
|
64
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height)
|
|
65
|
+
return false;
|
|
66
|
+
return ((this.bits[y * this.rowWords + (x >>> 5)] >>> (x & 31)) & 1) === 1;
|
|
67
|
+
}
|
|
68
|
+
/** @param {number} x @param {number} y */
|
|
69
|
+
set(x, y) {
|
|
70
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height)
|
|
71
|
+
return;
|
|
72
|
+
this.bits[y * this.rowWords + (x >>> 5)] |= 1 << (x & 31);
|
|
73
|
+
}
|
|
74
|
+
/** @param {number} x @param {number} y */
|
|
75
|
+
unset(x, y) {
|
|
76
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height)
|
|
77
|
+
return;
|
|
78
|
+
this.bits[y * this.rowWords + (x >>> 5)] &= ~(1 << (x & 31));
|
|
79
|
+
}
|
|
80
|
+
/** @param {number} x @param {number} y */
|
|
81
|
+
flip(x, y) {
|
|
82
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height)
|
|
83
|
+
return;
|
|
84
|
+
this.bits[y * this.rowWords + (x >>> 5)] ^= 1 << (x & 31);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* @param {number} x @param {number} y @param {boolean} value
|
|
88
|
+
*/
|
|
89
|
+
setValue(x, y, value) {
|
|
90
|
+
if (value)
|
|
91
|
+
this.set(x, y);
|
|
92
|
+
else
|
|
93
|
+
this.unset(x, y);
|
|
94
|
+
}
|
|
95
|
+
/** Fill a rectangle. @param {number} x @param {number} y @param {number} w @param {number} h */
|
|
96
|
+
setRegion(x, y, w, h) {
|
|
97
|
+
for (let j = y; j < y + h; j++) {
|
|
98
|
+
for (let i = x; i < x + w; i++)
|
|
99
|
+
this.set(i, j);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
clear() {
|
|
103
|
+
this.bits.fill(0);
|
|
104
|
+
}
|
|
105
|
+
/** @returns {BitMatrix} */
|
|
106
|
+
clone() {
|
|
107
|
+
const m = new BitMatrix(this.width, this.height);
|
|
108
|
+
m.bits.set(this.bits);
|
|
109
|
+
return m;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Copy row `y` into a reusable array, avoiding an allocation per row in the
|
|
113
|
+
* 1D scanning loops which run this thousands of times per image.
|
|
114
|
+
*
|
|
115
|
+
* @param {number} y
|
|
116
|
+
* @param {Uint8Array} [out]
|
|
117
|
+
* @returns {Uint8Array}
|
|
118
|
+
*/
|
|
119
|
+
getRow(y, out) {
|
|
120
|
+
const row = out && out.length >= this.width ? out : new Uint8Array(this.width);
|
|
121
|
+
const base = y * this.rowWords;
|
|
122
|
+
for (let x = 0; x < this.width; x++) {
|
|
123
|
+
row[x] = (this.bits[base + (x >>> 5)] >>> (x & 31)) & 1;
|
|
124
|
+
}
|
|
125
|
+
return row;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Add a uniform light border. Symbols need a quiet zone to be scannable at
|
|
129
|
+
* all, so this is applied by default when rendering.
|
|
130
|
+
*
|
|
131
|
+
* @param {number} size Modules of margin on every side.
|
|
132
|
+
* @returns {BitMatrix}
|
|
133
|
+
*/
|
|
134
|
+
withMargin(size) {
|
|
135
|
+
if (size <= 0)
|
|
136
|
+
return this.clone();
|
|
137
|
+
const m = new BitMatrix(this.width + size * 2, this.height + size * 2);
|
|
138
|
+
for (let y = 0; y < this.height; y++) {
|
|
139
|
+
for (let x = 0; x < this.width; x++) {
|
|
140
|
+
if (this.get(x, y))
|
|
141
|
+
m.set(x + size, y + size);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return m;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Nearest-neighbour upscale. Integer factors only — a barcode resampled with
|
|
148
|
+
* interpolation stops being readable.
|
|
149
|
+
*
|
|
150
|
+
* @param {number} factor
|
|
151
|
+
* @returns {BitMatrix}
|
|
152
|
+
*/
|
|
153
|
+
scale(factor) {
|
|
154
|
+
const f = Math.max(1, Math.floor(factor));
|
|
155
|
+
if (f === 1)
|
|
156
|
+
return this.clone();
|
|
157
|
+
const m = new BitMatrix(this.width * f, this.height * f);
|
|
158
|
+
for (let y = 0; y < this.height; y++) {
|
|
159
|
+
for (let x = 0; x < this.width; x++) {
|
|
160
|
+
if (this.get(x, y))
|
|
161
|
+
m.setRegion(x * f, y * f, f, f);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return m;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Bounding box of the dark modules, or null if the matrix is empty.
|
|
168
|
+
* @returns {{x: number, y: number, width: number, height: number} | null}
|
|
169
|
+
*/
|
|
170
|
+
getBounds() {
|
|
171
|
+
let minX = this.width, minY = this.height, maxX = -1, maxY = -1;
|
|
172
|
+
for (let y = 0; y < this.height; y++) {
|
|
173
|
+
for (let x = 0; x < this.width; x++) {
|
|
174
|
+
if (this.get(x, y)) {
|
|
175
|
+
if (x < minX)
|
|
176
|
+
minX = x;
|
|
177
|
+
if (x > maxX)
|
|
178
|
+
maxX = x;
|
|
179
|
+
if (y < minY)
|
|
180
|
+
minY = y;
|
|
181
|
+
if (y > maxY)
|
|
182
|
+
maxY = y;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (maxX < 0)
|
|
187
|
+
return null;
|
|
188
|
+
return { x: minX, y: minY, width: maxX - minX + 1, height: maxY - minY + 1 };
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Rotate 180 degrees, in place. Cheaper than re-detecting when a reader
|
|
192
|
+
* discovers a symbol is upside down.
|
|
193
|
+
*/
|
|
194
|
+
rotate180() {
|
|
195
|
+
const w = this.width, h = this.height;
|
|
196
|
+
for (let y = 0; y < Math.ceil(h / 2); y++) {
|
|
197
|
+
for (let x = 0; x < w; x++) {
|
|
198
|
+
const oy = h - 1 - y, ox = w - 1 - x;
|
|
199
|
+
if (y === oy && x >= ox)
|
|
200
|
+
break;
|
|
201
|
+
const a = this.get(x, y);
|
|
202
|
+
const b = this.get(ox, oy);
|
|
203
|
+
this.setValue(x, y, b);
|
|
204
|
+
this.setValue(ox, oy, a);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Build from a string of '1'/'X'/'#' (dark) and anything else (light),
|
|
210
|
+
* newline-separated. Test fixtures are far more legible this way.
|
|
211
|
+
*
|
|
212
|
+
* @param {string} text
|
|
213
|
+
* @returns {BitMatrix}
|
|
214
|
+
*/
|
|
215
|
+
static parse(text) {
|
|
216
|
+
const lines = text.trim().split('\n').map((l) => l.trim()).filter((l) => l.length);
|
|
217
|
+
const height = lines.length;
|
|
218
|
+
const width = Math.max(...lines.map((l) => l.length));
|
|
219
|
+
const m = new BitMatrix(width, height);
|
|
220
|
+
for (let y = 0; y < height; y++) {
|
|
221
|
+
for (let x = 0; x < lines[y].length; x++) {
|
|
222
|
+
const c = lines[y][x];
|
|
223
|
+
if (c === '1' || c === 'X' || c === 'x' || c === '#')
|
|
224
|
+
m.set(x, y);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return m;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* @param {string} [dark] @param {string} [light]
|
|
231
|
+
* @returns {string}
|
|
232
|
+
*/
|
|
233
|
+
toString(dark = '##', light = ' ') {
|
|
234
|
+
const rows = [];
|
|
235
|
+
for (let y = 0; y < this.height; y++) {
|
|
236
|
+
let s = '';
|
|
237
|
+
for (let x = 0; x < this.width; x++)
|
|
238
|
+
s += this.get(x, y) ? dark : light;
|
|
239
|
+
rows.push(s);
|
|
240
|
+
}
|
|
241
|
+
return rows.join('\n');
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Error types.
|
|
32
|
+
*
|
|
33
|
+
* Decoding uses exceptions for control flow internally: a detector that fails
|
|
34
|
+
* on one candidate should be cheap to abandon, and a `try` around a candidate
|
|
35
|
+
* loop reads better than threading `null` through six call frames. The public
|
|
36
|
+
* API converts them to results.
|
|
37
|
+
*
|
|
38
|
+
* @module core/errors
|
|
39
|
+
*/
|
|
40
|
+
/** Base class so consumers can `catch (e) { if (e instanceof BarcodeError) ... }`. */
|
|
41
|
+
export class BarcodeError extends Error {
|
|
42
|
+
/** @param {string} message */
|
|
43
|
+
constructor(message) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = new.target.name;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** Input could not be encoded — bad payload, or it does not fit the symbology. */
|
|
49
|
+
export class EncodeError extends BarcodeError {
|
|
50
|
+
}
|
|
51
|
+
/** No symbol was found in the image. Not an error condition for `decode()`. */
|
|
52
|
+
export class NotFoundError extends BarcodeError {
|
|
53
|
+
}
|
|
54
|
+
/** A symbol was found, but its geometry or content is malformed. */
|
|
55
|
+
export class FormatError extends BarcodeError {
|
|
56
|
+
}
|
|
57
|
+
/** A symbol was found and read, but error correction could not repair it. */
|
|
58
|
+
export class ChecksumError extends BarcodeError {
|
|
59
|
+
}
|