@sythos/js_barcode_universal 1.5.8 → 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 +17 -13
- package/bundle/sythos-barcode.esm.js +11658 -11244
- package/bundle/sythos-barcode.js +11658 -11244
- package/package.json +10 -3
- package/src/index.d.ts +1 -1
- package/src/index.js +508 -516
- package/src/js/aztec/decoder.js +208 -199
- package/src/js/aztec/detector.js +153 -126
- package/src/js/aztec/encoder.js +172 -153
- package/src/js/aztec/high-level.js +106 -101
- package/src/js/aztec/index.js +1 -12
- package/src/js/aztec/tables.js +106 -120
- package/src/js/aztecrune/decoder.js +76 -85
- package/src/js/aztecrune/detector.js +107 -93
- package/src/js/aztecrune/encoder.js +50 -68
- package/src/js/aztecrune/index.js +1 -16
- package/src/js/aztecrune/tables.js +59 -54
- package/src/js/compactpdf417/decoder.js +69 -74
- package/src/js/compactpdf417/detector.js +74 -75
- package/src/js/compactpdf417/encoder.js +68 -81
- package/src/js/compactpdf417/index.js +1 -13
- package/src/js/compactpdf417/tables.js +71 -80
- package/src/js/core/bit-buffer.js +106 -122
- package/src/js/core/bit-matrix.js +196 -194
- package/src/js/core/errors.js +13 -15
- package/src/js/core/galois-field.js +119 -133
- package/src/js/core/index.js +2 -19
- package/src/js/core/reed-solomon.js +195 -204
- package/src/js/databar/codec.js +93 -108
- package/src/js/databar/decoder.js +149 -140
- package/src/js/databar/encoder.js +47 -55
- package/src/js/databar/gs1.js +122 -123
- package/src/js/databar/index.js +4 -36
- package/src/js/databar/patterns.js +81 -85
- package/src/js/databar/tables.js +51 -52
- package/src/js/datamatrix/decoder.js +216 -182
- package/src/js/datamatrix/detector.js +161 -132
- package/src/js/datamatrix/encoder.js +192 -133
- package/src/js/datamatrix/index.js +1 -9
- package/src/js/datamatrix/tables.js +68 -69
- package/src/js/frameqr/decoder.js +102 -125
- package/src/js/frameqr/detector.js +101 -94
- package/src/js/frameqr/encoder.js +67 -80
- package/src/js/frameqr/index.js +1 -10
- package/src/js/frameqr/tables.js +145 -163
- package/src/js/image/binarizer.js +146 -162
- package/src/js/image/grid-sampler.js +63 -79
- package/src/js/image/index.js +0 -2
- package/src/js/image/luminance.js +129 -140
- package/src/js/image/perspective.js +112 -149
- package/src/js/micropdf417/compaction.js +64 -65
- package/src/js/micropdf417/decoder.js +106 -109
- package/src/js/micropdf417/detector.js +73 -70
- package/src/js/micropdf417/encoder.js +129 -154
- package/src/js/micropdf417/error-correction.js +6 -11
- package/src/js/micropdf417/index.js +2 -16
- package/src/js/micropdf417/tables.js +112 -99
- package/src/js/microqr/decoder.js +177 -182
- package/src/js/microqr/detector.js +240 -256
- package/src/js/microqr/encoder.js +239 -194
- package/src/js/microqr/index.js +0 -2
- package/src/js/microqr/tables.js +208 -200
- package/src/js/oned/addons.js +167 -191
- package/src/js/oned/index.js +27 -58
- package/src/js/oned/patterns.js +194 -213
- package/src/js/oned/reader.js +1003 -984
- package/src/js/oned/writers.js +411 -466
- package/src/js/pdf417/compaction.js +315 -222
- package/src/js/pdf417/decoder.js +71 -36
- package/src/js/pdf417/detector.js +377 -361
- package/src/js/pdf417/encoder.js +57 -46
- package/src/js/pdf417/error-correction.js +5 -8
- package/src/js/pdf417/tables.js +248 -250
- package/src/js/qr/decoder.js +311 -347
- package/src/js/qr/detector.js +378 -395
- package/src/js/qr/encoder.js +514 -599
- package/src/js/qr/index.js +0 -2
- package/src/js/qr/tables.js +375 -422
- package/src/js/render/image-data.js +57 -62
- package/src/js/render/index.js +21 -23
- package/src/js/render/options.js +82 -90
- package/src/js/render/png.js +144 -169
- package/src/js/render/svg.js +41 -44
- package/src/js/render/webgl.js +103 -109
- package/src/js/render/webgpu.js +205 -217
- package/src/js/rmqr/decoder.js +161 -53
- package/src/js/rmqr/detector.js +73 -41
- package/src/js/rmqr/encoder.js +253 -104
- package/src/js/rmqr/index.js +1 -5
- package/src/js/rmqr/tables.js +108 -85
- package/src/ts/aztec/decoder.ts +317 -0
- package/src/ts/aztec/detector.ts +224 -0
- package/src/ts/aztec/encoder.ts +257 -0
- package/src/ts/aztec/high-level.ts +211 -0
- package/src/ts/aztec/index.ts +45 -0
- package/src/ts/aztec/tables.ts +210 -0
- package/src/ts/aztecrune/decoder.ts +155 -0
- package/src/ts/aztecrune/detector.ts +166 -0
- package/src/ts/aztecrune/encoder.ts +121 -0
- package/src/ts/aztecrune/index.ts +49 -0
- package/src/ts/aztecrune/tables.ts +137 -0
- package/src/ts/compactpdf417/decoder.ts +128 -0
- package/src/ts/compactpdf417/detector.ts +139 -0
- package/src/ts/compactpdf417/encoder.ts +140 -0
- package/src/ts/compactpdf417/index.ts +17 -0
- package/src/ts/compactpdf417/tables.ts +173 -0
- package/src/ts/core/bit-buffer.ts +174 -0
- package/src/ts/core/bit-matrix.ts +241 -0
- package/src/ts/core/errors.ts +61 -0
- package/src/ts/core/galois-field.ts +207 -0
- package/src/ts/core/index.ts +56 -0
- package/src/ts/core/reed-solomon.ts +327 -0
- package/src/ts/databar/codec.ts +181 -0
- package/src/ts/databar/decoder.ts +215 -0
- package/src/ts/databar/encoder.ts +96 -0
- package/src/ts/databar/gs1.ts +177 -0
- package/src/ts/databar/index.ts +68 -0
- package/src/ts/databar/patterns.ts +143 -0
- package/src/ts/databar/tables.ts +124 -0
- package/src/ts/datamatrix/decoder.ts +262 -0
- package/src/ts/datamatrix/detector.ts +225 -0
- package/src/ts/datamatrix/encoder.ts +191 -0
- package/src/ts/datamatrix/index.ts +42 -0
- package/src/ts/datamatrix/tables.ts +123 -0
- package/src/ts/frameqr/decoder.ts +239 -0
- package/src/ts/frameqr/detector.ts +192 -0
- package/src/ts/frameqr/encoder.ts +156 -0
- package/src/ts/frameqr/index.ts +42 -0
- package/src/ts/frameqr/tables.ts +270 -0
- package/src/ts/image/binarizer.ts +270 -0
- package/src/ts/image/grid-sampler.ts +164 -0
- package/src/ts/image/index.ts +40 -0
- package/src/ts/image/luminance.ts +196 -0
- package/src/ts/image/perspective.ts +195 -0
- package/src/ts/index.d.ts +1 -1
- package/src/ts/index.ts +790 -0
- package/src/ts/micropdf417/compaction.ts +116 -0
- package/src/ts/micropdf417/decoder.ts +183 -0
- package/src/ts/micropdf417/detector.ts +149 -0
- package/src/ts/micropdf417/encoder.ts +209 -0
- package/src/ts/micropdf417/error-correction.ts +55 -0
- package/src/ts/micropdf417/index.ts +49 -0
- package/src/ts/micropdf417/tables.ts +184 -0
- package/src/ts/microqr/decoder.ts +245 -0
- package/src/ts/microqr/detector.ts +355 -0
- package/src/ts/microqr/encoder.ts +269 -0
- package/src/ts/microqr/index.ts +36 -0
- package/src/ts/microqr/tables.ts +316 -0
- package/src/ts/oned/addons.ts +420 -0
- package/src/ts/oned/index.ts +106 -0
- package/src/ts/oned/patterns.ts +384 -0
- package/src/ts/oned/reader.ts +1364 -0
- package/src/ts/oned/writers.ts +746 -0
- package/src/ts/pdf417/compaction.ts +298 -0
- package/src/ts/pdf417/decoder.ts +75 -0
- package/src/ts/pdf417/detector.ts +468 -0
- package/src/ts/pdf417/encoder.ts +91 -0
- package/src/ts/pdf417/error-correction.ts +47 -0
- package/src/ts/pdf417/index.ts +6 -0
- package/src/ts/pdf417/tables.ts +317 -0
- package/src/ts/qr/decoder.ts +575 -0
- package/src/ts/qr/detector.ts +630 -0
- package/src/ts/qr/encoder.ts +958 -0
- package/src/ts/qr/index.ts +44 -0
- package/src/ts/qr/tables.ts +737 -0
- package/src/ts/render/image-data.ts +125 -0
- package/src/ts/render/index.ts +130 -0
- package/src/ts/render/options.ts +160 -0
- package/src/ts/render/png.ts +295 -0
- package/src/ts/render/svg.ts +120 -0
- package/src/ts/render/webgl.ts +206 -0
- package/src/ts/render/webgpu.ts +369 -0
- package/src/ts/rmqr/decoder.ts +101 -0
- package/src/ts/rmqr/detector.ts +90 -0
- package/src/ts/rmqr/encoder.ts +172 -0
- package/src/ts/rmqr/index.ts +37 -0
- package/src/ts/rmqr/tables.ts +154 -0
|
@@ -0,0 +1,116 @@
|
|
|
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
|
+
/** MicroPDF417 high-level compaction adapter. @module micropdf417/compaction */
|
|
32
|
+
|
|
33
|
+
import { EncodeError } from '../core/errors.js';
|
|
34
|
+
import {
|
|
35
|
+
compactPdf417Bytes,
|
|
36
|
+
compactPdf417Numeric,
|
|
37
|
+
compactPdf417Text,
|
|
38
|
+
} from '../pdf417/compaction.js';
|
|
39
|
+
|
|
40
|
+
function byteLength(value) {
|
|
41
|
+
if (value instanceof Uint8Array) return value.byteLength;
|
|
42
|
+
if (ArrayBuffer.isView(value)) return value.byteLength;
|
|
43
|
+
return -1;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function assertNotEmpty(value) {
|
|
47
|
+
if ((typeof value === 'string' && value.length === 0) || byteLength(value) === 0) {
|
|
48
|
+
throw new EncodeError('MicroPDF417: value must not be empty');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function latin1Bytes(value) {
|
|
53
|
+
if (typeof value !== 'string') return value;
|
|
54
|
+
const bytes = [];
|
|
55
|
+
for (const character of value) {
|
|
56
|
+
const codePoint = character.codePointAt(0);
|
|
57
|
+
if (codePoint > 255) {
|
|
58
|
+
throw new EncodeError('MicroPDF417 ECI 3: string contains a character outside ISO-8859-1');
|
|
59
|
+
}
|
|
60
|
+
bytes.push(codePoint);
|
|
61
|
+
}
|
|
62
|
+
return Uint8Array.from(bytes);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function compactByte(value, eci) {
|
|
66
|
+
if (eci === undefined) return compactPdf417Bytes(value);
|
|
67
|
+
if (eci === 3) return compactPdf417Bytes(latin1Bytes(value));
|
|
68
|
+
if (eci === 26) {
|
|
69
|
+
if (typeof value !== 'string') {
|
|
70
|
+
throw new EncodeError('MicroPDF417 ECI 26: value must be a string so UTF-8 validity is known');
|
|
71
|
+
}
|
|
72
|
+
const encoded = compactPdf417Bytes(value);
|
|
73
|
+
return encoded[0] === 927 && encoded[1] === 26 ? encoded : [927, 26, ...encoded];
|
|
74
|
+
}
|
|
75
|
+
throw new EncodeError('MicroPDF417: supported ECI assignment numbers are 3 and 26');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Compact one MicroPDF417 value.
|
|
80
|
+
*
|
|
81
|
+
* Unlike PDF417, MicroPDF417 starts in Byte Compaction. Text therefore needs
|
|
82
|
+
* an explicit 900 latch. Byte compaction always emits 901 or 924 so its start
|
|
83
|
+
* state is unambiguous, including when an ECI designator precedes it.
|
|
84
|
+
*/
|
|
85
|
+
export function compactMicroPDF417(value, options = {}) {
|
|
86
|
+
assertNotEmpty(value);
|
|
87
|
+
const mode = options.compaction ?? 'auto';
|
|
88
|
+
const eci = options.eci;
|
|
89
|
+
if (eci !== undefined && eci !== 3 && eci !== 26) {
|
|
90
|
+
throw new EncodeError('MicroPDF417: supported ECI assignment numbers are 3 and 26');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (mode === 'text') {
|
|
94
|
+
if (eci !== undefined) throw new EncodeError('MicroPDF417: explicit ECI is supported only with byte compaction');
|
|
95
|
+
return [900, ...compactPdf417Text(value)];
|
|
96
|
+
}
|
|
97
|
+
if (mode === 'numeric') {
|
|
98
|
+
if (eci !== undefined) throw new EncodeError('MicroPDF417: explicit ECI is supported only with byte compaction');
|
|
99
|
+
return compactPdf417Numeric(value);
|
|
100
|
+
}
|
|
101
|
+
if (mode === 'byte') return compactByte(value, eci);
|
|
102
|
+
if (mode !== 'auto') {
|
|
103
|
+
throw new EncodeError(`MicroPDF417: unsupported compaction mode ${JSON.stringify(mode)}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (eci !== undefined) return compactByte(value, eci);
|
|
107
|
+
if (typeof value === 'string' && /^\d{13,}$/.test(value)) return compactPdf417Numeric(value);
|
|
108
|
+
if (typeof value === 'string') {
|
|
109
|
+
try {
|
|
110
|
+
return [900, ...compactPdf417Text(value)];
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (!(error instanceof EncodeError)) throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return compactPdf417Bytes(value);
|
|
116
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
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
|
+
/**
|
|
32
|
+
* Direct-module MicroPDF417 decoder.
|
|
33
|
+
*
|
|
34
|
+
* This module reads an already sampled, axis-aligned `BitMatrix`. Image finding,
|
|
35
|
+
* perspective correction, and recognition from photographic pixels are deliberately
|
|
36
|
+
* outside this first decoder boundary. The RAP sequence is authoritative for format
|
|
37
|
+
* detection; matrix metadata is used only as an optional row-height hint.
|
|
38
|
+
*
|
|
39
|
+
* @module micropdf417/decoder
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
import { FormatError } from '../core/errors.js';
|
|
43
|
+
import { decodePdf417CompactionDetailed } from '../pdf417/compaction.js';
|
|
44
|
+
import { pdf417CodewordForPattern } from '../pdf417/tables.js';
|
|
45
|
+
import { microPdf417CorrectErrors } from './error-correction.js';
|
|
46
|
+
import {
|
|
47
|
+
MICROPDF417_VARIANTS,
|
|
48
|
+
microPdf417RapSequence,
|
|
49
|
+
microPdf417RowAddress,
|
|
50
|
+
microPdf417VariantByNumber,
|
|
51
|
+
} from './tables.js';
|
|
52
|
+
|
|
53
|
+
function symbolWidth(columns) {
|
|
54
|
+
return 21 + columns * 17 + (columns > 2 ? 10 : 0);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function bits(matrix, y, x, width) {
|
|
58
|
+
let value = 0;
|
|
59
|
+
for (let i = 0; i < width; i++) value = (value << 1) | (matrix.get(x + i, y) ? 1 : 0);
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function widthsToBits(widths) {
|
|
64
|
+
let dark = true;
|
|
65
|
+
let out = '';
|
|
66
|
+
for (const digit of widths) {
|
|
67
|
+
out += (dark ? '1' : '0').repeat(digit.charCodeAt(0) - 48);
|
|
68
|
+
dark = !dark;
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function hasExpectedBits(matrix, y, x, sequence) {
|
|
74
|
+
const expected = widthsToBits(sequence);
|
|
75
|
+
for (let i = 0; i < expected.length; i++) {
|
|
76
|
+
if ((matrix.get(x + i, y) ? '1' : '0') !== expected[i]) return false;
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function centralRapAfter(entry, column) {
|
|
82
|
+
return (entry.columns === 3 && column === 0) ||
|
|
83
|
+
(entry.columns === 4 && column === 1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Return true when all address patterns for this format candidate agree. */
|
|
87
|
+
function hasValidRowAddresses(matrix, entry, rowHeight) {
|
|
88
|
+
for (let row = 0; row < entry.rows; row++) {
|
|
89
|
+
const y = row * rowHeight;
|
|
90
|
+
const address = microPdf417RowAddress(entry, row);
|
|
91
|
+
let x = 0;
|
|
92
|
+
if (!hasExpectedBits(matrix, y, x, microPdf417RapSequence(address.left, 'side'))) return false;
|
|
93
|
+
x += 10;
|
|
94
|
+
for (let column = 0; column < entry.columns; column++) {
|
|
95
|
+
x += 17;
|
|
96
|
+
if (centralRapAfter(entry, column)) {
|
|
97
|
+
if (address.center === null ||
|
|
98
|
+
!hasExpectedBits(matrix, y, x, microPdf417RapSequence(address.center, 'center'))) return false;
|
|
99
|
+
x += 10;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (!hasExpectedBits(matrix, y, x, microPdf417RapSequence(address.right, 'side'))) return false;
|
|
103
|
+
x += 10;
|
|
104
|
+
if (!matrix.get(x, y) || x + 1 !== matrix.width) return false;
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function candidateFormats(matrix, options) {
|
|
110
|
+
const metadataHeight = matrix.micropdf417?.rowHeight;
|
|
111
|
+
const requestedHeight = options.rowHeight ?? metadataHeight;
|
|
112
|
+
if (requestedHeight !== undefined && (!Number.isInteger(requestedHeight) || requestedHeight < 1)) {
|
|
113
|
+
throw new FormatError('MicroPDF417: rowHeight must be a positive integer');
|
|
114
|
+
}
|
|
115
|
+
const requestedVariant = options.variant === undefined ? null : microPdf417VariantByNumber(options.variant);
|
|
116
|
+
const pool = requestedVariant ? [requestedVariant] : MICROPDF417_VARIANTS;
|
|
117
|
+
const candidates = [];
|
|
118
|
+
for (const entry of pool) {
|
|
119
|
+
if (matrix.width !== symbolWidth(entry.columns)) continue;
|
|
120
|
+
if (matrix.height % entry.rows) continue;
|
|
121
|
+
const rowHeight = matrix.height / entry.rows;
|
|
122
|
+
if (requestedHeight !== undefined && rowHeight !== requestedHeight) continue;
|
|
123
|
+
if (hasValidRowAddresses(matrix, entry, rowHeight)) candidates.push({ entry, rowHeight });
|
|
124
|
+
}
|
|
125
|
+
return candidates;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function resolveFormat(matrix, options) {
|
|
129
|
+
if (!matrix?.width || !matrix?.height || typeof matrix.get !== 'function') {
|
|
130
|
+
throw new FormatError('MicroPDF417: matrix with width, height and get() is required');
|
|
131
|
+
}
|
|
132
|
+
const candidates = candidateFormats(matrix, options);
|
|
133
|
+
if (!candidates.length) throw new FormatError('MicroPDF417: no variant matches matrix geometry and row-address patterns');
|
|
134
|
+
if (candidates.length > 1) throw new FormatError('MicroPDF417: row-address patterns do not identify a unique variant');
|
|
135
|
+
return candidates[0];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function readCodewords(matrix, entry, rowHeight) {
|
|
139
|
+
const codewords = [];
|
|
140
|
+
const erasures = [];
|
|
141
|
+
for (let row = 0; row < entry.rows; row++) {
|
|
142
|
+
const y = row * rowHeight;
|
|
143
|
+
const address = microPdf417RowAddress(entry, row);
|
|
144
|
+
let x = 10;
|
|
145
|
+
for (let column = 0; column < entry.columns; column++) {
|
|
146
|
+
const decoded = pdf417CodewordForPattern(bits(matrix, y, x, 17));
|
|
147
|
+
if (!decoded || decoded.cluster !== address.cluster) {
|
|
148
|
+
erasures.push(codewords.length);
|
|
149
|
+
codewords.push(0);
|
|
150
|
+
} else {
|
|
151
|
+
codewords.push(decoded.codeword);
|
|
152
|
+
}
|
|
153
|
+
x += 17;
|
|
154
|
+
if (centralRapAfter(entry, column)) x += 10;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return { codewords, erasures };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Decode a sampled MicroPDF417 matrix.
|
|
162
|
+
*
|
|
163
|
+
* The complete fixed data region is compacted after correction. Encoder padding
|
|
164
|
+
* is PDF417 Text latch 900, which contributes no characters at the end of the
|
|
165
|
+
* payload. This avoids relying on non-symbol metadata for payload length.
|
|
166
|
+
*/
|
|
167
|
+
export function decodeMicroPDF417(matrix, options = {}) {
|
|
168
|
+
const { entry, rowHeight } = resolveFormat(matrix, options);
|
|
169
|
+
const { codewords, erasures } = readCodewords(matrix, entry, rowHeight);
|
|
170
|
+
const corrections = microPdf417CorrectErrors(codewords, entry, erasures);
|
|
171
|
+
const data = codewords.slice(0, entry.dataCodewords);
|
|
172
|
+
const decoded = decodePdf417CompactionDetailed(data);
|
|
173
|
+
return {
|
|
174
|
+
...decoded,
|
|
175
|
+
codewords,
|
|
176
|
+
rows: entry.rows,
|
|
177
|
+
columns: entry.columns,
|
|
178
|
+
variant: entry.id,
|
|
179
|
+
eccCodewords: entry.eccCodewords,
|
|
180
|
+
rowHeight,
|
|
181
|
+
corrections,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
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
|
+
/**
|
|
32
|
+
* Axis-aligned MicroPDF417 raster detection.
|
|
33
|
+
*
|
|
34
|
+
* A MicroPDF417 symbol has a fixed module width for each column count and a
|
|
35
|
+
* dark leading and trailing module in every row. Consequently the bounding
|
|
36
|
+
* rectangle of dark pixels identifies the complete symbol even when a light
|
|
37
|
+
* quiet zone surrounds it. Its width determines the integer raster scale;
|
|
38
|
+
* the existing direct-module decoder then verifies every row-address pattern
|
|
39
|
+
* and selects the exact variant. This is intentionally narrower than the
|
|
40
|
+
* PDF417 photo detector: it handles clean binarized rasters only, not skew or
|
|
41
|
+
* projective camera images.
|
|
42
|
+
*
|
|
43
|
+
* @module micropdf417/detector
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import { BitMatrix } from '../core/bit-matrix.js';
|
|
47
|
+
import { decodeMicroPDF417 } from './decoder.js';
|
|
48
|
+
|
|
49
|
+
/** @typedef {{x:number, y:number}} Point */
|
|
50
|
+
|
|
51
|
+
// Each row has two 10-module side RAPs, a final separator, and 17 modules for
|
|
52
|
+
// each data column. Three and four columns also contain one central RAP.
|
|
53
|
+
function symbolWidth(columns) { return 21 + columns * 17 + (columns > 2 ? 10 : 0); }
|
|
54
|
+
const WIDTHS = [1, 2, 3, 4].map(symbolWidth);
|
|
55
|
+
|
|
56
|
+
function rotateClockwise(source) {
|
|
57
|
+
const rotated = new BitMatrix(source.height, source.width);
|
|
58
|
+
for (let y = 0; y < source.height; y++) for (let x = 0; x < source.width; x++) {
|
|
59
|
+
if (source.get(x, y)) rotated.set(source.height - 1 - y, x);
|
|
60
|
+
}
|
|
61
|
+
return rotated;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function integerScale(width, modules) {
|
|
65
|
+
if (width % modules) return 0;
|
|
66
|
+
const scale = width / modules;
|
|
67
|
+
return Number.isInteger(scale) && scale > 0 ? scale : 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Collapse exact integer scale blocks using a majority vote. */
|
|
71
|
+
function sampleRaster(image, bounds, modulesWide, scale) {
|
|
72
|
+
const modulesHigh = bounds.height / scale;
|
|
73
|
+
if (!Number.isInteger(modulesHigh) || modulesHigh < 1) return null;
|
|
74
|
+
const matrix = new BitMatrix(modulesWide, modulesHigh);
|
|
75
|
+
for (let y = 0; y < modulesHigh; y++) for (let x = 0; x < modulesWide; x++) {
|
|
76
|
+
let dark = 0;
|
|
77
|
+
for (let py = 0; py < scale; py++) for (let px = 0; px < scale; px++) {
|
|
78
|
+
if (image.get(bounds.x + x * scale + px, bounds.y + y * scale + py)) dark++;
|
|
79
|
+
}
|
|
80
|
+
if (dark * 2 >= scale * scale) matrix.set(x, y);
|
|
81
|
+
}
|
|
82
|
+
return matrix;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function rectangle(bounds) {
|
|
86
|
+
return [
|
|
87
|
+
{ x: bounds.x, y: bounds.y },
|
|
88
|
+
{ x: bounds.x + bounds.width, y: bounds.y },
|
|
89
|
+
{ x: bounds.x + bounds.width, y: bounds.y + bounds.height },
|
|
90
|
+
{ x: bounds.x, y: bounds.y + bounds.height },
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function detectAxisAligned(image, options) {
|
|
95
|
+
const bounds = image.getBounds();
|
|
96
|
+
if (!bounds) return null;
|
|
97
|
+
for (const width of WIDTHS) {
|
|
98
|
+
const scale = integerScale(bounds.width, width);
|
|
99
|
+
if (!scale || bounds.height % scale) continue;
|
|
100
|
+
const matrix = sampleRaster(image, bounds, width, scale);
|
|
101
|
+
if (!matrix) continue;
|
|
102
|
+
try {
|
|
103
|
+
const decoded = decodeMicroPDF417(matrix, options);
|
|
104
|
+
return { matrix, corners: rectangle(bounds), moduleSize: scale, ...decoded };
|
|
105
|
+
} catch { /* The RAP sequence is not a MicroPDF417 symbol of this width. */ }
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Detect and decode one clean, binarized MicroPDF417 raster.
|
|
112
|
+
*
|
|
113
|
+
* Integer upscaling and quiet zones are accepted. The image is retried at all
|
|
114
|
+
* quarter-turns, but arbitrary angles and perspective require caller-side
|
|
115
|
+
* rectification before this function is used. `rotation` reports the clockwise
|
|
116
|
+
* orientation of the supplied input relative to a normally oriented symbol;
|
|
117
|
+
* it is not the inverse correction applied internally while searching.
|
|
118
|
+
*
|
|
119
|
+
* @param {import('../core/bit-matrix.js').BitMatrix} binaryImage Set bit = dark.
|
|
120
|
+
* @param {object} [options] Passed to {@link decodeMicroPDF417}.
|
|
121
|
+
* @returns {(ReturnType<typeof decodeMicroPDF417> & {matrix: BitMatrix, corners: Point[], moduleSize: number, rotation: number}) | null}
|
|
122
|
+
*/
|
|
123
|
+
export function detectMicroPDF417(binaryImage, options = {}) {
|
|
124
|
+
if (!binaryImage?.width || !binaryImage?.height || typeof binaryImage.get !== 'function') return null;
|
|
125
|
+
let oriented = binaryImage;
|
|
126
|
+
let toOriginal = (point) => ({ x: point.x, y: point.y });
|
|
127
|
+
for (let turns = 0; turns < 4; turns++) {
|
|
128
|
+
const found = detectAxisAligned(oriented, options);
|
|
129
|
+
// Search rotates clockwise to normalize the input. Public rotation has the
|
|
130
|
+
// opposite meaning: it describes how the input itself was rotated.
|
|
131
|
+
if (found) return {
|
|
132
|
+
...found,
|
|
133
|
+
rotation: (360 - turns * 90) % 360,
|
|
134
|
+
corners: found.corners.map(toOriginal),
|
|
135
|
+
};
|
|
136
|
+
const previous = oriented;
|
|
137
|
+
const previousToOriginal = toOriginal;
|
|
138
|
+
oriented = rotateClockwise(previous);
|
|
139
|
+
// Boundary coordinates (rather than just pixel centres) are transformed
|
|
140
|
+
// here, so callers can draw the returned rectangle directly on the input.
|
|
141
|
+
toOriginal = (point) => previousToOriginal({ x: point.y, y: previous.height - point.x });
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Alias kept symmetric with the other 2D readers. */
|
|
147
|
+
export function detectAndDecodeMicroPDF417(binaryImage, options = {}) {
|
|
148
|
+
return detectMicroPDF417(binaryImage, options);
|
|
149
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
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
|
+
/** MicroPDF417 encoder. @module micropdf417/encoder */
|
|
32
|
+
|
|
33
|
+
import { BitMatrix } from '../core/bit-matrix.js';
|
|
34
|
+
import { EncodeError } from '../core/errors.js';
|
|
35
|
+
import { pdf417PatternForCodeword } from '../pdf417/tables.js';
|
|
36
|
+
import { compactMicroPDF417 } from './compaction.js';
|
|
37
|
+
import { microPdf417ErrorCorrection } from './error-correction.js';
|
|
38
|
+
import {
|
|
39
|
+
MICROPDF417_VARIANTS,
|
|
40
|
+
microPdf417RapSequence,
|
|
41
|
+
microPdf417RowAddress,
|
|
42
|
+
microPdf417VariantByNumber,
|
|
43
|
+
microPdf417VariantForCapacity,
|
|
44
|
+
} from './tables.js';
|
|
45
|
+
|
|
46
|
+
function appendWidths(matrix, y, x, sequence, height) {
|
|
47
|
+
let dark = true;
|
|
48
|
+
for (const digit of sequence) {
|
|
49
|
+
const width = digit.charCodeAt(0) - 48;
|
|
50
|
+
if (!Number.isInteger(width) || width < 1 || width > 6) {
|
|
51
|
+
throw new EncodeError('MicroPDF417: invalid module-width sequence');
|
|
52
|
+
}
|
|
53
|
+
if (dark) matrix.setRegion(x, y, width, height);
|
|
54
|
+
x += width;
|
|
55
|
+
dark = !dark;
|
|
56
|
+
}
|
|
57
|
+
return x;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function codewordSequence(codeword, cluster) {
|
|
61
|
+
return pdf417PatternForCodeword(codeword, cluster)
|
|
62
|
+
.toString(2)
|
|
63
|
+
.padStart(17, '0')
|
|
64
|
+
.replace(/0+|1+/g, (run) => String(run.length));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function symbolWidth(columns) {
|
|
68
|
+
return 21 + columns * 17 + (columns > 2 ? 10 : 0);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function validateOptions(options) {
|
|
72
|
+
const rowHeight = options.rowHeight ?? 2;
|
|
73
|
+
if (!Number.isInteger(rowHeight) || rowHeight < 2) {
|
|
74
|
+
throw new EncodeError('MicroPDF417: rowHeight must be an integer of at least 2');
|
|
75
|
+
}
|
|
76
|
+
if (options.columns !== undefined &&
|
|
77
|
+
(!Number.isInteger(options.columns) || options.columns < 1 || options.columns > 4)) {
|
|
78
|
+
throw new EncodeError('MicroPDF417: columns must be an integer in 1..4');
|
|
79
|
+
}
|
|
80
|
+
if (options.variant !== undefined &&
|
|
81
|
+
(!Number.isInteger(options.variant) || options.variant < 1 || options.variant > 34)) {
|
|
82
|
+
throw new EncodeError('MicroPDF417: variant must be an integer in 1..34');
|
|
83
|
+
}
|
|
84
|
+
if (options.aspectRatio !== undefined &&
|
|
85
|
+
(!Number.isFinite(options.aspectRatio) || options.aspectRatio <= 0)) {
|
|
86
|
+
throw new EncodeError('MicroPDF417: aspectRatio must be positive');
|
|
87
|
+
}
|
|
88
|
+
if (options.rows !== undefined) {
|
|
89
|
+
throw new EncodeError('MicroPDF417: rows are fixed by the selected variant');
|
|
90
|
+
}
|
|
91
|
+
if (options.eccLevel !== undefined) {
|
|
92
|
+
throw new EncodeError('MicroPDF417: error correction is fixed by the selected variant');
|
|
93
|
+
}
|
|
94
|
+
for (const feature of [
|
|
95
|
+
'structuredAppend', 'macro', 'macroPdf417', 'macroControlBlock',
|
|
96
|
+
'readerInit', 'gs1', 'hibc', 'linkage',
|
|
97
|
+
]) {
|
|
98
|
+
if (options[feature] !== undefined) {
|
|
99
|
+
throw new EncodeError(`MicroPDF417: ${feature} is not implemented`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return rowHeight;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function chooseVariant(codewordCount, rowHeight, options) {
|
|
106
|
+
if (options.variant !== undefined) {
|
|
107
|
+
const variant = microPdf417VariantByNumber(options.variant);
|
|
108
|
+
if (!variant) throw new EncodeError(`MicroPDF417: unknown variant ${options.variant}`);
|
|
109
|
+
if (options.columns !== undefined && variant.columns !== options.columns) {
|
|
110
|
+
throw new EncodeError(`MicroPDF417: variant ${variant.id} has ${variant.columns} columns`);
|
|
111
|
+
}
|
|
112
|
+
if (codewordCount > variant.dataCodewords) {
|
|
113
|
+
throw new EncodeError(
|
|
114
|
+
`MicroPDF417: payload requires ${codewordCount} data codewords, variant ${variant.id} holds ${variant.dataCodewords}`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return variant;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (options.columns === undefined && options.aspectRatio === undefined) {
|
|
121
|
+
try {
|
|
122
|
+
return microPdf417VariantForCapacity(codewordCount);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (!(error instanceof RangeError)) throw error;
|
|
125
|
+
throw new EncodeError(`MicroPDF417: payload requires ${codewordCount} data codewords and exceeds every variant`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const candidates = MICROPDF417_VARIANTS.filter((variant) =>
|
|
130
|
+
variant.dataCodewords >= codewordCount &&
|
|
131
|
+
(options.columns === undefined || variant.columns === options.columns)
|
|
132
|
+
);
|
|
133
|
+
if (!candidates.length) {
|
|
134
|
+
const columnText = options.columns === undefined ? '' : ` with ${options.columns} columns`;
|
|
135
|
+
throw new EncodeError(`MicroPDF417: payload does not fit any supported variant${columnText}`);
|
|
136
|
+
}
|
|
137
|
+
if (options.aspectRatio === undefined) {
|
|
138
|
+
return candidates.reduce((best, variant) =>
|
|
139
|
+
variant.dataCodewords < best.dataCodewords ||
|
|
140
|
+
(variant.dataCodewords === best.dataCodewords && variant.totalCodewords < best.totalCodewords)
|
|
141
|
+
? variant : best
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const target = options.aspectRatio;
|
|
146
|
+
return candidates.reduce((best, variant) => {
|
|
147
|
+
const ratio = symbolWidth(variant.columns) / (variant.rows * rowHeight);
|
|
148
|
+
const score = Math.abs(Math.log(ratio / target)) +
|
|
149
|
+
(variant.dataCodewords - codewordCount) / 10000;
|
|
150
|
+
return !best || score < best.score ? { variant, score } : best;
|
|
151
|
+
}, null).variant;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Encode a value as one of the 34 fixed MicroPDF417 variants. */
|
|
155
|
+
export function encodeMicroPDF417(value, options = {}) {
|
|
156
|
+
const rowHeight = validateOptions(options);
|
|
157
|
+
const payload = compactMicroPDF417(value, options);
|
|
158
|
+
const variant = chooseVariant(payload.length, rowHeight, options);
|
|
159
|
+
const data = payload.slice();
|
|
160
|
+
while (data.length < variant.dataCodewords) data.push(900);
|
|
161
|
+
const ecc = microPdf417ErrorCorrection(data, variant);
|
|
162
|
+
if (ecc.length !== variant.eccCodewords) {
|
|
163
|
+
throw new EncodeError('MicroPDF417: error-correction length does not match the selected variant');
|
|
164
|
+
}
|
|
165
|
+
const codewords = data.concat(ecc);
|
|
166
|
+
if (codewords.length !== variant.totalCodewords || codewords.length !== variant.rows * variant.columns) {
|
|
167
|
+
throw new EncodeError('MicroPDF417: selected variant has inconsistent codeword dimensions');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const matrix = new BitMatrix(symbolWidth(variant.columns), variant.rows * rowHeight);
|
|
171
|
+
for (let row = 0; row < variant.rows; row++) {
|
|
172
|
+
const y = row * rowHeight;
|
|
173
|
+
const address = microPdf417RowAddress(variant, row);
|
|
174
|
+
let x = appendWidths(matrix, y, 0, microPdf417RapSequence(address.left, 'side'), rowHeight);
|
|
175
|
+
for (let column = 0; column < variant.columns; column++) {
|
|
176
|
+
x = appendWidths(
|
|
177
|
+
matrix,
|
|
178
|
+
y,
|
|
179
|
+
x,
|
|
180
|
+
codewordSequence(codewords[row * variant.columns + column], address.cluster),
|
|
181
|
+
rowHeight
|
|
182
|
+
);
|
|
183
|
+
const hasCentralRap = (variant.columns === 3 && column === 0) ||
|
|
184
|
+
(variant.columns === 4 && column === 1);
|
|
185
|
+
if (hasCentralRap) {
|
|
186
|
+
if (address.center === null) {
|
|
187
|
+
throw new EncodeError('MicroPDF417: selected variant is missing its centre row address');
|
|
188
|
+
}
|
|
189
|
+
x = appendWidths(matrix, y, x, microPdf417RapSequence(address.center, 'center'), rowHeight);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
x = appendWidths(matrix, y, x, microPdf417RapSequence(address.right, 'side'), rowHeight);
|
|
193
|
+
matrix.setRegion(x, y, 1, rowHeight);
|
|
194
|
+
x++;
|
|
195
|
+
if (x !== matrix.width) throw new EncodeError('MicroPDF417: row width does not match the selected variant');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
matrix.micropdf417 = {
|
|
199
|
+
variant: variant.id,
|
|
200
|
+
rows: variant.rows,
|
|
201
|
+
columns: variant.columns,
|
|
202
|
+
eccCodewords: variant.eccCodewords,
|
|
203
|
+
rowHeight,
|
|
204
|
+
payloadCodewords: payload.length,
|
|
205
|
+
dataCodewords: data,
|
|
206
|
+
codewords,
|
|
207
|
+
};
|
|
208
|
+
return matrix;
|
|
209
|
+
}
|