@sythos/js_barcode_universal 1.5.8 → 1.5.10
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 +61 -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
|
@@ -27,59 +27,49 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/** Compact PDF417 (truncated PDF417) encoder. @module compactpdf417/encoder */
|
|
32
|
-
|
|
33
31
|
import { BitMatrix } from '../core/bit-matrix.js';
|
|
34
32
|
import { EncodeError } from '../core/errors.js';
|
|
35
33
|
import { compactPdf417 } from '../pdf417/compaction.js';
|
|
36
34
|
import { pdf417ErrorCorrection, pdf417EccLength } from '../pdf417/error-correction.js';
|
|
37
35
|
import { pdf417PatternForCodeword } from '../pdf417/tables.js';
|
|
38
|
-
import {
|
|
39
|
-
COMPACT_PDF417_START,
|
|
40
|
-
compactPdf417Indicators,
|
|
41
|
-
compactPdf417Width,
|
|
42
|
-
validateCompactPdf417Options,
|
|
43
|
-
} from './tables.js';
|
|
44
|
-
|
|
36
|
+
import { COMPACT_PDF417_START, compactPdf417Indicators, compactPdf417Width, validateCompactPdf417Options, } from './tables.js';
|
|
45
37
|
function appendWidths(matrix, y, x, sequence, height) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
let dark = true;
|
|
39
|
+
for (const digit of sequence) {
|
|
40
|
+
const width = digit.charCodeAt(0) - 48;
|
|
41
|
+
if (!Number.isInteger(width) || width < 1 || width > 8) {
|
|
42
|
+
throw new EncodeError('Compact PDF417: invalid module-width sequence');
|
|
43
|
+
}
|
|
44
|
+
if (dark)
|
|
45
|
+
matrix.setRegion(x, y, width, height);
|
|
46
|
+
x += width;
|
|
47
|
+
dark = !dark;
|
|
51
48
|
}
|
|
52
|
-
|
|
53
|
-
x += width;
|
|
54
|
-
dark = !dark;
|
|
55
|
-
}
|
|
56
|
-
return x;
|
|
49
|
+
return x;
|
|
57
50
|
}
|
|
58
|
-
|
|
59
51
|
function patternSequence(pattern) {
|
|
60
|
-
|
|
52
|
+
return pattern.toString(2).padStart(17, '0').replace(/0+|1+/g, (run) => String(run.length));
|
|
61
53
|
}
|
|
62
|
-
|
|
63
54
|
function dimensions(needed, level, options, rowHeight) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
55
|
+
const ecc = pdf417EccLength(level);
|
|
56
|
+
let best = null;
|
|
57
|
+
for (let rows = options.rows ?? 3; rows <= (options.rows ?? 90); rows++) {
|
|
58
|
+
for (let columns = options.columns ?? 1; columns <= (options.columns ?? 30); columns++) {
|
|
59
|
+
if (rows * columns > 928 || rows * columns - ecc < needed)
|
|
60
|
+
continue;
|
|
61
|
+
const ratio = compactPdf417Width(columns) / (rows * rowHeight);
|
|
62
|
+
const score = (rows * columns - ecc - needed) * 10 +
|
|
63
|
+
Math.abs(ratio - (options.aspectRatio ?? 3));
|
|
64
|
+
if (!best || score < best.score)
|
|
65
|
+
best = { rows, columns, score };
|
|
66
|
+
}
|
|
73
67
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
return best;
|
|
68
|
+
if (!best) {
|
|
69
|
+
throw new EncodeError('Compact PDF417: payload does not fit the requested dimensions and error correction level');
|
|
70
|
+
}
|
|
71
|
+
return best;
|
|
81
72
|
}
|
|
82
|
-
|
|
83
73
|
/**
|
|
84
74
|
* Encode Compact PDF417.
|
|
85
75
|
*
|
|
@@ -93,48 +83,45 @@ function dimensions(needed, level, options, rowHeight) {
|
|
|
93
83
|
* @returns {import('../core/bit-matrix.js').BitMatrix}
|
|
94
84
|
*/
|
|
95
85
|
export function encodeCompactPDF417(value, options = {}) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
86
|
+
const rowHeight = validateCompactPdf417Options(options);
|
|
87
|
+
const level = options.eccLevel ?? 2;
|
|
88
|
+
if (!Number.isInteger(level) || level < 0 || level > 8) {
|
|
89
|
+
throw new EncodeError('Compact PDF417: eccLevel must be an integer in 0..8');
|
|
90
|
+
}
|
|
91
|
+
const payload = compactPdf417(value, { compaction: options.compaction, charset: options.charset });
|
|
92
|
+
const { rows, columns } = dimensions(payload.length + 1, level, options, rowHeight);
|
|
93
|
+
const eccLength = pdf417EccLength(level);
|
|
94
|
+
const dataLength = rows * columns - eccLength;
|
|
95
|
+
const data = [dataLength, ...payload];
|
|
96
|
+
while (data.length < dataLength)
|
|
97
|
+
data.push(900);
|
|
98
|
+
const codewords = data.concat(pdf417ErrorCorrection(data, level));
|
|
99
|
+
const matrix = new BitMatrix(compactPdf417Width(columns), rows * rowHeight);
|
|
100
|
+
for (let row = 0; row < rows; row++) {
|
|
101
|
+
const y = row * rowHeight;
|
|
102
|
+
const cluster = (row % 3) * 3;
|
|
103
|
+
let x = appendWidths(matrix, y, 0, COMPACT_PDF417_START, rowHeight);
|
|
104
|
+
const left = compactPdf417Indicators(row, rows, columns, level);
|
|
105
|
+
x = appendWidths(matrix, y, x, patternSequence(pdf417PatternForCodeword(left, cluster)), rowHeight);
|
|
106
|
+
for (let column = 0; column < columns; column++) {
|
|
107
|
+
const codeword = codewords[row * columns + column];
|
|
108
|
+
x = appendWidths(matrix, y, x, patternSequence(pdf417PatternForCodeword(codeword, cluster)), rowHeight);
|
|
109
|
+
}
|
|
110
|
+
// Compact PDF417 terminates every row with one dark module, not the normal
|
|
111
|
+
// right indicator plus 18-module stop pattern.
|
|
112
|
+
matrix.setRegion(x, y, 1, rowHeight);
|
|
113
|
+
x++;
|
|
114
|
+
if (x !== matrix.width)
|
|
115
|
+
throw new EncodeError('Compact PDF417: internal row width mismatch');
|
|
121
116
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
columns,
|
|
132
|
-
eccLevel: level,
|
|
133
|
-
rowHeight,
|
|
134
|
-
codewords,
|
|
135
|
-
layout: 'compact',
|
|
136
|
-
};
|
|
137
|
-
return matrix;
|
|
117
|
+
matrix.compactPdf417 = {
|
|
118
|
+
rows,
|
|
119
|
+
columns,
|
|
120
|
+
eccLevel: level,
|
|
121
|
+
rowHeight,
|
|
122
|
+
codewords,
|
|
123
|
+
layout: 'compact',
|
|
124
|
+
};
|
|
125
|
+
return matrix;
|
|
138
126
|
}
|
|
139
|
-
|
|
140
127
|
export { dimensions as compactPdf417Dimensions };
|
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
/* Compact PDF417 public module exports. */
|
|
2
|
-
|
|
3
|
-
export {
|
|
4
|
-
COMPACT_PDF417_START,
|
|
5
|
-
COMPACT_PDF417_START_BITS,
|
|
6
|
-
COMPACT_PDF417_STOP_MODULES,
|
|
7
|
-
COMPACT_PDF417_LIMITS,
|
|
8
|
-
compactPdf417Width,
|
|
9
|
-
compactPdf417Geometry,
|
|
10
|
-
compactPdf417Indicators,
|
|
11
|
-
compactPdf417MatchingLevels,
|
|
12
|
-
validateCompactPdf417Options,
|
|
13
|
-
validateCompactPdf417Tables,
|
|
14
|
-
} from './tables.js';
|
|
2
|
+
export { COMPACT_PDF417_START, COMPACT_PDF417_START_BITS, COMPACT_PDF417_STOP_MODULES, COMPACT_PDF417_LIMITS, compactPdf417Width, compactPdf417Geometry, compactPdf417Indicators, compactPdf417MatchingLevels, validateCompactPdf417Options, validateCompactPdf417Tables, } from './tables.js';
|
|
15
3
|
export { encodeCompactPDF417, compactPdf417Dimensions } from './encoder.js';
|
|
16
4
|
export { decodeCompactPDF417 } from './decoder.js';
|
|
17
5
|
export { detectCompactPDF417, detectAndDecodeCompactPDF417 } from './detector.js';
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/**
|
|
32
31
|
* Compact (truncated) PDF417 layout.
|
|
33
32
|
*
|
|
@@ -40,27 +39,21 @@
|
|
|
40
39
|
*
|
|
41
40
|
* @module compactpdf417/tables
|
|
42
41
|
*/
|
|
43
|
-
|
|
44
42
|
import { EncodeError } from '../core/errors.js';
|
|
45
|
-
|
|
46
43
|
/** PDF417 start pattern, in module widths. */
|
|
47
44
|
export const COMPACT_PDF417_START = '81111113';
|
|
48
|
-
|
|
49
45
|
/** Binary module representation of the start pattern. */
|
|
50
46
|
export const COMPACT_PDF417_START_BITS = '11111111010101000';
|
|
51
|
-
|
|
52
47
|
/** Compact PDF417's reduced stop is one dark module. */
|
|
53
48
|
export const COMPACT_PDF417_STOP_MODULES = 1;
|
|
54
|
-
|
|
55
49
|
/** Minimum/maximum number of rows and data columns. */
|
|
56
50
|
export const COMPACT_PDF417_LIMITS = Object.freeze({
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
minRows: 3,
|
|
52
|
+
maxRows: 90,
|
|
53
|
+
minColumns: 1,
|
|
54
|
+
maxColumns: 30,
|
|
55
|
+
maxCodewords: 928,
|
|
62
56
|
});
|
|
63
|
-
|
|
64
57
|
/**
|
|
65
58
|
* Return the printed width in modules for a compact symbol.
|
|
66
59
|
*
|
|
@@ -68,12 +61,11 @@ export const COMPACT_PDF417_LIMITS = Object.freeze({
|
|
|
68
61
|
* @param {number} columns
|
|
69
62
|
*/
|
|
70
63
|
export function compactPdf417Width(columns) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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;
|
|
75
68
|
}
|
|
76
|
-
|
|
77
69
|
/**
|
|
78
70
|
* Validate a compact matrix geometry and return its dimensions.
|
|
79
71
|
*
|
|
@@ -82,92 +74,91 @@ export function compactPdf417Width(columns) {
|
|
|
82
74
|
* @param {number} rowHeight
|
|
83
75
|
*/
|
|
84
76
|
export function compactPdf417Geometry(width, height, rowHeight = 3) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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 };
|
|
103
95
|
}
|
|
104
|
-
|
|
105
96
|
/**
|
|
106
97
|
* Validate encoder dimensions before codeword packing.
|
|
107
98
|
* @param {object} options
|
|
108
99
|
*/
|
|
109
100
|
export function validateCompactPdf417Options(options = {}) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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');
|
|
121
117
|
}
|
|
122
|
-
|
|
123
|
-
if (options.aspectRatio !== undefined &&
|
|
124
|
-
(!Number.isFinite(options.aspectRatio) || options.aspectRatio <= 0)) {
|
|
125
|
-
throw new EncodeError('Compact PDF417: aspectRatio must be positive');
|
|
126
|
-
}
|
|
127
|
-
return rowHeight;
|
|
118
|
+
return rowHeight;
|
|
128
119
|
}
|
|
129
|
-
|
|
130
120
|
/**
|
|
131
121
|
* The row indicator values used by ordinary PDF417 are retained unchanged.
|
|
132
122
|
* Compact symbols omit only the right indicator, so the left indicator still
|
|
133
123
|
* carries the row group, row count, error-correction level and column count.
|
|
134
124
|
*/
|
|
135
125
|
export function compactPdf417Indicators(row, rows, columns, level) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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;
|
|
143
135
|
}
|
|
144
|
-
|
|
145
136
|
/**
|
|
146
137
|
* Return all standard ECC levels which agree with the observed left
|
|
147
138
|
* indicators. This is kept as a table helper so decoder and tests share the
|
|
148
139
|
* same compact-layout rule.
|
|
149
140
|
*/
|
|
150
141
|
export function compactPdf417MatchingLevels(leftIndicators, rows, columns) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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;
|
|
157
148
|
}
|
|
158
|
-
|
|
159
149
|
/** Validate representative layout invariants. */
|
|
160
150
|
export function validateCompactPdf417Tables() {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
+
}
|
|
170
162
|
}
|
|
171
|
-
|
|
172
|
-
return problems;
|
|
163
|
+
return problems;
|
|
173
164
|
}
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/**
|
|
32
31
|
* Bit-level writing and reading, MSB-first.
|
|
33
32
|
*
|
|
@@ -38,137 +37,122 @@
|
|
|
38
37
|
*
|
|
39
38
|
* @module core/bit-buffer
|
|
40
39
|
*/
|
|
41
|
-
|
|
42
40
|
import { FormatError } from './errors.js';
|
|
43
|
-
|
|
44
41
|
/** Growable MSB-first bit writer. */
|
|
45
42
|
export class BitWriter {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** @returns {number} Bits written so far. */
|
|
53
|
-
get length() {
|
|
54
|
-
return this.bitLength;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Append the low `count` bits of `value`, most significant first.
|
|
59
|
-
*
|
|
60
|
-
* @param {number} value
|
|
61
|
-
* @param {number} count
|
|
62
|
-
*/
|
|
63
|
-
put(value, count) {
|
|
64
|
-
for (let i = count - 1; i >= 0; i--) {
|
|
65
|
-
this.putBit(((value >>> i) & 1) === 1);
|
|
43
|
+
constructor() {
|
|
44
|
+
/** @type {number[]} Packed bytes; the last one may be partially filled. */
|
|
45
|
+
this.bytes = [];
|
|
46
|
+
this.bitLength = 0;
|
|
66
47
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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;
|
|
100
97
|
}
|
|
101
|
-
return s;
|
|
102
|
-
}
|
|
103
98
|
}
|
|
104
|
-
|
|
105
99
|
/** MSB-first bit reader over a byte array. */
|
|
106
100
|
export class BitReader {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
this.bitOffset = 0;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** @returns {number} Bits not yet consumed. */
|
|
115
|
-
available() {
|
|
116
|
-
return 8 * (this.bytes.length - this.byteOffset) - this.bitOffset;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Read `count` bits (1..32) as an unsigned integer, most significant first.
|
|
121
|
-
*
|
|
122
|
-
* @param {number} count
|
|
123
|
-
* @returns {number}
|
|
124
|
-
* @throws {FormatError} If the stream is exhausted.
|
|
125
|
-
*/
|
|
126
|
-
read(count) {
|
|
127
|
-
if (count < 1 || count > 32) {
|
|
128
|
-
throw new FormatError(`BitReader: cannot read ${count} bits`);
|
|
129
|
-
}
|
|
130
|
-
if (count > this.available()) {
|
|
131
|
-
throw new FormatError(
|
|
132
|
-
`BitReader: needed ${count} bits, ${this.available()} remain`
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
let result = 0;
|
|
137
|
-
let remaining = count;
|
|
138
|
-
|
|
139
|
-
// Finish the partially consumed byte first, then take whole bytes.
|
|
140
|
-
if (this.bitOffset > 0) {
|
|
141
|
-
const inCurrent = 8 - this.bitOffset;
|
|
142
|
-
const take = Math.min(remaining, inCurrent);
|
|
143
|
-
const shift = inCurrent - take;
|
|
144
|
-
const mask = (0xff >> this.bitOffset) & ~((1 << shift) - 1);
|
|
145
|
-
result = (this.bytes[this.byteOffset] & mask) >> shift;
|
|
146
|
-
remaining -= take;
|
|
147
|
-
this.bitOffset += take;
|
|
148
|
-
if (this.bitOffset === 8) {
|
|
101
|
+
/** @param {ArrayLike<number>} bytes */
|
|
102
|
+
constructor(bytes) {
|
|
103
|
+
this.bytes = bytes;
|
|
104
|
+
this.byteOffset = 0;
|
|
149
105
|
this.bitOffset = 0;
|
|
150
|
-
this.byteOffset++;
|
|
151
|
-
}
|
|
152
106
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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;
|
|
158
153
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const mask = ~((1 << shift) - 1) & 0xff;
|
|
163
|
-
result = (result << remaining) | ((this.bytes[this.byteOffset] & mask) >> shift);
|
|
164
|
-
this.bitOffset += remaining;
|
|
154
|
+
/** @returns {boolean} */
|
|
155
|
+
readBit() {
|
|
156
|
+
return this.read(1) === 1;
|
|
165
157
|
}
|
|
166
|
-
|
|
167
|
-
return result >>> 0;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/** @returns {boolean} */
|
|
171
|
-
readBit() {
|
|
172
|
-
return this.read(1) === 1;
|
|
173
|
-
}
|
|
174
158
|
}
|