@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,70 +27,62 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/** GS1 DataBar Omnidirectional and Truncated encoder. @module databar/encoder */
|
|
32
|
-
|
|
33
31
|
import { BitMatrix } from '../core/bit-matrix.js';
|
|
34
32
|
import { EncodeError } from '../core/errors.js';
|
|
35
33
|
import { encodeDataBar14GTIN } from './codec.js';
|
|
36
|
-
import {
|
|
37
|
-
DATABAR14_CHECKSUM_WEIGHTS,
|
|
38
|
-
DATABAR14_FINDERS,
|
|
39
|
-
dataBar14CharacterWidths,
|
|
40
|
-
} from './patterns.js';
|
|
41
|
-
|
|
34
|
+
import { DATABAR14_CHECKSUM_WEIGHTS, DATABAR14_FINDERS, dataBar14CharacterWidths, } from './patterns.js';
|
|
42
35
|
function finderIndexes(characters) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
checksum += widths[character][element] * DATABAR14_CHECKSUM_WEIGHTS[weightOffsets[character] + element];
|
|
36
|
+
const widths = characters.map((value, index) => dataBar14CharacterWidths(value, index === 0 || index === 3 ? 'outside' : 'inside'));
|
|
37
|
+
let checksum = 0;
|
|
38
|
+
const weightOffsets = [0, 8, 24, 16];
|
|
39
|
+
for (let character = 0; character < 4; character++) {
|
|
40
|
+
for (let element = 0; element < 8; element++) {
|
|
41
|
+
checksum += widths[character][element] * DATABAR14_CHECKSUM_WEIGHTS[weightOffsets[character] + element];
|
|
42
|
+
}
|
|
51
43
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
44
|
+
checksum %= 79;
|
|
45
|
+
if (checksum >= 8)
|
|
46
|
+
checksum++;
|
|
47
|
+
if (checksum >= 72)
|
|
48
|
+
checksum++;
|
|
49
|
+
return { widths, checksum, left: Math.floor(checksum / 9), right: checksum % 9 };
|
|
57
50
|
}
|
|
58
|
-
|
|
59
51
|
function widthsToMatrix(widths, height) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
52
|
+
const width = widths.reduce((sum, value) => sum + value, 0);
|
|
53
|
+
const matrix = new BitMatrix(width, height);
|
|
54
|
+
let dark = false;
|
|
55
|
+
let x = 0;
|
|
56
|
+
for (const run of widths) {
|
|
57
|
+
if (dark)
|
|
58
|
+
matrix.setRegion(x, 0, run, height);
|
|
59
|
+
x += run;
|
|
60
|
+
dark = !dark;
|
|
61
|
+
}
|
|
62
|
+
return matrix;
|
|
70
63
|
}
|
|
71
|
-
|
|
72
64
|
/** Encode a checked GTIN as DataBar Omnidirectional or Truncated. */
|
|
73
65
|
export function encodeDataBar14(value, options = {}) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
66
|
+
const variant = options.variant ?? 'omnidirectional';
|
|
67
|
+
if (variant !== 'omnidirectional' && variant !== 'truncated') {
|
|
68
|
+
throw new EncodeError('GS1 DataBar-14 physical encoder currently supports omnidirectional and truncated');
|
|
69
|
+
}
|
|
70
|
+
const height = options.height ?? (variant === 'omnidirectional' ? 33 : 13);
|
|
71
|
+
if (!Number.isInteger(height) || height < (variant === 'omnidirectional' ? 33 : 13)) {
|
|
72
|
+
throw new EncodeError(`GS1 DataBar ${variant} height is below its normative minimum`);
|
|
73
|
+
}
|
|
74
|
+
const compacted = encodeDataBar14GTIN(value, { linkage: options.linkage });
|
|
75
|
+
const characters = compacted.physicalCharacters;
|
|
76
|
+
const check = finderIndexes(characters);
|
|
77
|
+
const widths = [1, 1];
|
|
78
|
+
widths.push(...check.widths[0]);
|
|
79
|
+
widths.push(...DATABAR14_FINDERS[check.left]);
|
|
80
|
+
widths.push(...check.widths[1].slice().reverse());
|
|
81
|
+
widths.push(...check.widths[2]);
|
|
82
|
+
widths.push(...DATABAR14_FINDERS[check.right].slice().reverse());
|
|
83
|
+
widths.push(...check.widths[3].slice().reverse());
|
|
84
|
+
widths.push(1, 1);
|
|
85
|
+
const matrix = widthsToMatrix(widths, height);
|
|
86
|
+
matrix.databar = Object.freeze({ variant, gtin: compacted.gtin, linkage: compacted.linkage, checksum: check.checksum });
|
|
87
|
+
return matrix;
|
|
96
88
|
}
|
package/src/js/databar/gs1.js
CHANGED
|
@@ -27,151 +27,150 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/** GS1 element-string codec used by GS1 DataBar Expanded. @module databar/gs1 */
|
|
32
|
-
|
|
33
31
|
import { EncodeError, FormatError } from '../core/errors.js';
|
|
34
|
-
|
|
35
32
|
export const GS1_SEPARATOR = '\x1d';
|
|
36
|
-
|
|
37
33
|
const EXACT = new Map([
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
34
|
+
['00', [18, true]], ['01', [14, true]], ['02', [14, true]],
|
|
35
|
+
['10', [20, false]], ['11', [6, true]], ['12', [6, true]],
|
|
36
|
+
['13', [6, true]], ['15', [6, true]], ['16', [6, true]],
|
|
37
|
+
['17', [6, true]], ['20', [2, true]], ['21', [20, false]],
|
|
38
|
+
['22', [29, false]], ['30', [8, false]], ['37', [8, false]],
|
|
39
|
+
['240', [30, false]], ['241', [30, false]], ['242', [6, false]],
|
|
40
|
+
['243', [20, false]], ['250', [30, false]], ['251', [30, false]],
|
|
41
|
+
['253', [30, false]], ['254', [20, false]], ['255', [13, true]],
|
|
42
|
+
['400', [30, false]], ['401', [30, false]], ['402', [17, true]],
|
|
43
|
+
['403', [30, false]], ['410', [13, true]], ['411', [13, true]],
|
|
44
|
+
['412', [13, true]], ['413', [13, true]], ['414', [13, true]],
|
|
45
|
+
['415', [13, true]], ['416', [13, true]], ['417', [13, true]],
|
|
46
|
+
['420', [20, false]], ['421', [15, false]], ['422', [3, true]],
|
|
47
|
+
['423', [15, false]], ['424', [3, true]], ['425', [3, true]],
|
|
48
|
+
['426', [3, true]], ['427', [3, false]],
|
|
49
|
+
['7001', [13, true]], ['7002', [30, false]], ['7003', [10, true]],
|
|
50
|
+
['7004', [4, false]], ['7005', [12, false]], ['7006', [6, true]],
|
|
51
|
+
['7007', [12, false]], ['7008', [3, false]], ['7009', [10, false]],
|
|
52
|
+
['7010', [2, false]], ['7020', [20, false]], ['7021', [20, false]],
|
|
53
|
+
['7022', [20, false]], ['710', [20, false]], ['711', [20, false]],
|
|
54
|
+
['712', [20, false]], ['713', [20, false]], ['714', [20, false]],
|
|
55
|
+
['715', [20, false]],
|
|
56
|
+
['8001', [14, true]], ['8002', [20, false]], ['8003', [30, false]],
|
|
57
|
+
['8004', [30, false]], ['8005', [6, true]], ['8006', [18, true]],
|
|
58
|
+
['8007', [34, false]], ['8008', [12, false]], ['8009', [50, false]],
|
|
59
|
+
['8010', [30, false]], ['8011', [12, false]], ['8012', [20, false]],
|
|
60
|
+
['8013', [30, false]], ['8017', [18, true]], ['8018', [18, true]],
|
|
61
|
+
['8019', [10, false]], ['8020', [25, false]], ['8026', [18, true]],
|
|
62
|
+
['8110', [70, false]], ['8111', [4, true]], ['8112', [70, false]],
|
|
63
|
+
['8200', [70, false]],
|
|
68
64
|
]);
|
|
69
|
-
|
|
70
65
|
function rangedAI(ai) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
66
|
+
if (/^31[0-6]\d$/.test(ai) || /^32[0-7]\d$/.test(ai) ||
|
|
67
|
+
/^33[0-7]\d$/.test(ai) || /^34[0-9]\d$/.test(ai) ||
|
|
68
|
+
/^35[0-7]\d$/.test(ai) || /^36[0-9]\d$/.test(ai))
|
|
69
|
+
return [6, true];
|
|
70
|
+
if (/^390\d$/.test(ai) || /^392\d$/.test(ai))
|
|
71
|
+
return [15, false];
|
|
72
|
+
if (/^391\d$/.test(ai) || /^393\d$/.test(ai))
|
|
73
|
+
return [18, false];
|
|
74
|
+
if (/^394\d$/.test(ai))
|
|
75
|
+
return [4, true];
|
|
76
|
+
if (/^395\d$/.test(ai))
|
|
77
|
+
return [6, true];
|
|
78
|
+
if (/^703\d$/.test(ai) || /^723\d$/.test(ai))
|
|
79
|
+
return [30, false];
|
|
80
|
+
return undefined;
|
|
80
81
|
}
|
|
81
|
-
|
|
82
82
|
export function gs1AIInfo(ai) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
if (typeof ai !== 'string' || !/^\d{2,4}$/.test(ai))
|
|
84
|
+
return undefined;
|
|
85
|
+
const spec = EXACT.get(ai) || rangedAI(ai);
|
|
86
|
+
if (!spec)
|
|
87
|
+
return undefined;
|
|
88
|
+
return { ai, length: spec[0], fixed: spec[1] };
|
|
87
89
|
}
|
|
88
|
-
|
|
89
90
|
function assertCharacters(value, label, ErrorType) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
if (/[^\x20-\x7e]/.test(value)) {
|
|
92
|
+
throw new ErrorType(`GS1: ${label} contains a character outside the GS1 element-string character set`);
|
|
93
|
+
}
|
|
93
94
|
}
|
|
94
|
-
|
|
95
95
|
function validateElement(ai, value, ErrorType) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
const info = gs1AIInfo(ai);
|
|
97
|
+
if (!info)
|
|
98
|
+
throw new ErrorType(`GS1: unsupported or invalid Application Identifier ${ai}`);
|
|
99
|
+
if (value.length === 0)
|
|
100
|
+
throw new ErrorType(`GS1: AI ${ai} must not be empty`);
|
|
101
|
+
if (info.fixed ? value.length !== info.length : value.length > info.length) {
|
|
102
|
+
const expectation = info.fixed ? `exactly ${info.length}` : `at most ${info.length}`;
|
|
103
|
+
throw new ErrorType(`GS1: AI ${ai} requires ${expectation} characters`);
|
|
104
|
+
}
|
|
105
|
+
assertCharacters(value, `AI ${ai}`, ErrorType);
|
|
106
|
+
return { ai, value, fixed: info.fixed };
|
|
105
107
|
}
|
|
106
|
-
|
|
107
108
|
export function parseGS1ElementString(input) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
109
|
+
if (typeof input !== 'string' || input.length === 0) {
|
|
110
|
+
throw new EncodeError('GS1: element string must be a non-empty string');
|
|
111
|
+
}
|
|
112
|
+
const elements = [];
|
|
113
|
+
let offset = 0;
|
|
114
|
+
while (offset < input.length) {
|
|
115
|
+
const match = /^\((\d{2,4})\)/.exec(input.slice(offset));
|
|
116
|
+
if (!match)
|
|
117
|
+
throw new EncodeError(`GS1: expected an Application Identifier at offset ${offset}`);
|
|
118
|
+
const ai = match[1];
|
|
119
|
+
offset += match[0].length;
|
|
120
|
+
const next = input.indexOf('(', offset);
|
|
121
|
+
const end = next < 0 ? input.length : next;
|
|
122
|
+
elements.push(validateElement(ai, input.slice(offset, end), EncodeError));
|
|
123
|
+
offset = end;
|
|
124
|
+
}
|
|
125
|
+
return elements;
|
|
124
126
|
}
|
|
125
|
-
|
|
126
127
|
export function encodeGS1ElementString(input) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
`${element.ai}${element.value}${!element.fixed && index + 1 < elements.length ? GS1_SEPARATOR : ''}`
|
|
132
|
-
).join('');
|
|
128
|
+
const elements = Array.isArray(input)
|
|
129
|
+
? input.map(({ ai, value }) => validateElement(String(ai), String(value), EncodeError))
|
|
130
|
+
: parseGS1ElementString(input);
|
|
131
|
+
return elements.map((element, index) => `${element.ai}${element.value}${!element.fixed && index + 1 < elements.length ? GS1_SEPARATOR : ''}`).join('');
|
|
133
132
|
}
|
|
134
|
-
|
|
135
133
|
function matchAIAt(data, offset) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
134
|
+
for (const length of [4, 3, 2]) {
|
|
135
|
+
const ai = data.slice(offset, offset + length);
|
|
136
|
+
if (gs1AIInfo(ai))
|
|
137
|
+
return ai;
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
141
140
|
}
|
|
142
|
-
|
|
143
141
|
export function decodeGS1ElementString(data) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
const elements = [];
|
|
148
|
-
let offset = 0;
|
|
149
|
-
while (offset < data.length) {
|
|
150
|
-
if (data[offset] === GS1_SEPARATOR) {
|
|
151
|
-
throw new FormatError(`GS1: unexpected separator at offset ${offset}`);
|
|
142
|
+
if (typeof data !== 'string' || data.length === 0) {
|
|
143
|
+
throw new FormatError('GS1: encoded data must be a non-empty string');
|
|
152
144
|
}
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
offset
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
145
|
+
const elements = [];
|
|
146
|
+
let offset = 0;
|
|
147
|
+
while (offset < data.length) {
|
|
148
|
+
if (data[offset] === GS1_SEPARATOR) {
|
|
149
|
+
throw new FormatError(`GS1: unexpected separator at offset ${offset}`);
|
|
150
|
+
}
|
|
151
|
+
const ai = matchAIAt(data, offset);
|
|
152
|
+
if (!ai)
|
|
153
|
+
throw new FormatError(`GS1: unknown Application Identifier at offset ${offset}`);
|
|
154
|
+
offset += ai.length;
|
|
155
|
+
const info = gs1AIInfo(ai);
|
|
156
|
+
let value;
|
|
157
|
+
if (info.fixed) {
|
|
158
|
+
value = data.slice(offset, offset + info.length);
|
|
159
|
+
if (value.length !== info.length || value.includes(GS1_SEPARATOR)) {
|
|
160
|
+
throw new FormatError(`GS1: truncated fixed-length AI ${ai}`);
|
|
161
|
+
}
|
|
162
|
+
offset += info.length;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
const separator = data.indexOf(GS1_SEPARATOR, offset);
|
|
166
|
+
const end = separator < 0 ? data.length : separator;
|
|
167
|
+
value = data.slice(offset, end);
|
|
168
|
+
offset = separator < 0 ? data.length : separator + 1;
|
|
169
|
+
}
|
|
170
|
+
elements.push(validateElement(ai, value, FormatError));
|
|
169
171
|
}
|
|
170
|
-
elements
|
|
171
|
-
}
|
|
172
|
-
return elements;
|
|
172
|
+
return elements;
|
|
173
173
|
}
|
|
174
|
-
|
|
175
174
|
export function formatGS1Elements(elements) {
|
|
176
|
-
|
|
175
|
+
return elements.map(({ ai, value }) => `(${ai})${value}`).join('');
|
|
177
176
|
}
|
package/src/js/databar/index.js
CHANGED
|
@@ -27,42 +27,10 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/** Verified GS1 DataBar data-layer primitives. @module databar */
|
|
32
|
-
|
|
33
|
-
export {
|
|
34
|
-
|
|
35
|
-
decodeDataBar14GTIN,
|
|
36
|
-
decodeDataBarLimitedGTIN,
|
|
37
|
-
encodeDataBar14GTIN,
|
|
38
|
-
encodeDataBarLimitedGTIN,
|
|
39
|
-
gtinCheckDigit,
|
|
40
|
-
makeGTIN14,
|
|
41
|
-
normalizeGTIN,
|
|
42
|
-
} from './codec.js';
|
|
43
|
-
|
|
44
|
-
export {
|
|
45
|
-
GS1_SEPARATOR,
|
|
46
|
-
decodeGS1ElementString,
|
|
47
|
-
encodeGS1ElementString,
|
|
48
|
-
formatGS1Elements,
|
|
49
|
-
gs1AIInfo,
|
|
50
|
-
parseGS1ElementString,
|
|
51
|
-
} from './gs1.js';
|
|
52
|
-
|
|
53
|
-
export {
|
|
54
|
-
DATABAR14_VARIANTS,
|
|
55
|
-
DATABAR_LIMITED_VARIANT,
|
|
56
|
-
dataBar14GroupFor,
|
|
57
|
-
validateDataBarTables,
|
|
58
|
-
} from './tables.js';
|
|
59
|
-
|
|
31
|
+
export { dataBarGtinTransmission, decodeDataBar14GTIN, decodeDataBarLimitedGTIN, encodeDataBar14GTIN, encodeDataBarLimitedGTIN, gtinCheckDigit, makeGTIN14, normalizeGTIN, } from './codec.js';
|
|
32
|
+
export { GS1_SEPARATOR, decodeGS1ElementString, encodeGS1ElementString, formatGS1Elements, gs1AIInfo, parseGS1ElementString, } from './gs1.js';
|
|
33
|
+
export { DATABAR14_VARIANTS, DATABAR_LIMITED_VARIANT, dataBar14GroupFor, validateDataBarTables, } from './tables.js';
|
|
60
34
|
export { encodeDataBar14 } from './encoder.js';
|
|
61
35
|
export { decodeDataBar14, decodeDataBar14Scanline } from './decoder.js';
|
|
62
|
-
export {
|
|
63
|
-
DATABAR14_CHECKSUM_WEIGHTS,
|
|
64
|
-
DATABAR14_FINDERS,
|
|
65
|
-
dataBar14CharacterWidths,
|
|
66
|
-
dataBar14ValueForWidths,
|
|
67
|
-
dataBarWidths,
|
|
68
|
-
} from './patterns.js';
|
|
36
|
+
export { DATABAR14_CHECKSUM_WEIGHTS, DATABAR14_FINDERS, dataBar14CharacterWidths, dataBar14ValueForWidths, dataBarWidths, } from './patterns.js';
|
|
@@ -27,20 +27,19 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/** Mathematical width construction for GS1 DataBar characters. @module databar/patterns */
|
|
32
|
-
|
|
33
31
|
import { dataBar14GroupFor } from './tables.js';
|
|
34
|
-
|
|
35
32
|
function combinations(n, r) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
if (n < r || r < 0)
|
|
34
|
+
return 0;
|
|
35
|
+
if (r === 0 || n === r)
|
|
36
|
+
return 1;
|
|
37
|
+
let result = 1;
|
|
38
|
+
const k = Math.min(r, n - r);
|
|
39
|
+
for (let i = 1; i <= k; i++)
|
|
40
|
+
result = result * (n - k + i) / i;
|
|
41
|
+
return result;
|
|
42
42
|
}
|
|
43
|
-
|
|
44
43
|
/**
|
|
45
44
|
* Unrank one constrained positive composition.
|
|
46
45
|
*
|
|
@@ -49,95 +48,92 @@ function combinations(n, r) {
|
|
|
49
48
|
* every remaining admissible suffix rather than storing third-party patterns.
|
|
50
49
|
*/
|
|
51
50
|
export function dataBarWidths(rank, modules, elements, maximumWidth, noNarrow) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
51
|
+
if (!Number.isInteger(rank) || rank < 0)
|
|
52
|
+
throw new RangeError('GS1 DataBar width rank must be non-negative');
|
|
53
|
+
const widths = new Array(elements).fill(0);
|
|
54
|
+
let remaining = modules;
|
|
55
|
+
let narrowMask = 0;
|
|
56
|
+
for (let bar = 0; bar < elements - 1; bar++) {
|
|
57
|
+
let count = 0;
|
|
58
|
+
for (let width = 1;; width++) {
|
|
59
|
+
narrowMask |= width === 1 ? 1 << bar : 0;
|
|
60
|
+
count = combinations(remaining - width - 1, elements - bar - 2);
|
|
61
|
+
if (noNarrow && narrowMask === 0 && remaining - width - (elements - bar - 1) >= elements - bar - 1) {
|
|
62
|
+
count -= combinations(remaining - width - (elements - bar), elements - bar - 2);
|
|
63
|
+
}
|
|
64
|
+
if (elements - bar - 1 > 1) {
|
|
65
|
+
let tooWide = 0;
|
|
66
|
+
for (let last = remaining - width - (elements - bar - 2); last > maximumWidth; last--) {
|
|
67
|
+
tooWide += combinations(remaining - width - last - 1, elements - bar - 3);
|
|
68
|
+
}
|
|
69
|
+
count -= tooWide * (elements - 1 - bar);
|
|
70
|
+
}
|
|
71
|
+
else if (remaining - width > maximumWidth) {
|
|
72
|
+
count--;
|
|
73
|
+
}
|
|
74
|
+
if (rank < count) {
|
|
75
|
+
widths[bar] = width;
|
|
76
|
+
remaining -= width;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
rank -= count;
|
|
80
|
+
narrowMask &= ~(1 << bar);
|
|
71
81
|
}
|
|
72
|
-
count -= tooWide * (elements - 1 - bar);
|
|
73
|
-
} else if (remaining - width > maximumWidth) {
|
|
74
|
-
count--;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (rank < count) {
|
|
78
|
-
widths[bar] = width;
|
|
79
|
-
remaining -= width;
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
rank -= count;
|
|
83
|
-
narrowMask &= ~(1 << bar);
|
|
84
82
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return widths;
|
|
83
|
+
widths[elements - 1] = remaining;
|
|
84
|
+
if (rank !== 0 || widths.some((width) => width < 1 || width > maximumWidth)) {
|
|
85
|
+
throw new RangeError('GS1 DataBar width rank exceeds its character group');
|
|
86
|
+
}
|
|
87
|
+
return widths;
|
|
91
88
|
}
|
|
92
|
-
|
|
93
89
|
/** Convert one DataBar-14 character value into its eight alternating widths. */
|
|
94
90
|
export function dataBar14CharacterWidths(value, kind) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
91
|
+
const group = dataBar14GroupFor(value, kind);
|
|
92
|
+
const offset = value - group.gsum;
|
|
93
|
+
const outside = kind === 'outside';
|
|
94
|
+
const oddRank = outside ? Math.floor(offset / group.evenTotal) : offset % group.oddTotal;
|
|
95
|
+
const evenRank = outside ? offset % group.evenTotal : Math.floor(offset / group.oddTotal);
|
|
96
|
+
const odd = dataBarWidths(oddRank, group.oddModules, 4, group.oddWidest, !outside);
|
|
97
|
+
const even = dataBarWidths(evenRank, group.evenModules, 4, group.evenWidest, outside);
|
|
98
|
+
const result = [];
|
|
99
|
+
for (let i = 0; i < 4; i++)
|
|
100
|
+
result.push(odd[i], even[i]);
|
|
101
|
+
return result;
|
|
105
102
|
}
|
|
106
|
-
|
|
107
103
|
const inverseCharacterMaps = new Map();
|
|
108
|
-
|
|
109
104
|
/** Recover a character value from its canonical eight-width representation. */
|
|
110
105
|
export function dataBar14ValueForWidths(widths, kind) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
106
|
+
if (!Array.isArray(widths) || widths.length !== 8 || widths.some((width) => !Number.isInteger(width) || width < 1)) {
|
|
107
|
+
throw new TypeError('GS1 DataBar character widths must contain eight positive integers');
|
|
108
|
+
}
|
|
109
|
+
if (kind !== 'outside' && kind !== 'inside')
|
|
110
|
+
throw new RangeError(`Unknown GS1 DataBar character kind "${kind}"`);
|
|
111
|
+
let inverse = inverseCharacterMaps.get(kind);
|
|
112
|
+
if (!inverse) {
|
|
113
|
+
inverse = new Map();
|
|
114
|
+
const maximum = kind === 'outside' ? 2840 : 1596;
|
|
115
|
+
for (let value = 0; value <= maximum; value++) {
|
|
116
|
+
inverse.set(dataBar14CharacterWidths(value, kind).join(','), value);
|
|
117
|
+
}
|
|
118
|
+
inverseCharacterMaps.set(kind, inverse);
|
|
121
119
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return value;
|
|
120
|
+
const value = inverse.get(widths.join(','));
|
|
121
|
+
if (value === undefined)
|
|
122
|
+
throw new RangeError(`Invalid GS1 DataBar ${kind} character widths`);
|
|
123
|
+
return value;
|
|
127
124
|
}
|
|
128
|
-
|
|
129
125
|
/** Nine finder patterns, expressed as normative five-element widths. */
|
|
130
126
|
export const DATABAR14_FINDERS = Object.freeze([
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
127
|
+
Object.freeze([3, 8, 2, 1, 1]), Object.freeze([3, 5, 5, 1, 1]),
|
|
128
|
+
Object.freeze([3, 3, 7, 1, 1]), Object.freeze([3, 1, 9, 1, 1]),
|
|
129
|
+
Object.freeze([2, 7, 4, 1, 1]), Object.freeze([2, 5, 6, 1, 1]),
|
|
130
|
+
Object.freeze([2, 3, 8, 1, 1]), Object.freeze([1, 5, 7, 1, 1]),
|
|
131
|
+
Object.freeze([1, 3, 9, 1, 1]),
|
|
136
132
|
]);
|
|
137
|
-
|
|
138
133
|
/** Weight sequence generated as powers of three modulo 79. */
|
|
139
134
|
export const DATABAR14_CHECKSUM_WEIGHTS = Object.freeze(Array.from({ length: 32 }, (_, index) => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
135
|
+
let value = 1;
|
|
136
|
+
for (let i = 0; i < index; i++)
|
|
137
|
+
value = (value * 3) % 79;
|
|
138
|
+
return value;
|
|
143
139
|
}));
|