@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.
Files changed (101) hide show
  1. package/AI_USAGE.md +33 -0
  2. package/LICENSE +4 -2
  3. package/NOTICE.md +10 -5
  4. package/README.md +95 -31
  5. package/bundle/sythos-barcode.esm.js +11552 -8877
  6. package/bundle/sythos-barcode.js +11469 -8877
  7. package/examples/create.html +2 -1
  8. package/examples/read.html +6 -0
  9. package/licenses/README.md +5 -0
  10. package/licenses/aztec-rune.license +76 -0
  11. package/licenses/compact-pdf417.license +76 -0
  12. package/licenses/ean-2.license +75 -0
  13. package/licenses/ean-5.license +75 -0
  14. package/licenses/gs1-databar.license +84 -0
  15. package/package.json +16 -4
  16. package/src/aztec/decoder.js +1 -0
  17. package/src/aztec/detector.js +1 -0
  18. package/src/aztec/encoder.js +1 -0
  19. package/src/aztec/high-level.js +1 -0
  20. package/src/aztec/index.js +1 -0
  21. package/src/aztec/tables.js +1 -0
  22. package/src/aztecrune/decoder.js +156 -0
  23. package/src/aztecrune/detector.js +167 -0
  24. package/src/aztecrune/encoder.js +122 -0
  25. package/src/aztecrune/index.js +50 -0
  26. package/src/aztecrune/tables.js +138 -0
  27. package/src/compactpdf417/decoder.js +129 -0
  28. package/src/compactpdf417/detector.js +140 -0
  29. package/src/compactpdf417/encoder.js +141 -0
  30. package/src/compactpdf417/index.js +22 -0
  31. package/src/compactpdf417/tables.js +174 -0
  32. package/src/core/bit-buffer.js +1 -0
  33. package/src/core/bit-matrix.js +1 -0
  34. package/src/core/errors.js +1 -0
  35. package/src/core/galois-field.js +1 -0
  36. package/src/core/index.js +1 -0
  37. package/src/core/reed-solomon.js +1 -0
  38. package/src/databar/codec.js +182 -0
  39. package/src/databar/decoder.js +216 -0
  40. package/src/databar/encoder.js +97 -0
  41. package/src/databar/gs1.js +178 -0
  42. package/src/databar/index.js +69 -0
  43. package/src/databar/patterns.js +144 -0
  44. package/src/databar/tables.js +125 -0
  45. package/src/datamatrix/decoder.js +1 -0
  46. package/src/datamatrix/detector.js +1 -0
  47. package/src/datamatrix/encoder.js +1 -0
  48. package/src/datamatrix/index.js +1 -0
  49. package/src/datamatrix/tables.js +1 -0
  50. package/src/frameqr/decoder.js +16 -15
  51. package/src/frameqr/detector.js +3 -2
  52. package/src/frameqr/encoder.js +8 -7
  53. package/src/frameqr/index.js +1 -0
  54. package/src/frameqr/tables.js +11 -10
  55. package/src/image/binarizer.js +1 -0
  56. package/src/image/grid-sampler.js +1 -0
  57. package/src/image/index.js +1 -0
  58. package/src/image/luminance.js +1 -0
  59. package/src/image/perspective.js +1 -0
  60. package/src/index.js +101 -12
  61. package/src/micropdf417/compaction.js +1 -0
  62. package/src/micropdf417/decoder.js +1 -0
  63. package/src/micropdf417/detector.js +1 -0
  64. package/src/micropdf417/encoder.js +1 -0
  65. package/src/micropdf417/error-correction.js +1 -0
  66. package/src/micropdf417/index.js +1 -0
  67. package/src/micropdf417/tables.js +1 -0
  68. package/src/microqr/decoder.js +1 -0
  69. package/src/microqr/detector.js +1 -0
  70. package/src/microqr/encoder.js +1 -0
  71. package/src/microqr/index.js +1 -0
  72. package/src/microqr/tables.js +1 -0
  73. package/src/oned/addons.js +421 -0
  74. package/src/oned/index.js +21 -3
  75. package/src/oned/patterns.js +1 -0
  76. package/src/oned/reader.js +330 -11
  77. package/src/oned/writers.js +6 -0
  78. package/src/pdf417/compaction.js +1 -0
  79. package/src/pdf417/decoder.js +1 -0
  80. package/src/pdf417/detector.js +1 -0
  81. package/src/pdf417/encoder.js +1 -0
  82. package/src/pdf417/error-correction.js +1 -0
  83. package/src/pdf417/index.js +5 -0
  84. package/src/pdf417/tables.js +1 -0
  85. package/src/qr/decoder.js +1 -0
  86. package/src/qr/detector.js +1 -0
  87. package/src/qr/encoder.js +1 -0
  88. package/src/qr/index.js +1 -0
  89. package/src/qr/tables.js +1 -0
  90. package/src/render/image-data.js +1 -0
  91. package/src/render/index.js +1 -0
  92. package/src/render/options.js +1 -0
  93. package/src/render/png.js +1 -0
  94. package/src/render/svg.js +1 -0
  95. package/src/render/webgl.js +1 -0
  96. package/src/render/webgpu.js +1 -0
  97. package/src/rmqr/decoder.js +1 -0
  98. package/src/rmqr/detector.js +1 -0
  99. package/src/rmqr/encoder.js +1 -0
  100. package/src/rmqr/index.js +1 -0
  101. package/src/rmqr/tables.js +1 -0
@@ -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
- if (!matchAt(row, offset, START_END_PATTERN)) return null;
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
- return first === 0
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
- if (!matchAt(row, offset, START_END_PATTERN)) return null;
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
- if (!matchAt(row, offset, UPCE_END_PATTERN)) return null;
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 (const value of dataValues) {
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) { continue; }
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]) => !enabled || enabled.has(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 && !enabled.has(result.format)) continue;
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 key = `${result.format}:${result.text}`;
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 });
@@ -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);
@@ -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.
@@ -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.
@@ -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.
@@ -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';
@@ -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.
@@ -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.
@@ -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.
@@ -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.
@@ -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.
@@ -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.