@sythos/js_barcode_universal 1.3.1 → 1.5.0
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/AI_USAGE.md +33 -0
- package/LICENSE +4 -2
- package/NOTICE.md +10 -5
- package/README.md +95 -31
- package/bundle/sythos-barcode.esm.js +11552 -8877
- package/bundle/sythos-barcode.js +11469 -8877
- package/examples/create.html +2 -1
- package/examples/read.html +6 -0
- package/licenses/README.md +5 -0
- package/licenses/aztec-rune.license +76 -0
- package/licenses/compact-pdf417.license +76 -0
- package/licenses/ean-2.license +75 -0
- package/licenses/ean-5.license +75 -0
- package/licenses/gs1-databar.license +84 -0
- package/package.json +16 -4
- package/src/aztec/decoder.js +1 -0
- package/src/aztec/detector.js +1 -0
- package/src/aztec/encoder.js +1 -0
- package/src/aztec/high-level.js +1 -0
- package/src/aztec/index.js +1 -0
- package/src/aztec/tables.js +1 -0
- package/src/aztecrune/decoder.js +156 -0
- package/src/aztecrune/detector.js +167 -0
- package/src/aztecrune/encoder.js +122 -0
- package/src/aztecrune/index.js +50 -0
- package/src/aztecrune/tables.js +138 -0
- package/src/compactpdf417/decoder.js +129 -0
- package/src/compactpdf417/detector.js +140 -0
- package/src/compactpdf417/encoder.js +141 -0
- package/src/compactpdf417/index.js +22 -0
- package/src/compactpdf417/tables.js +174 -0
- package/src/core/bit-buffer.js +1 -0
- package/src/core/bit-matrix.js +1 -0
- package/src/core/errors.js +1 -0
- package/src/core/galois-field.js +1 -0
- package/src/core/index.js +1 -0
- package/src/core/reed-solomon.js +1 -0
- package/src/databar/codec.js +182 -0
- package/src/databar/decoder.js +216 -0
- package/src/databar/encoder.js +97 -0
- package/src/databar/gs1.js +178 -0
- package/src/databar/index.js +69 -0
- package/src/databar/patterns.js +144 -0
- package/src/databar/tables.js +125 -0
- package/src/datamatrix/decoder.js +1 -0
- package/src/datamatrix/detector.js +1 -0
- package/src/datamatrix/encoder.js +1 -0
- package/src/datamatrix/index.js +1 -0
- package/src/datamatrix/tables.js +1 -0
- package/src/frameqr/decoder.js +16 -15
- package/src/frameqr/detector.js +3 -2
- package/src/frameqr/encoder.js +8 -7
- package/src/frameqr/index.js +1 -0
- package/src/frameqr/tables.js +11 -10
- package/src/image/binarizer.js +1 -0
- package/src/image/grid-sampler.js +1 -0
- package/src/image/index.js +1 -0
- package/src/image/luminance.js +1 -0
- package/src/image/perspective.js +1 -0
- package/src/index.js +101 -12
- package/src/micropdf417/compaction.js +1 -0
- package/src/micropdf417/decoder.js +1 -0
- package/src/micropdf417/detector.js +1 -0
- package/src/micropdf417/encoder.js +1 -0
- package/src/micropdf417/error-correction.js +1 -0
- package/src/micropdf417/index.js +1 -0
- package/src/micropdf417/tables.js +1 -0
- package/src/microqr/decoder.js +1 -0
- package/src/microqr/detector.js +1 -0
- package/src/microqr/encoder.js +1 -0
- package/src/microqr/index.js +1 -0
- package/src/microqr/tables.js +1 -0
- package/src/oned/addons.js +421 -0
- package/src/oned/index.js +21 -3
- package/src/oned/patterns.js +1 -0
- package/src/oned/reader.js +330 -11
- package/src/oned/writers.js +6 -0
- package/src/pdf417/compaction.js +1 -0
- package/src/pdf417/decoder.js +1 -0
- package/src/pdf417/detector.js +1 -0
- package/src/pdf417/encoder.js +1 -0
- package/src/pdf417/error-correction.js +1 -0
- package/src/pdf417/index.js +5 -0
- package/src/pdf417/tables.js +1 -0
- package/src/qr/decoder.js +1 -0
- package/src/qr/detector.js +1 -0
- package/src/qr/encoder.js +1 -0
- package/src/qr/index.js +1 -0
- package/src/qr/tables.js +1 -0
- package/src/render/image-data.js +1 -0
- package/src/render/index.js +1 -0
- package/src/render/options.js +1 -0
- package/src/render/png.js +1 -0
- package/src/render/svg.js +1 -0
- package/src/render/webgl.js +1 -0
- package/src/render/webgpu.js +1 -0
- package/src/rmqr/decoder.js +1 -0
- package/src/rmqr/detector.js +1 -0
- package/src/rmqr/encoder.js +1 -0
- package/src/rmqr/index.js +1 -0
- package/src/rmqr/tables.js +1 -0
package/src/oned/reader.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* MIT License
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) 2026 Sythos
|
|
7
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
7
8
|
*
|
|
8
9
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
10
|
* of this software and associated documentation files (the "Software"), to deal
|
|
@@ -57,8 +58,14 @@ import {
|
|
|
57
58
|
CODE128_STOP, CODE128_FNC1, CODE128_CODE_A, CODE128_CODE_B, CODE128_CODE_C,
|
|
58
59
|
CODE128_SHIFT,
|
|
59
60
|
ITF, CODABAR, CODABAR_START_STOP,
|
|
61
|
+
CODE11, CODE11_START_STOP, MSI_START, MSI_STOP, MSI_BIT,
|
|
60
62
|
} from './patterns.js';
|
|
61
63
|
import { ean13CheckDigit, upceToUpcaBody } from './writers.js';
|
|
64
|
+
import {
|
|
65
|
+
EAN2_PARITY, EAN5_PARITY, EAN_ADDON_START, EAN_ADDON_SEPARATOR,
|
|
66
|
+
ean5Checksum,
|
|
67
|
+
} from './addons.js';
|
|
68
|
+
import { decodeDataBar14Scanline } from '../databar/decoder.js';
|
|
62
69
|
|
|
63
70
|
/* ------------------------------------------------------------------ *
|
|
64
71
|
* Pattern matching primitives
|
|
@@ -231,6 +238,14 @@ const CODABAR_BITS = Object.fromEntries(
|
|
|
231
238
|
Object.entries(CODABAR).map(([k, v]) => [nwToBits(v), k])
|
|
232
239
|
);
|
|
233
240
|
const ITF_BITS = Object.fromEntries(ITF.map((v, i) => [nwToBits(v), i]));
|
|
241
|
+
const CODE11_BITS = Object.fromEntries(
|
|
242
|
+
Object.entries(CODE11).flatMap(([ch, value]) => {
|
|
243
|
+
const bits = nwToBits(value);
|
|
244
|
+
return [[`${bits}:1`, ch], [`${bits}:2`, ch]];
|
|
245
|
+
})
|
|
246
|
+
);
|
|
247
|
+
const CODE11_START_BITS = nwToBits(CODE11_START_STOP);
|
|
248
|
+
const CODE11_CHARSET = '0123456789-';
|
|
234
249
|
|
|
235
250
|
/**
|
|
236
251
|
* Shortest ITF payload treated as a real read.
|
|
@@ -316,7 +331,8 @@ function decodeEANFamily(row) {
|
|
|
316
331
|
digits.push(d.digit);
|
|
317
332
|
offset = d.end;
|
|
318
333
|
}
|
|
319
|
-
|
|
334
|
+
const trailing = matchAt(row, offset, START_END_PATTERN);
|
|
335
|
+
if (!trailing) return null;
|
|
320
336
|
|
|
321
337
|
const parityStr = [];
|
|
322
338
|
for (let i = 0; i < 6; i++) parityStr.push((parityBits >> (5 - i)) & 1 ? 'G' : 'L');
|
|
@@ -327,9 +343,10 @@ function decodeEANFamily(row) {
|
|
|
327
343
|
if (Number(text[12]) !== ean13CheckDigit(text.slice(0, 12))) return null;
|
|
328
344
|
|
|
329
345
|
// A leading zero means this was printed as UPC-A.
|
|
330
|
-
|
|
346
|
+
const result = first === 0
|
|
331
347
|
? { format: 'upca', text: text.slice(1) }
|
|
332
348
|
: { format: 'ean13', text };
|
|
349
|
+
return attachEANAddon(result, row, trailing.end);
|
|
333
350
|
}
|
|
334
351
|
|
|
335
352
|
return null;
|
|
@@ -364,11 +381,12 @@ function decodeEAN8(row) {
|
|
|
364
381
|
digits.push(d.digit);
|
|
365
382
|
offset = d.end;
|
|
366
383
|
}
|
|
367
|
-
|
|
384
|
+
const trailing = matchAt(row, offset, START_END_PATTERN);
|
|
385
|
+
if (!trailing) return null;
|
|
368
386
|
|
|
369
387
|
const text = digits.join('');
|
|
370
388
|
if (Number(text[7]) !== ean13CheckDigit(text.slice(0, 7))) return null;
|
|
371
|
-
return { format: 'ean8', text };
|
|
389
|
+
return attachEANAddon({ format: 'ean8', text }, row, trailing.end);
|
|
372
390
|
}
|
|
373
391
|
|
|
374
392
|
/**
|
|
@@ -395,7 +413,8 @@ function decodeUPCE(row) {
|
|
|
395
413
|
// Six digits and then the end guard, in that order and nothing between. The
|
|
396
414
|
// EAN readers above match their trailing guard; this one used to stop at the
|
|
397
415
|
// last digit, which let it report a symbol it had never seen the end of.
|
|
398
|
-
|
|
416
|
+
const trailing = matchAt(row, offset, UPCE_END_PATTERN);
|
|
417
|
+
if (!trailing) return null;
|
|
399
418
|
|
|
400
419
|
const parityStr = [];
|
|
401
420
|
for (let i = 0; i < 6; i++) parityStr.push((parityBits >> (5 - i)) & 1 ? 'E' : 'O');
|
|
@@ -412,7 +431,7 @@ function decodeUPCE(row) {
|
|
|
412
431
|
const body = digits.join('');
|
|
413
432
|
if (ean13CheckDigit(upceToUpcaBody(0, body)) !== check) return null;
|
|
414
433
|
|
|
415
|
-
return { format: 'upce', text: '0' + body + String(check) };
|
|
434
|
+
return attachEANAddon({ format: 'upce', text: '0' + body + String(check) }, row, trailing.end);
|
|
416
435
|
}
|
|
417
436
|
|
|
418
437
|
/* ------------------------------------------------------------------ *
|
|
@@ -483,6 +502,256 @@ function matchAt(row, start, pattern) {
|
|
|
483
502
|
return { end: start + width };
|
|
484
503
|
}
|
|
485
504
|
|
|
505
|
+
/* ------------------------------------------------------------------ *
|
|
506
|
+
* EAN supplements
|
|
507
|
+
* ------------------------------------------------------------------ */
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Decode a supplement immediately following a validated EAN/UPC symbol.
|
|
511
|
+
* The caller supplies the end of the parent trailing guard, so a supplement
|
|
512
|
+
* can never be accepted as an unrelated standalone linear symbol.
|
|
513
|
+
*
|
|
514
|
+
* @param {Uint8Array} row
|
|
515
|
+
* @param {number} baseEnd
|
|
516
|
+
* @param {2|5} digitCount
|
|
517
|
+
* @returns {{format:'ean2'|'ean5', text:string, parity:string, checksum?:number, end:number}|null}
|
|
518
|
+
*/
|
|
519
|
+
function decodeEANSupplementRow(row, baseEnd, digitCount) {
|
|
520
|
+
const guard = findGuard(row, baseEnd, [1, 1, 2], false);
|
|
521
|
+
if (!guard || guard.start - baseEnd < 4) return null;
|
|
522
|
+
|
|
523
|
+
let offset = guard.end;
|
|
524
|
+
let text = '';
|
|
525
|
+
let parity = '';
|
|
526
|
+
|
|
527
|
+
for (let i = 0; i < digitCount; i++) {
|
|
528
|
+
const digit = decodeEANDigit(row, offset, false);
|
|
529
|
+
if (!digit) return null;
|
|
530
|
+
text += String(digit.digit);
|
|
531
|
+
parity += digit.even ? 'B' : 'A';
|
|
532
|
+
offset = digit.end;
|
|
533
|
+
|
|
534
|
+
if (i + 1 < digitCount) {
|
|
535
|
+
const separator = matchAt(row, offset, [1, 1]);
|
|
536
|
+
if (!separator) return null;
|
|
537
|
+
offset = separator.end;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (digitCount === 2) {
|
|
542
|
+
if (EAN2_PARITY[Number(text) % 4] !== parity) return null;
|
|
543
|
+
return { format: 'ean2', text, parity, end: offset };
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const checksum = ean5Checksum(text);
|
|
547
|
+
if (EAN5_PARITY[checksum] !== parity) return null;
|
|
548
|
+
return { format: 'ean5', text, parity, checksum, end: offset };
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Attach the longest valid supplement to a base result. EAN-5 is attempted
|
|
553
|
+
* first so its prefix cannot be reported as a shorter EAN-2 symbol.
|
|
554
|
+
*
|
|
555
|
+
* @param {object} base
|
|
556
|
+
* @param {Uint8Array} row
|
|
557
|
+
* @param {number} baseEnd
|
|
558
|
+
* @returns {object}
|
|
559
|
+
*/
|
|
560
|
+
function attachEANAddon(base, row, baseEnd) {
|
|
561
|
+
const addon = decodeEANSupplementRow(row, baseEnd, 5)
|
|
562
|
+
?? decodeEANSupplementRow(row, baseEnd, 2);
|
|
563
|
+
if (!addon) return base;
|
|
564
|
+
const { end, ...publicAddon } = addon;
|
|
565
|
+
void end;
|
|
566
|
+
return { ...base, addon: publicAddon };
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/* ------------------------------------------------------------------ *
|
|
570
|
+
* Code 11 and MSI/Plessey
|
|
571
|
+
* ------------------------------------------------------------------ */
|
|
572
|
+
|
|
573
|
+
/** @param {number[]} counters @returns {number} */
|
|
574
|
+
function counterTotal(counters) {
|
|
575
|
+
return counters.reduce((sum, value) => sum + value, 0);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Apply the Code 11 C/K checksum grammar used by the writer.
|
|
580
|
+
*
|
|
581
|
+
* @param {string} encoded
|
|
582
|
+
* @param {boolean|undefined} requested
|
|
583
|
+
* @returns {string|null}
|
|
584
|
+
*/
|
|
585
|
+
function finalizeCode11(encoded, requested) {
|
|
586
|
+
const weighted = (text, maxWeight) => {
|
|
587
|
+
let sum = 0;
|
|
588
|
+
for (let i = 0; i < text.length; i++) {
|
|
589
|
+
const weight = ((text.length - 1 - i) % maxWeight) + 1;
|
|
590
|
+
sum += weight * CODE11_CHARSET.indexOf(text[i]);
|
|
591
|
+
}
|
|
592
|
+
return sum;
|
|
593
|
+
};
|
|
594
|
+
const validC = (text) => {
|
|
595
|
+
if (text.length < 2) return null;
|
|
596
|
+
const body = text.slice(0, -1);
|
|
597
|
+
const expected = CODE11_CHARSET[weighted(body, 10) % 11];
|
|
598
|
+
return text[text.length - 1] === expected ? body : null;
|
|
599
|
+
};
|
|
600
|
+
const validCK = (text) => {
|
|
601
|
+
if (text.length < 12) return null;
|
|
602
|
+
const body = text.slice(0, -2);
|
|
603
|
+
const c = text[text.length - 2];
|
|
604
|
+
const k = text[text.length - 1];
|
|
605
|
+
const expectedC = CODE11_CHARSET[weighted(body, 10) % 11];
|
|
606
|
+
if (c !== expectedC) return null;
|
|
607
|
+
const expectedK = CODE11_CHARSET[weighted(body + c, 9) % 11];
|
|
608
|
+
return k === expectedK ? body : null;
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
if (requested === false) return encoded;
|
|
612
|
+
if (requested === true) {
|
|
613
|
+
const checked = encoded.length >= 12 ? validCK(encoded) : validC(encoded);
|
|
614
|
+
return checked;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// With no explicit option, strip checks only when the complete grammar is
|
|
618
|
+
// unambiguous; otherwise preserve the literal payload.
|
|
619
|
+
return validCK(encoded) ?? validC(encoded) ?? encoded;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Decode Code 11 from one binarized scanline.
|
|
624
|
+
*
|
|
625
|
+
* @param {Uint8Array} row
|
|
626
|
+
* @param {object} [options]
|
|
627
|
+
* @param {boolean} [options.checkDigit]
|
|
628
|
+
* @returns {{format:'code11', text:string}|null}
|
|
629
|
+
*/
|
|
630
|
+
export function decodeCode11(row, options = {}) {
|
|
631
|
+
const counters = new Array(5).fill(0);
|
|
632
|
+
let start = null;
|
|
633
|
+
for (let i = 0; i < row.length; i++) {
|
|
634
|
+
if (row[i] !== 1 || (i > 0 && row[i - 1] === 1)) continue;
|
|
635
|
+
if (!recordPattern(row, i, counters)) continue;
|
|
636
|
+
if (toNarrowWidePattern(counters, 2) === CODE11_START_BITS) {
|
|
637
|
+
start = { position: i, end: i + counterTotal(counters), scale: counterTotal(counters) / 9 };
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
if (!start) return null;
|
|
642
|
+
|
|
643
|
+
let offset = start.end;
|
|
644
|
+
while (offset < row.length && row[offset] === 0) offset++;
|
|
645
|
+
let encoded = '';
|
|
646
|
+
|
|
647
|
+
for (let count = 0; count < 160 && offset < row.length; count++) {
|
|
648
|
+
if (!recordPattern(row, offset, counters)) return null;
|
|
649
|
+
const width = counterTotal(counters);
|
|
650
|
+
const stop = toNarrowWidePattern(counters, 2);
|
|
651
|
+
if (stop === CODE11_START_BITS) {
|
|
652
|
+
if (encoded.length === 0) return null;
|
|
653
|
+
const stopEnd = offset + width;
|
|
654
|
+
let nextDark = stopEnd;
|
|
655
|
+
while (nextDark < row.length && row[nextDark] === 0) nextDark++;
|
|
656
|
+
if (nextDark !== row.length && nextDark - stopEnd < Math.max(3, Math.ceil(start.scale * 3))) {
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
const text = finalizeCode11(encoded, options.checkDigit);
|
|
660
|
+
return text == null ? null : { format: 'code11', text };
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
let character = null;
|
|
664
|
+
for (const expectedWide of [1, 2]) {
|
|
665
|
+
const bits = toNarrowWidePattern(counters, expectedWide);
|
|
666
|
+
if (bits < 0) continue;
|
|
667
|
+
const candidate = CODE11_BITS[`${bits}:${expectedWide}`];
|
|
668
|
+
if (candidate !== undefined) {
|
|
669
|
+
character = candidate;
|
|
670
|
+
break;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (character == null) return null;
|
|
674
|
+
encoded += character;
|
|
675
|
+
if (encoded.length > 128) return null;
|
|
676
|
+
offset += width;
|
|
677
|
+
while (offset < row.length && row[offset] === 0) offset++;
|
|
678
|
+
}
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/** @param {string} encoded @param {boolean|undefined} requested */
|
|
683
|
+
function finalizeMSI(encoded, requested) {
|
|
684
|
+
if (requested !== true) return encoded;
|
|
685
|
+
if (encoded.length < 2) return null;
|
|
686
|
+
const body = encoded.slice(0, -1);
|
|
687
|
+
let odd = '';
|
|
688
|
+
for (let i = body.length - 1; i >= 0; i -= 2) odd = body[i] + odd;
|
|
689
|
+
const doubled = String(Number(odd) * 2);
|
|
690
|
+
let sum = 0;
|
|
691
|
+
for (const ch of doubled) sum += Number(ch);
|
|
692
|
+
for (let i = body.length - 2; i >= 0; i -= 2) sum += Number(body[i]);
|
|
693
|
+
const expected = String((10 - (sum % 10)) % 10);
|
|
694
|
+
return encoded.endsWith(expected) ? body : null;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Decode MSI/Plessey from one binarized scanline.
|
|
699
|
+
*
|
|
700
|
+
* @param {Uint8Array} row
|
|
701
|
+
* @param {object} [options]
|
|
702
|
+
* @param {boolean} [options.checkDigit]
|
|
703
|
+
* @returns {{format:'msi', text:string}|null}
|
|
704
|
+
*/
|
|
705
|
+
export function decodeMSI(row, options = {}) {
|
|
706
|
+
const start = findGuard(row, 0, [2, 1], false);
|
|
707
|
+
if (!start) return null;
|
|
708
|
+
const scale = (start.end - start.start) / 3;
|
|
709
|
+
if (!(scale >= 1)) return null;
|
|
710
|
+
|
|
711
|
+
let offset = start.end;
|
|
712
|
+
let encoded = '';
|
|
713
|
+
const bitPatterns = [
|
|
714
|
+
{ pattern: [1, 2], bit: '0' },
|
|
715
|
+
{ pattern: [2, 1], bit: '1' },
|
|
716
|
+
];
|
|
717
|
+
|
|
718
|
+
for (let digitIndex = 0; digitIndex < 80; digitIndex++) {
|
|
719
|
+
const stop = matchAt(row, offset, [1, 2, 1]);
|
|
720
|
+
if (stop && encoded.length > 0) {
|
|
721
|
+
let nextDark = stop.end;
|
|
722
|
+
while (nextDark < row.length && row[nextDark] === 0) nextDark++;
|
|
723
|
+
if (nextDark === row.length ||
|
|
724
|
+
nextDark - stop.end >= Math.max(3, Math.ceil(scale * 3))) {
|
|
725
|
+
if (encoded.length < 6 && !(options.formats && options.formats.includes('msi'))) {
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
const text = finalizeMSI(encoded, options.checkDigit);
|
|
729
|
+
return text == null ? null : { format: 'msi', text };
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
let nibble = '';
|
|
734
|
+
for (let bitIndex = 0; bitIndex < 4; bitIndex++) {
|
|
735
|
+
let matched = null;
|
|
736
|
+
for (const candidate of bitPatterns) {
|
|
737
|
+
const found = matchAt(row, offset, candidate.pattern);
|
|
738
|
+
if (found) {
|
|
739
|
+
matched = { ...candidate, end: found.end };
|
|
740
|
+
break;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
if (!matched) return null;
|
|
744
|
+
nibble += matched.bit;
|
|
745
|
+
offset = matched.end;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const digit = Number.parseInt(nibble, 2);
|
|
749
|
+
if (digit > 9) return null;
|
|
750
|
+
encoded += String(digit);
|
|
751
|
+
}
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
|
|
486
755
|
/* ------------------------------------------------------------------ *
|
|
487
756
|
* Code 128
|
|
488
757
|
* ------------------------------------------------------------------ */
|
|
@@ -555,8 +824,11 @@ function decodeCode128(row) {
|
|
|
555
824
|
: start.code === CODE128_START_B ? 'B' : 'C';
|
|
556
825
|
let shifted = null;
|
|
557
826
|
let text = '';
|
|
827
|
+
const fnc1AtStart = dataValues[0] === CODE128_FNC1;
|
|
828
|
+
const fnc1Positions = [];
|
|
558
829
|
|
|
559
|
-
for (
|
|
830
|
+
for (let dataIndex = 0; dataIndex < dataValues.length; dataIndex++) {
|
|
831
|
+
const value = dataValues[dataIndex];
|
|
560
832
|
const active = shifted || mode;
|
|
561
833
|
shifted = null;
|
|
562
834
|
|
|
@@ -564,7 +836,13 @@ function decodeCode128(row) {
|
|
|
564
836
|
if (value === CODE128_CODE_B && mode !== 'B') { mode = 'B'; continue; }
|
|
565
837
|
if (value === CODE128_CODE_C) { mode = 'C'; continue; }
|
|
566
838
|
if (value === CODE128_SHIFT) { shifted = mode === 'A' ? 'B' : 'A'; continue; }
|
|
567
|
-
if (value === CODE128_FNC1) {
|
|
839
|
+
if (value === CODE128_FNC1) {
|
|
840
|
+
if (dataIndex > 0) {
|
|
841
|
+
fnc1Positions.push(text.length);
|
|
842
|
+
text += '\x1d';
|
|
843
|
+
}
|
|
844
|
+
continue;
|
|
845
|
+
}
|
|
568
846
|
if (value >= 96 && value <= 102) { continue; } // other function characters
|
|
569
847
|
|
|
570
848
|
if (active === 'C') {
|
|
@@ -577,6 +855,16 @@ function decodeCode128(row) {
|
|
|
577
855
|
}
|
|
578
856
|
|
|
579
857
|
if (text.length === 0) return null;
|
|
858
|
+
if (fnc1AtStart) {
|
|
859
|
+
return {
|
|
860
|
+
format: 'gs1128',
|
|
861
|
+
text,
|
|
862
|
+
gs1: true,
|
|
863
|
+
symbologyIdentifier: ']C1',
|
|
864
|
+
fnc1AtStart: true,
|
|
865
|
+
fnc1Positions,
|
|
866
|
+
};
|
|
867
|
+
}
|
|
580
868
|
return { format: 'code128', text };
|
|
581
869
|
}
|
|
582
870
|
|
|
@@ -721,6 +1009,7 @@ function decodeCode93(row) {
|
|
|
721
1009
|
function decodeITF(row) {
|
|
722
1010
|
const start = findGuard(row, 0, [1, 1, 1, 1], false);
|
|
723
1011
|
if (!start) return null;
|
|
1012
|
+
const startScale = (start.end - start.start) / 4;
|
|
724
1013
|
|
|
725
1014
|
let offset = start.end;
|
|
726
1015
|
const digits = [];
|
|
@@ -766,6 +1055,10 @@ function decodeITF(row) {
|
|
|
766
1055
|
const stop = new Array(3).fill(0);
|
|
767
1056
|
if (!recordPattern(row, offset, stop)) return null;
|
|
768
1057
|
if (toNarrowWidePattern(stop, 1) !== 0b100) return null;
|
|
1058
|
+
const stopEnd = offset + counterTotal(stop);
|
|
1059
|
+
let nextDark = stopEnd;
|
|
1060
|
+
while (nextDark < row.length && row[nextDark] === 0) nextDark++;
|
|
1061
|
+
if (nextDark !== row.length && nextDark - stopEnd < Math.max(3, Math.ceil(startScale * 3))) return null;
|
|
769
1062
|
|
|
770
1063
|
return { format: 'itf', text: digits.join('') };
|
|
771
1064
|
}
|
|
@@ -840,6 +1133,9 @@ const DECODERS = [
|
|
|
840
1133
|
['ean8', decodeEAN8],
|
|
841
1134
|
['upce', decodeUPCE],
|
|
842
1135
|
['code128', decodeCode128],
|
|
1136
|
+
['code11', decodeCode11],
|
|
1137
|
+
['msi', decodeMSI],
|
|
1138
|
+
['gs1databar14', decodeDataBar14Scanline],
|
|
843
1139
|
['code39', decodeCode39],
|
|
844
1140
|
['code93', decodeCode93],
|
|
845
1141
|
['itf', decodeITF],
|
|
@@ -859,7 +1155,16 @@ const DECODERS = [
|
|
|
859
1155
|
export function decodeOneD(image, options = {}) {
|
|
860
1156
|
const { formats = null, rows = 15, tryHarder = true } = options;
|
|
861
1157
|
const enabled = formats ? new Set(formats) : null;
|
|
862
|
-
const active = DECODERS.filter(([id]) =>
|
|
1158
|
+
const active = DECODERS.filter(([id]) => {
|
|
1159
|
+
if (!enabled) return true;
|
|
1160
|
+
if (enabled.has(id)) return true;
|
|
1161
|
+
if (id === 'ean13' || id === 'ean8' || id === 'upca' || id === 'upce') {
|
|
1162
|
+
return enabled.has('ean2') || enabled.has('ean5');
|
|
1163
|
+
}
|
|
1164
|
+
if (id === 'code128') return enabled.has('gs1128');
|
|
1165
|
+
if (id === 'gs1databar14') return enabled.has('databar') || enabled.has('gs1-databar14');
|
|
1166
|
+
return false;
|
|
1167
|
+
});
|
|
863
1168
|
if (active.length === 0) return [];
|
|
864
1169
|
|
|
865
1170
|
const results = [];
|
|
@@ -890,9 +1195,23 @@ export function decodeOneD(image, options = {}) {
|
|
|
890
1195
|
result = null; // a malformed candidate is not an error
|
|
891
1196
|
}
|
|
892
1197
|
if (!result) continue;
|
|
893
|
-
if (enabled
|
|
1198
|
+
if (enabled) {
|
|
1199
|
+
const addonRequested = enabled.has('ean2') || enabled.has('ean5');
|
|
1200
|
+
const isEANBase = result.format === 'ean13' || result.format === 'ean8' ||
|
|
1201
|
+
result.format === 'upca' || result.format === 'upce';
|
|
1202
|
+
if (isEANBase && addonRequested) {
|
|
1203
|
+
if (!result.addon || !enabled.has(result.addon.format)) continue;
|
|
1204
|
+
} else if (result.format === 'gs1128') {
|
|
1205
|
+
if (!enabled.has('gs1128') && !enabled.has('code128')) continue;
|
|
1206
|
+
} else if (result.format === 'gs1databar14') {
|
|
1207
|
+
if (!enabled.has('gs1databar14') && !enabled.has('databar') && !enabled.has('gs1-databar14')) continue;
|
|
1208
|
+
} else if (!enabled.has(result.format)) {
|
|
1209
|
+
continue;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
894
1212
|
|
|
895
|
-
const
|
|
1213
|
+
const addonKey = result.addon ? `:${result.addon.format}:${result.addon.text}` : '';
|
|
1214
|
+
const key = `${result.format}:${result.text}${addonKey}`;
|
|
896
1215
|
if (seen.has(key)) continue;
|
|
897
1216
|
seen.add(key);
|
|
898
1217
|
results.push({ ...result, row: y });
|
package/src/oned/writers.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* MIT License
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) 2026 Sythos
|
|
7
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
7
8
|
*
|
|
8
9
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
10
|
* of this software and associated documentation files (the "Software"), to deal
|
|
@@ -463,6 +464,11 @@ export function encodeCode128(value, options = {}) {
|
|
|
463
464
|
if (gs1) codes.push(CODE128_FNC1);
|
|
464
465
|
|
|
465
466
|
while (i < value.length) {
|
|
467
|
+
if (gs1 && value[i] === '\x1d') {
|
|
468
|
+
codes.push(CODE128_FNC1);
|
|
469
|
+
i++;
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
466
472
|
const run = digitRun(i);
|
|
467
473
|
const atEnd = i + run === value.length;
|
|
468
474
|
const worthC = run >= 6 || (i === 0 && run >= 4) || (atEnd && run >= 4);
|
package/src/pdf417/compaction.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/pdf417/decoder.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/pdf417/detector.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/pdf417/encoder.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/pdf417/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
export { compactPdf417, compactPdf417Text, compactPdf417Bytes, compactPdf417Numeric, decodePdf417Compaction, decodePdf417CompactionDetailed } from './compaction.js';
|
|
2
7
|
export { encodePDF417 } from './encoder.js';
|
|
3
8
|
export { decodePDF417 } from './decoder.js';
|
package/src/pdf417/tables.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/qr/decoder.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/qr/detector.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/qr/encoder.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/qr/index.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/qr/tables.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/render/image-data.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/render/index.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/render/options.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/render/png.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/render/svg.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/render/webgl.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/render/webgpu.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/rmqr/decoder.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|
package/src/rmqr/detector.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
24
|
* SOFTWARE.
|
|
25
25
|
*
|
|
26
|
+
* SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net)
|
|
26
27
|
* SPDX-License-Identifier: MIT
|
|
27
28
|
*
|
|
28
29
|
* Original work. No code from any other barcode implementation.
|