@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
package/src/js/databar/codec.js
CHANGED
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/**
|
|
32
31
|
* GTIN validation and numeric compaction for GS1 DataBar GTIN-only symbols.
|
|
33
32
|
*
|
|
@@ -37,145 +36,131 @@
|
|
|
37
36
|
*
|
|
38
37
|
* @module databar/codec
|
|
39
38
|
*/
|
|
40
|
-
|
|
41
|
-
import {
|
|
42
|
-
DATABAR14_INSIDE_RADIX,
|
|
43
|
-
DATABAR14_PAIR_RADIX,
|
|
44
|
-
DATABAR14_SYMBOL_LIMIT,
|
|
45
|
-
DATABAR_LIMITED_DATA_LIMIT,
|
|
46
|
-
DATABAR_LIMITED_LINKAGE_OFFSET,
|
|
47
|
-
DATABAR_LIMITED_PAIR_RADIX,
|
|
48
|
-
} from './tables.js';
|
|
49
|
-
|
|
39
|
+
import { DATABAR14_INSIDE_RADIX, DATABAR14_PAIR_RADIX, DATABAR14_SYMBOL_LIMIT, DATABAR_LIMITED_DATA_LIMIT, DATABAR_LIMITED_LINKAGE_OFFSET, DATABAR_LIMITED_PAIR_RADIX, } from './tables.js';
|
|
50
40
|
const GTIN_LENGTHS = new Set([8, 12, 13, 14]);
|
|
51
|
-
|
|
52
41
|
function digits(value, label) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
const text = String(value);
|
|
43
|
+
if (!/^\d+$/.test(text))
|
|
44
|
+
throw new TypeError(`${label} must contain only decimal digits`);
|
|
45
|
+
return text;
|
|
56
46
|
}
|
|
57
|
-
|
|
58
47
|
function asCharacterValue(value, label, maximum) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
48
|
+
if (!Number.isInteger(value) || value < 0 || value > maximum) {
|
|
49
|
+
throw new RangeError(`${label} must be an integer from 0 to ${maximum}`);
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
63
52
|
}
|
|
64
|
-
|
|
65
53
|
/** Calculate the GS1 modulo-10 check digit for a GTIN body. */
|
|
66
54
|
export function gtinCheckDigit(body) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
55
|
+
const text = digits(body, 'GTIN body');
|
|
56
|
+
if (text.length < 1 || text.length > 13)
|
|
57
|
+
throw new RangeError('GTIN body must contain 1 to 13 digits');
|
|
58
|
+
let sum = 0;
|
|
59
|
+
for (let i = text.length - 1, weight = 3; i >= 0; i--, weight = weight === 3 ? 1 : 3) {
|
|
60
|
+
sum += Number(text[i]) * weight;
|
|
61
|
+
}
|
|
62
|
+
return String((10 - (sum % 10)) % 10);
|
|
74
63
|
}
|
|
75
|
-
|
|
76
64
|
/** Return a checked 14-digit GTIN, preserving only its standardized digits. */
|
|
77
65
|
export function normalizeGTIN(value) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
66
|
+
const input = digits(value, 'GTIN');
|
|
67
|
+
if (!GTIN_LENGTHS.has(input.length)) {
|
|
68
|
+
throw new RangeError('GTIN must contain 8, 12, 13, or 14 digits including its check digit');
|
|
69
|
+
}
|
|
70
|
+
if (gtinCheckDigit(input.slice(0, -1)) !== input.at(-1)) {
|
|
71
|
+
throw new RangeError(`GTIN check digit is invalid for ${input}`);
|
|
72
|
+
}
|
|
73
|
+
return input.padStart(14, '0');
|
|
86
74
|
}
|
|
87
|
-
|
|
88
75
|
/** Build a checked GTIN-14 from its thirteen-digit data body. */
|
|
89
76
|
export function makeGTIN14(body) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
77
|
+
const input = digits(body, 'GTIN-14 body');
|
|
78
|
+
if (input.length > 13)
|
|
79
|
+
throw new RangeError('GTIN-14 body must contain at most 13 digits');
|
|
80
|
+
const padded = input.padStart(13, '0');
|
|
81
|
+
return padded + gtinCheckDigit(padded);
|
|
94
82
|
}
|
|
95
|
-
|
|
96
83
|
function gtinFromSymbolValue(symbolValue) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
84
|
+
const value = BigInt(symbolValue);
|
|
85
|
+
if (value < 0n || value >= DATABAR14_SYMBOL_LIMIT)
|
|
86
|
+
throw new RangeError('GS1 DataBar-14 symbol value is out of range');
|
|
87
|
+
const linkage = value >= 10000000000000n;
|
|
88
|
+
const body = (linkage ? value - 10000000000000n : value).toString().padStart(13, '0');
|
|
89
|
+
return { linkage, gtin: body + gtinCheckDigit(body) };
|
|
102
90
|
}
|
|
103
|
-
|
|
104
91
|
/**
|
|
105
92
|
* Compact a GTIN into the four values shared by Omnidirectional, Truncated,
|
|
106
93
|
* Stacked and Stacked Omnidirectional. The `physicalCharacters` sequence is
|
|
107
94
|
* left-to-right on a linear DataBar-14 row: 1, 2, 4, 3.
|
|
108
95
|
*/
|
|
109
96
|
export function encodeDataBar14GTIN(value, options = {}) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
});
|
|
97
|
+
const gtin = normalizeGTIN(value);
|
|
98
|
+
const linkage = options.linkage === true;
|
|
99
|
+
if (options.linkage !== undefined && typeof options.linkage !== 'boolean') {
|
|
100
|
+
throw new TypeError('GS1 DataBar linkage must be a boolean');
|
|
101
|
+
}
|
|
102
|
+
const dataBody = gtin.slice(0, -1);
|
|
103
|
+
const symbolValue = BigInt(dataBody) + (linkage ? 10000000000000n : 0n);
|
|
104
|
+
const leftPair = symbolValue / BigInt(DATABAR14_PAIR_RADIX);
|
|
105
|
+
const rightPair = symbolValue % BigInt(DATABAR14_PAIR_RADIX);
|
|
106
|
+
const outerLeft = Number(leftPair / BigInt(DATABAR14_INSIDE_RADIX));
|
|
107
|
+
const innerLeft = Number(leftPair % BigInt(DATABAR14_INSIDE_RADIX));
|
|
108
|
+
const outerRight = Number(rightPair / BigInt(DATABAR14_INSIDE_RADIX));
|
|
109
|
+
const innerRight = Number(rightPair % BigInt(DATABAR14_INSIDE_RADIX));
|
|
110
|
+
return Object.freeze({
|
|
111
|
+
gtin, linkage, symbolValue, leftPair, rightPair,
|
|
112
|
+
logicalCharacters: Object.freeze({ outerLeft, innerLeft, outerRight, innerRight }),
|
|
113
|
+
physicalCharacters: Object.freeze([outerLeft, innerLeft, innerRight, outerRight]),
|
|
114
|
+
});
|
|
129
115
|
}
|
|
130
|
-
|
|
131
116
|
/** Reconstruct and validate a GTIN from the four DataBar-14 character values. */
|
|
132
117
|
export function decodeDataBar14GTIN(values) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
118
|
+
if (values === null || typeof values !== 'object')
|
|
119
|
+
throw new TypeError('GS1 DataBar-14 characters must be an object');
|
|
120
|
+
const outerLeft = asCharacterValue(values.outerLeft, 'outerLeft', 2840);
|
|
121
|
+
const innerLeft = asCharacterValue(values.innerLeft, 'innerLeft', 1596);
|
|
122
|
+
const outerRight = asCharacterValue(values.outerRight, 'outerRight', 2840);
|
|
123
|
+
const innerRight = asCharacterValue(values.innerRight, 'innerRight', 1596);
|
|
124
|
+
const leftPair = BigInt(outerLeft) * BigInt(DATABAR14_INSIDE_RADIX) + BigInt(innerLeft);
|
|
125
|
+
const rightPair = BigInt(outerRight) * BigInt(DATABAR14_INSIDE_RADIX) + BigInt(innerRight);
|
|
126
|
+
return Object.freeze({
|
|
127
|
+
...gtinFromSymbolValue(leftPair * BigInt(DATABAR14_PAIR_RADIX) + rightPair),
|
|
128
|
+
leftPair, rightPair,
|
|
129
|
+
});
|
|
144
130
|
}
|
|
145
|
-
|
|
146
131
|
/** Compact a DataBar Limited-eligible GTIN into its two data character values. */
|
|
147
132
|
export function encodeDataBarLimitedGTIN(value, options = {}) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
133
|
+
const gtin = normalizeGTIN(value);
|
|
134
|
+
const linkage = options.linkage === true;
|
|
135
|
+
if (options.linkage !== undefined && typeof options.linkage !== 'boolean') {
|
|
136
|
+
throw new TypeError('GS1 DataBar linkage must be a boolean');
|
|
137
|
+
}
|
|
138
|
+
const dataBody = BigInt(gtin.slice(0, -1));
|
|
139
|
+
if (dataBody >= DATABAR_LIMITED_DATA_LIMIT) {
|
|
140
|
+
throw new RangeError('GS1 DataBar Limited requires a GTIN whose indicator digit is 0 or 1');
|
|
141
|
+
}
|
|
142
|
+
const symbolValue = dataBody + (linkage ? DATABAR_LIMITED_LINKAGE_OFFSET : 0n);
|
|
143
|
+
const left = Number(symbolValue / BigInt(DATABAR_LIMITED_PAIR_RADIX));
|
|
144
|
+
const right = Number(symbolValue % BigInt(DATABAR_LIMITED_PAIR_RADIX));
|
|
145
|
+
return Object.freeze({ gtin, linkage, symbolValue, left, right });
|
|
161
146
|
}
|
|
162
|
-
|
|
163
147
|
/** Reconstruct and validate a GTIN from DataBar Limited data character values. */
|
|
164
148
|
export function decodeDataBarLimitedGTIN(values) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
149
|
+
if (values === null || typeof values !== 'object')
|
|
150
|
+
throw new TypeError('GS1 DataBar Limited characters must be an object');
|
|
151
|
+
const left = asCharacterValue(values.left, 'left', 1994036);
|
|
152
|
+
const right = asCharacterValue(values.right, 'right', DATABAR_LIMITED_PAIR_RADIX - 1);
|
|
153
|
+
let symbolValue = BigInt(left) * BigInt(DATABAR_LIMITED_PAIR_RADIX) + BigInt(right);
|
|
154
|
+
const linkage = symbolValue >= DATABAR_LIMITED_LINKAGE_OFFSET;
|
|
155
|
+
if (linkage)
|
|
156
|
+
symbolValue -= DATABAR_LIMITED_LINKAGE_OFFSET;
|
|
157
|
+
if (symbolValue < 0n || symbolValue >= DATABAR_LIMITED_DATA_LIMIT) {
|
|
158
|
+
throw new RangeError('GS1 DataBar Limited character values do not encode a permitted GTIN');
|
|
159
|
+
}
|
|
160
|
+
const body = symbolValue.toString().padStart(13, '0');
|
|
161
|
+
return Object.freeze({ linkage, gtin: body + gtinCheckDigit(body), symbolValue: BigInt(left) * BigInt(DATABAR_LIMITED_PAIR_RADIX) + BigInt(right) });
|
|
176
162
|
}
|
|
177
|
-
|
|
178
163
|
/** GS1 transmitted form for the GTIN-only DataBar variants. */
|
|
179
164
|
export function dataBarGtinTransmission(value) {
|
|
180
|
-
|
|
165
|
+
return `]e001${normalizeGTIN(value)}`;
|
|
181
166
|
}
|
|
@@ -27,114 +27,110 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/** Clean-matrix decoder for GS1 DataBar Omnidirectional and Truncated. @module databar/decoder */
|
|
32
|
-
|
|
33
31
|
import { ChecksumError, FormatError } from '../core/errors.js';
|
|
34
32
|
import { BitMatrix } from '../core/bit-matrix.js';
|
|
35
33
|
import { decodeDataBar14GTIN } from './codec.js';
|
|
36
|
-
import {
|
|
37
|
-
DATABAR14_CHECKSUM_WEIGHTS,
|
|
38
|
-
DATABAR14_FINDERS,
|
|
39
|
-
dataBar14ValueForWidths,
|
|
40
|
-
} from './patterns.js';
|
|
41
|
-
|
|
34
|
+
import { DATABAR14_CHECKSUM_WEIGHTS, DATABAR14_FINDERS, dataBar14ValueForWidths, } from './patterns.js';
|
|
42
35
|
function sampledRuns(matrix) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
if (matrix.width % 96 !== 0) throw new FormatError('GS1 DataBar-14 matrix width must be an integer multiple of 96 modules');
|
|
47
|
-
const scale = matrix.width / 96;
|
|
48
|
-
const y = Math.floor(matrix.height / 2);
|
|
49
|
-
const bits = Array.from({ length: 96 }, (_, x) => matrix.get(x * scale + Math.floor(scale / 2), y));
|
|
50
|
-
if (bits[0] || !bits[95]) throw new FormatError('GS1 DataBar-14 guard pattern is invalid');
|
|
51
|
-
const runs = [];
|
|
52
|
-
let current = bits[0];
|
|
53
|
-
let length = 0;
|
|
54
|
-
for (const bit of bits) {
|
|
55
|
-
if (bit === current) length++;
|
|
56
|
-
else {
|
|
57
|
-
runs.push(length);
|
|
58
|
-
current = bit;
|
|
59
|
-
length = 1;
|
|
36
|
+
if (!matrix || !Number.isInteger(matrix.width) || !Number.isInteger(matrix.height)) {
|
|
37
|
+
throw new TypeError('GS1 DataBar decoder expects a BitMatrix-like value');
|
|
60
38
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
39
|
+
if (matrix.width % 96 !== 0)
|
|
40
|
+
throw new FormatError('GS1 DataBar-14 matrix width must be an integer multiple of 96 modules');
|
|
41
|
+
const scale = matrix.width / 96;
|
|
42
|
+
const y = Math.floor(matrix.height / 2);
|
|
43
|
+
const bits = Array.from({ length: 96 }, (_, x) => matrix.get(x * scale + Math.floor(scale / 2), y));
|
|
44
|
+
if (bits[0] || !bits[95])
|
|
45
|
+
throw new FormatError('GS1 DataBar-14 guard pattern is invalid');
|
|
46
|
+
const runs = [];
|
|
47
|
+
let current = bits[0];
|
|
48
|
+
let length = 0;
|
|
49
|
+
for (const bit of bits) {
|
|
50
|
+
if (bit === current)
|
|
51
|
+
length++;
|
|
52
|
+
else {
|
|
53
|
+
runs.push(length);
|
|
54
|
+
current = bit;
|
|
55
|
+
length = 1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
runs.push(length);
|
|
59
|
+
if (runs.length !== 46 || runs[0] !== 1 || runs[1] !== 1 || runs[44] !== 1 || runs[45] !== 1) {
|
|
60
|
+
throw new FormatError('GS1 DataBar-14 element count or guard widths are invalid');
|
|
61
|
+
}
|
|
62
|
+
return runs;
|
|
67
63
|
}
|
|
68
|
-
|
|
69
64
|
function finderIndex(widths) {
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
const key = widths.join(',');
|
|
66
|
+
return DATABAR14_FINDERS.findIndex((candidate) => candidate.join(',') === key);
|
|
72
67
|
}
|
|
73
|
-
|
|
74
68
|
function expectedChecksum(widths) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
const offsets = [0, 8, 24, 16];
|
|
70
|
+
let checksum = 0;
|
|
71
|
+
for (let character = 0; character < 4; character++) {
|
|
72
|
+
for (let element = 0; element < 8; element++) {
|
|
73
|
+
checksum += widths[character][element] * DATABAR14_CHECKSUM_WEIGHTS[offsets[character] + element];
|
|
74
|
+
}
|
|
80
75
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
checksum %= 79;
|
|
77
|
+
if (checksum >= 8)
|
|
78
|
+
checksum++;
|
|
79
|
+
if (checksum >= 72)
|
|
80
|
+
checksum++;
|
|
81
|
+
return checksum;
|
|
86
82
|
}
|
|
87
|
-
|
|
88
83
|
/** Decode a clean or integer-scaled 96-module DataBar-14 matrix. */
|
|
89
84
|
export function decodeDataBar14(matrix) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
85
|
+
const runs = sampledRuns(matrix);
|
|
86
|
+
const widths = [
|
|
87
|
+
runs.slice(2, 10),
|
|
88
|
+
runs.slice(15, 23).slice().reverse(),
|
|
89
|
+
runs.slice(23, 31),
|
|
90
|
+
runs.slice(36, 44).slice().reverse(),
|
|
91
|
+
];
|
|
92
|
+
const leftFinder = finderIndex(runs.slice(10, 15));
|
|
93
|
+
const rightFinder = finderIndex(runs.slice(31, 36).slice().reverse());
|
|
94
|
+
if (leftFinder < 0 || rightFinder < 0)
|
|
95
|
+
throw new FormatError('GS1 DataBar-14 finder pattern is invalid');
|
|
96
|
+
const encodedChecksum = leftFinder * 9 + rightFinder;
|
|
97
|
+
if (encodedChecksum !== expectedChecksum(widths))
|
|
98
|
+
throw new ChecksumError('GS1 DataBar-14 checksum mismatch');
|
|
99
|
+
const outerLeft = dataBar14ValueForWidths(widths[0], 'outside');
|
|
100
|
+
const innerLeft = dataBar14ValueForWidths(widths[1], 'inside');
|
|
101
|
+
const innerRight = dataBar14ValueForWidths(widths[2], 'inside');
|
|
102
|
+
const outerRight = dataBar14ValueForWidths(widths[3], 'outside');
|
|
103
|
+
const decoded = decodeDataBar14GTIN({ outerLeft, innerLeft, outerRight, innerRight });
|
|
104
|
+
return Object.freeze({
|
|
105
|
+
format: 'databar-omnidirectional',
|
|
106
|
+
text: decoded.gtin,
|
|
107
|
+
gtin: decoded.gtin,
|
|
108
|
+
linkage: decoded.linkage,
|
|
109
|
+
symbologyIdentifier: ']e0',
|
|
110
|
+
});
|
|
115
111
|
}
|
|
116
|
-
|
|
117
112
|
/**
|
|
118
113
|
* Extract alternating runs from a binarized scanline.
|
|
119
114
|
* @param {Uint8Array} row
|
|
120
115
|
* @returns {{widths:number[], dark:boolean}[]}
|
|
121
116
|
*/
|
|
122
117
|
function scanlineRuns(row) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
118
|
+
if (!row || row.length < 96)
|
|
119
|
+
return [];
|
|
120
|
+
const runs = [];
|
|
121
|
+
let dark = row[0] === 1;
|
|
122
|
+
let start = 0;
|
|
123
|
+
for (let x = 1; x < row.length; x++) {
|
|
124
|
+
const nextDark = row[x] === 1;
|
|
125
|
+
if (nextDark === dark)
|
|
126
|
+
continue;
|
|
127
|
+
runs.push({ width: x - start, dark });
|
|
128
|
+
start = x;
|
|
129
|
+
dark = nextDark;
|
|
130
|
+
}
|
|
131
|
+
runs.push({ width: row.length - start, dark });
|
|
132
|
+
return runs;
|
|
136
133
|
}
|
|
137
|
-
|
|
138
134
|
/**
|
|
139
135
|
* Normalize a candidate's pixel runs to the 96 logical DataBar modules.
|
|
140
136
|
* Rounding is followed by a small conservation pass so mild non-integer
|
|
@@ -143,46 +139,55 @@ function scanlineRuns(row) {
|
|
|
143
139
|
* @returns {number[]|null}
|
|
144
140
|
*/
|
|
145
141
|
function normalizeScanlineWidths(raw) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
142
|
+
const total = raw.reduce((sum, width) => sum + width, 0);
|
|
143
|
+
if (total <= 0)
|
|
144
|
+
return null;
|
|
145
|
+
const scale = total / 96;
|
|
146
|
+
if (scale < 0.5)
|
|
147
|
+
return null;
|
|
148
|
+
const widths = raw.map((width) => Math.max(1, Math.round(width / scale)));
|
|
149
|
+
let delta = 96 - widths.reduce((sum, width) => sum + width, 0);
|
|
150
|
+
while (delta !== 0) {
|
|
151
|
+
if (delta > 0) {
|
|
152
|
+
let index = 0;
|
|
153
|
+
for (let i = 1; i < widths.length; i++)
|
|
154
|
+
if (raw[i] > raw[index])
|
|
155
|
+
index = i;
|
|
156
|
+
widths[index]++;
|
|
157
|
+
delta--;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
let index = -1;
|
|
161
|
+
for (let i = 0; i < widths.length; i++) {
|
|
162
|
+
if (widths[i] <= 1)
|
|
163
|
+
continue;
|
|
164
|
+
if (index < 0 || raw[i] / widths[i] > raw[index] / widths[index])
|
|
165
|
+
index = i;
|
|
166
|
+
}
|
|
167
|
+
if (index < 0)
|
|
168
|
+
return null;
|
|
169
|
+
widths[index]--;
|
|
170
|
+
delta++;
|
|
171
|
+
}
|
|
167
172
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
173
|
+
if (widths[0] !== 1 || widths[widths.length - 1] !== 1)
|
|
174
|
+
return null;
|
|
175
|
+
return widths;
|
|
171
176
|
}
|
|
172
|
-
|
|
173
177
|
/** Build a 96-module row from normalized alternating runs. */
|
|
174
178
|
function matrixFromRuns(widths, darkFirst) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
179
|
+
const matrix = new BitMatrix(96, 1);
|
|
180
|
+
let x = 0;
|
|
181
|
+
let dark = darkFirst;
|
|
182
|
+
for (const width of widths) {
|
|
183
|
+
if (dark)
|
|
184
|
+
for (let i = 0; i < width; i++)
|
|
185
|
+
matrix.set(x + i, 0);
|
|
186
|
+
x += width;
|
|
187
|
+
dark = !dark;
|
|
188
|
+
}
|
|
189
|
+
return matrix;
|
|
184
190
|
}
|
|
185
|
-
|
|
186
191
|
/**
|
|
187
192
|
* Decode GS1 DataBar-14 from one raster scanline. This is the image layer over
|
|
188
193
|
* the existing clean 96-module decoder; it recognizes both Omnidirectional
|
|
@@ -192,24 +197,28 @@ function matrixFromRuns(widths, darkFirst) {
|
|
|
192
197
|
* @returns {{format:'gs1databar14', text:string, gtin:string, gs1:boolean, linkage:boolean, symbologyIdentifier:string, elements:Array}|null}
|
|
193
198
|
*/
|
|
194
199
|
export function decodeDataBar14Scanline(row) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
200
|
+
const runs = scanlineRuns(row);
|
|
201
|
+
for (let start = 0; start + 46 <= runs.length; start++) {
|
|
202
|
+
if (runs[start].dark)
|
|
203
|
+
continue;
|
|
204
|
+
const candidate = runs.slice(start, start + 46);
|
|
205
|
+
if (start + 46 < runs.length && runs[start + 46].dark)
|
|
206
|
+
continue;
|
|
207
|
+
const widths = normalizeScanlineWidths(candidate.map((run) => run.width));
|
|
208
|
+
if (!widths)
|
|
209
|
+
continue;
|
|
210
|
+
try {
|
|
211
|
+
const decoded = decodeDataBar14(matrixFromRuns(widths, false));
|
|
212
|
+
return {
|
|
213
|
+
...decoded,
|
|
214
|
+
format: 'gs1databar14',
|
|
215
|
+
gs1: true,
|
|
216
|
+
elements: [{ ai: '01', value: decoded.gtin, fixed: true }],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
// Try the next light-run candidate in the scanline.
|
|
221
|
+
}
|
|
212
222
|
}
|
|
213
|
-
|
|
214
|
-
return null;
|
|
223
|
+
return null;
|
|
215
224
|
}
|