@sythos/js_barcode_universal 1.5.8 → 1.5.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/LICENSE +5 -4
  2. package/NOTICE.md +2 -2
  3. package/README.md +17 -13
  4. package/bundle/sythos-barcode.esm.js +11658 -11244
  5. package/bundle/sythos-barcode.js +11658 -11244
  6. package/package.json +10 -3
  7. package/src/index.d.ts +1 -1
  8. package/src/index.js +508 -516
  9. package/src/js/aztec/decoder.js +208 -199
  10. package/src/js/aztec/detector.js +153 -126
  11. package/src/js/aztec/encoder.js +172 -153
  12. package/src/js/aztec/high-level.js +106 -101
  13. package/src/js/aztec/index.js +1 -12
  14. package/src/js/aztec/tables.js +106 -120
  15. package/src/js/aztecrune/decoder.js +76 -85
  16. package/src/js/aztecrune/detector.js +107 -93
  17. package/src/js/aztecrune/encoder.js +50 -68
  18. package/src/js/aztecrune/index.js +1 -16
  19. package/src/js/aztecrune/tables.js +59 -54
  20. package/src/js/compactpdf417/decoder.js +69 -74
  21. package/src/js/compactpdf417/detector.js +74 -75
  22. package/src/js/compactpdf417/encoder.js +68 -81
  23. package/src/js/compactpdf417/index.js +1 -13
  24. package/src/js/compactpdf417/tables.js +71 -80
  25. package/src/js/core/bit-buffer.js +106 -122
  26. package/src/js/core/bit-matrix.js +196 -194
  27. package/src/js/core/errors.js +13 -15
  28. package/src/js/core/galois-field.js +119 -133
  29. package/src/js/core/index.js +2 -19
  30. package/src/js/core/reed-solomon.js +195 -204
  31. package/src/js/databar/codec.js +93 -108
  32. package/src/js/databar/decoder.js +149 -140
  33. package/src/js/databar/encoder.js +47 -55
  34. package/src/js/databar/gs1.js +122 -123
  35. package/src/js/databar/index.js +4 -36
  36. package/src/js/databar/patterns.js +81 -85
  37. package/src/js/databar/tables.js +51 -52
  38. package/src/js/datamatrix/decoder.js +216 -182
  39. package/src/js/datamatrix/detector.js +161 -132
  40. package/src/js/datamatrix/encoder.js +192 -133
  41. package/src/js/datamatrix/index.js +1 -9
  42. package/src/js/datamatrix/tables.js +68 -69
  43. package/src/js/frameqr/decoder.js +102 -125
  44. package/src/js/frameqr/detector.js +101 -94
  45. package/src/js/frameqr/encoder.js +67 -80
  46. package/src/js/frameqr/index.js +1 -10
  47. package/src/js/frameqr/tables.js +145 -163
  48. package/src/js/image/binarizer.js +146 -162
  49. package/src/js/image/grid-sampler.js +63 -79
  50. package/src/js/image/index.js +0 -2
  51. package/src/js/image/luminance.js +129 -140
  52. package/src/js/image/perspective.js +112 -149
  53. package/src/js/micropdf417/compaction.js +64 -65
  54. package/src/js/micropdf417/decoder.js +106 -109
  55. package/src/js/micropdf417/detector.js +73 -70
  56. package/src/js/micropdf417/encoder.js +129 -154
  57. package/src/js/micropdf417/error-correction.js +6 -11
  58. package/src/js/micropdf417/index.js +2 -16
  59. package/src/js/micropdf417/tables.js +112 -99
  60. package/src/js/microqr/decoder.js +177 -182
  61. package/src/js/microqr/detector.js +240 -256
  62. package/src/js/microqr/encoder.js +239 -194
  63. package/src/js/microqr/index.js +0 -2
  64. package/src/js/microqr/tables.js +208 -200
  65. package/src/js/oned/addons.js +167 -191
  66. package/src/js/oned/index.js +27 -58
  67. package/src/js/oned/patterns.js +194 -213
  68. package/src/js/oned/reader.js +1003 -984
  69. package/src/js/oned/writers.js +411 -466
  70. package/src/js/pdf417/compaction.js +315 -222
  71. package/src/js/pdf417/decoder.js +71 -36
  72. package/src/js/pdf417/detector.js +377 -361
  73. package/src/js/pdf417/encoder.js +57 -46
  74. package/src/js/pdf417/error-correction.js +5 -8
  75. package/src/js/pdf417/tables.js +248 -250
  76. package/src/js/qr/decoder.js +311 -347
  77. package/src/js/qr/detector.js +378 -395
  78. package/src/js/qr/encoder.js +514 -599
  79. package/src/js/qr/index.js +0 -2
  80. package/src/js/qr/tables.js +375 -422
  81. package/src/js/render/image-data.js +57 -62
  82. package/src/js/render/index.js +21 -23
  83. package/src/js/render/options.js +82 -90
  84. package/src/js/render/png.js +144 -169
  85. package/src/js/render/svg.js +41 -44
  86. package/src/js/render/webgl.js +103 -109
  87. package/src/js/render/webgpu.js +205 -217
  88. package/src/js/rmqr/decoder.js +161 -53
  89. package/src/js/rmqr/detector.js +73 -41
  90. package/src/js/rmqr/encoder.js +253 -104
  91. package/src/js/rmqr/index.js +1 -5
  92. package/src/js/rmqr/tables.js +108 -85
  93. package/src/ts/aztec/decoder.ts +317 -0
  94. package/src/ts/aztec/detector.ts +224 -0
  95. package/src/ts/aztec/encoder.ts +257 -0
  96. package/src/ts/aztec/high-level.ts +211 -0
  97. package/src/ts/aztec/index.ts +45 -0
  98. package/src/ts/aztec/tables.ts +210 -0
  99. package/src/ts/aztecrune/decoder.ts +155 -0
  100. package/src/ts/aztecrune/detector.ts +166 -0
  101. package/src/ts/aztecrune/encoder.ts +121 -0
  102. package/src/ts/aztecrune/index.ts +49 -0
  103. package/src/ts/aztecrune/tables.ts +137 -0
  104. package/src/ts/compactpdf417/decoder.ts +128 -0
  105. package/src/ts/compactpdf417/detector.ts +139 -0
  106. package/src/ts/compactpdf417/encoder.ts +140 -0
  107. package/src/ts/compactpdf417/index.ts +17 -0
  108. package/src/ts/compactpdf417/tables.ts +173 -0
  109. package/src/ts/core/bit-buffer.ts +174 -0
  110. package/src/ts/core/bit-matrix.ts +241 -0
  111. package/src/ts/core/errors.ts +61 -0
  112. package/src/ts/core/galois-field.ts +207 -0
  113. package/src/ts/core/index.ts +56 -0
  114. package/src/ts/core/reed-solomon.ts +327 -0
  115. package/src/ts/databar/codec.ts +181 -0
  116. package/src/ts/databar/decoder.ts +215 -0
  117. package/src/ts/databar/encoder.ts +96 -0
  118. package/src/ts/databar/gs1.ts +177 -0
  119. package/src/ts/databar/index.ts +68 -0
  120. package/src/ts/databar/patterns.ts +143 -0
  121. package/src/ts/databar/tables.ts +124 -0
  122. package/src/ts/datamatrix/decoder.ts +262 -0
  123. package/src/ts/datamatrix/detector.ts +225 -0
  124. package/src/ts/datamatrix/encoder.ts +191 -0
  125. package/src/ts/datamatrix/index.ts +42 -0
  126. package/src/ts/datamatrix/tables.ts +123 -0
  127. package/src/ts/frameqr/decoder.ts +239 -0
  128. package/src/ts/frameqr/detector.ts +192 -0
  129. package/src/ts/frameqr/encoder.ts +156 -0
  130. package/src/ts/frameqr/index.ts +42 -0
  131. package/src/ts/frameqr/tables.ts +270 -0
  132. package/src/ts/image/binarizer.ts +270 -0
  133. package/src/ts/image/grid-sampler.ts +164 -0
  134. package/src/ts/image/index.ts +40 -0
  135. package/src/ts/image/luminance.ts +196 -0
  136. package/src/ts/image/perspective.ts +195 -0
  137. package/src/ts/index.d.ts +1 -1
  138. package/src/ts/index.ts +790 -0
  139. package/src/ts/micropdf417/compaction.ts +116 -0
  140. package/src/ts/micropdf417/decoder.ts +183 -0
  141. package/src/ts/micropdf417/detector.ts +149 -0
  142. package/src/ts/micropdf417/encoder.ts +209 -0
  143. package/src/ts/micropdf417/error-correction.ts +55 -0
  144. package/src/ts/micropdf417/index.ts +49 -0
  145. package/src/ts/micropdf417/tables.ts +184 -0
  146. package/src/ts/microqr/decoder.ts +245 -0
  147. package/src/ts/microqr/detector.ts +355 -0
  148. package/src/ts/microqr/encoder.ts +269 -0
  149. package/src/ts/microqr/index.ts +36 -0
  150. package/src/ts/microqr/tables.ts +316 -0
  151. package/src/ts/oned/addons.ts +420 -0
  152. package/src/ts/oned/index.ts +106 -0
  153. package/src/ts/oned/patterns.ts +384 -0
  154. package/src/ts/oned/reader.ts +1364 -0
  155. package/src/ts/oned/writers.ts +746 -0
  156. package/src/ts/pdf417/compaction.ts +298 -0
  157. package/src/ts/pdf417/decoder.ts +75 -0
  158. package/src/ts/pdf417/detector.ts +468 -0
  159. package/src/ts/pdf417/encoder.ts +91 -0
  160. package/src/ts/pdf417/error-correction.ts +47 -0
  161. package/src/ts/pdf417/index.ts +6 -0
  162. package/src/ts/pdf417/tables.ts +317 -0
  163. package/src/ts/qr/decoder.ts +575 -0
  164. package/src/ts/qr/detector.ts +630 -0
  165. package/src/ts/qr/encoder.ts +958 -0
  166. package/src/ts/qr/index.ts +44 -0
  167. package/src/ts/qr/tables.ts +737 -0
  168. package/src/ts/render/image-data.ts +125 -0
  169. package/src/ts/render/index.ts +130 -0
  170. package/src/ts/render/options.ts +160 -0
  171. package/src/ts/render/png.ts +295 -0
  172. package/src/ts/render/svg.ts +120 -0
  173. package/src/ts/render/webgl.ts +206 -0
  174. package/src/ts/render/webgpu.ts +369 -0
  175. package/src/ts/rmqr/decoder.ts +101 -0
  176. package/src/ts/rmqr/detector.ts +90 -0
  177. package/src/ts/rmqr/encoder.ts +172 -0
  178. package/src/ts/rmqr/index.ts +37 -0
  179. package/src/ts/rmqr/tables.ts +154 -0
@@ -27,214 +27,299 @@
27
27
  *
28
28
  * Original work. No code from any other barcode implementation.
29
29
  */
30
-
31
30
  /** PDF417 high-level text, byte and numeric compaction. @module pdf417/compaction */
32
-
33
31
  import { EncodeError, FormatError } from '../core/errors.js';
34
-
35
32
  const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
36
33
  const LOWER = 'abcdefghijklmnopqrstuvwxyz ';
37
34
  const MIXED = '0123456789&\r\t,:#-.$/+%*=^';
38
35
  const PUNCT = ';<>@[\\]_`~!\r\t,:\n-.$/"|*()?{}\'';
39
-
40
36
  function packBase30(values) {
41
- const out = [];
42
- for (let i = 0; i < values.length; i += 2) out.push(values[i] * 30 + (i + 1 < values.length ? values[i + 1] : 29));
43
- return out;
37
+ const out = [];
38
+ for (let i = 0; i < values.length; i += 2)
39
+ out.push(values[i] * 30 + (i + 1 < values.length ? values[i + 1] : 29));
40
+ return out;
44
41
  }
45
-
46
42
  /** Compact a value using the PDF417 Text Compaction alphabet. */
47
43
  export function compactPdf417Text(value) {
48
- if (typeof value !== 'string') throw new EncodeError('PDF417 text: value must be a string');
49
- const values = [];
50
- let submode = 'alpha';
51
- for (const character of value) {
52
- const inAlpha = ALPHA.indexOf(character), inLower = LOWER.indexOf(character);
53
- const inMixed = MIXED.indexOf(character), inPunct = PUNCT.indexOf(character);
54
- if (submode === 'alpha') {
55
- if (inAlpha >= 0) values.push(inAlpha);
56
- else if (inLower >= 0) { values.push(27, inLower); submode = 'lower'; }
57
- else if (inMixed >= 0 || character === ' ') { values.push(28, character === ' ' ? 26 : inMixed); submode = 'mixed'; }
58
- else if (inPunct >= 0) values.push(29, inPunct);
59
- else throw new EncodeError(`PDF417 text: unsupported character ${JSON.stringify(character)}`);
60
- } else if (submode === 'lower') {
61
- if (inLower >= 0) values.push(inLower);
62
- else if (inAlpha >= 0) values.push(27, inAlpha);
63
- else if (inMixed >= 0 || character === ' ') { values.push(28, character === ' ' ? 26 : inMixed); submode = 'mixed'; }
64
- else if (inPunct >= 0) values.push(29, inPunct);
65
- else throw new EncodeError(`PDF417 text: unsupported character ${JSON.stringify(character)}`);
66
- } else {
67
- if (inMixed >= 0) values.push(inMixed);
68
- else if (character === ' ') values.push(26);
69
- else if (inAlpha >= 0) { values.push(28); submode = 'alpha'; values.push(inAlpha); }
70
- else if (inLower >= 0) { values.push(27); submode = 'lower'; values.push(inLower); }
71
- else if (inPunct >= 0) values.push(29, inPunct);
72
- else throw new EncodeError(`PDF417 text: unsupported character ${JSON.stringify(character)}`);
44
+ if (typeof value !== 'string')
45
+ throw new EncodeError('PDF417 text: value must be a string');
46
+ const values = [];
47
+ let submode = 'alpha';
48
+ for (const character of value) {
49
+ const inAlpha = ALPHA.indexOf(character), inLower = LOWER.indexOf(character);
50
+ const inMixed = MIXED.indexOf(character), inPunct = PUNCT.indexOf(character);
51
+ if (submode === 'alpha') {
52
+ if (inAlpha >= 0)
53
+ values.push(inAlpha);
54
+ else if (inLower >= 0) {
55
+ values.push(27, inLower);
56
+ submode = 'lower';
57
+ }
58
+ else if (inMixed >= 0 || character === ' ') {
59
+ values.push(28, character === ' ' ? 26 : inMixed);
60
+ submode = 'mixed';
61
+ }
62
+ else if (inPunct >= 0)
63
+ values.push(29, inPunct);
64
+ else
65
+ throw new EncodeError(`PDF417 text: unsupported character ${JSON.stringify(character)}`);
66
+ }
67
+ else if (submode === 'lower') {
68
+ if (inLower >= 0)
69
+ values.push(inLower);
70
+ else if (inAlpha >= 0)
71
+ values.push(27, inAlpha);
72
+ else if (inMixed >= 0 || character === ' ') {
73
+ values.push(28, character === ' ' ? 26 : inMixed);
74
+ submode = 'mixed';
75
+ }
76
+ else if (inPunct >= 0)
77
+ values.push(29, inPunct);
78
+ else
79
+ throw new EncodeError(`PDF417 text: unsupported character ${JSON.stringify(character)}`);
80
+ }
81
+ else {
82
+ if (inMixed >= 0)
83
+ values.push(inMixed);
84
+ else if (character === ' ')
85
+ values.push(26);
86
+ else if (inAlpha >= 0) {
87
+ values.push(28);
88
+ submode = 'alpha';
89
+ values.push(inAlpha);
90
+ }
91
+ else if (inLower >= 0) {
92
+ values.push(27);
93
+ submode = 'lower';
94
+ values.push(inLower);
95
+ }
96
+ else if (inPunct >= 0)
97
+ values.push(29, inPunct);
98
+ else
99
+ throw new EncodeError(`PDF417 text: unsupported character ${JSON.stringify(character)}`);
100
+ }
73
101
  }
74
- }
75
- return packBase30(values);
102
+ return packBase30(values);
76
103
  }
77
-
78
104
  function asBytes(value) {
79
- if (value instanceof Uint8Array) return value;
80
- if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
81
- if (typeof value === 'string') return new TextEncoder().encode(value);
82
- throw new EncodeError('PDF417 byte: value must be text or a byte array');
105
+ if (value instanceof Uint8Array)
106
+ return value;
107
+ if (ArrayBuffer.isView(value))
108
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
109
+ if (typeof value === 'string')
110
+ return new TextEncoder().encode(value);
111
+ throw new EncodeError('PDF417 byte: value must be text or a byte array');
83
112
  }
84
-
85
113
  /** Compact bytes using latch 924 for exact six-byte blocks and 901 otherwise. */
86
114
  export function compactPdf417Bytes(value) {
87
- const bytes = asBytes(value);
88
- const utf8 = typeof value === 'string' && /[^\x00-\x7f]/.test(value);
89
- const out = utf8 ? [927, 26] : [];
90
- out.push(bytes.length > 0 && bytes.length % 6 === 0 ? 924 : 901);
91
- let at = 0;
92
- while (at + 6 <= bytes.length) {
93
- let number = 0n;
94
- for (let i = 0; i < 6; i++) number = (number << 8n) | BigInt(bytes[at++]);
95
- const group = new Array(5);
96
- for (let i = 4; i >= 0; i--) { group[i] = Number(number % 900n); number /= 900n; }
97
- out.push(...group);
98
- }
99
- while (at < bytes.length) out.push(bytes[at++]);
100
- return out;
115
+ const bytes = asBytes(value);
116
+ const utf8 = typeof value === 'string' && /[^\x00-\x7f]/.test(value);
117
+ const out = utf8 ? [927, 26] : [];
118
+ out.push(bytes.length > 0 && bytes.length % 6 === 0 ? 924 : 901);
119
+ let at = 0;
120
+ while (at + 6 <= bytes.length) {
121
+ let number = 0n;
122
+ for (let i = 0; i < 6; i++)
123
+ number = (number << 8n) | BigInt(bytes[at++]);
124
+ const group = new Array(5);
125
+ for (let i = 4; i >= 0; i--) {
126
+ group[i] = Number(number % 900n);
127
+ number /= 900n;
128
+ }
129
+ out.push(...group);
130
+ }
131
+ while (at < bytes.length)
132
+ out.push(bytes[at++]);
133
+ return out;
101
134
  }
102
-
103
135
  /** Compact decimal digits using latch 902 and groups of at most 44 digits. */
104
136
  export function compactPdf417Numeric(value) {
105
- if (typeof value !== 'string' || !/^\d+$/.test(value)) throw new EncodeError('PDF417 numeric: value must contain decimal digits only');
106
- const out = [902];
107
- for (let at = 0; at < value.length; at += 44) {
108
- let number = BigInt(`1${value.slice(at, at + 44)}`);
109
- const group = [];
110
- do { group.unshift(Number(number % 900n)); number /= 900n; } while (number > 0n);
111
- out.push(...group);
112
- }
113
- return out;
137
+ if (typeof value !== 'string' || !/^\d+$/.test(value))
138
+ throw new EncodeError('PDF417 numeric: value must contain decimal digits only');
139
+ const out = [902];
140
+ for (let at = 0; at < value.length; at += 44) {
141
+ let number = BigInt(`1${value.slice(at, at + 44)}`);
142
+ const group = [];
143
+ do {
144
+ group.unshift(Number(number % 900n));
145
+ number /= 900n;
146
+ } while (number > 0n);
147
+ out.push(...group);
148
+ }
149
+ return out;
114
150
  }
115
-
116
151
  /** Compact a single value, selecting text, numeric or byte mode. */
117
152
  export function compactPdf417(value, options = {}) {
118
- const mode = options.compaction ?? 'auto';
119
- if (mode === 'text') return compactPdf417Text(value);
120
- if (mode === 'byte') return compactPdf417Bytes(value);
121
- if (mode === 'numeric') return compactPdf417Numeric(value);
122
- if (mode !== 'auto') throw new EncodeError(`PDF417: unsupported compaction mode ${JSON.stringify(mode)}`);
123
- if (typeof value === 'string' && /^\d{13,}$/.test(value)) return compactPdf417Numeric(value);
124
- if (typeof value === 'string') {
125
- try { return compactPdf417Text(value); } catch (error) { if (!(error instanceof EncodeError)) throw error; }
126
- }
127
- return compactPdf417Bytes(value);
153
+ const mode = options.compaction ?? 'auto';
154
+ if (mode === 'text')
155
+ return compactPdf417Text(value);
156
+ if (mode === 'byte')
157
+ return compactPdf417Bytes(value);
158
+ if (mode === 'numeric')
159
+ return compactPdf417Numeric(value);
160
+ if (mode !== 'auto')
161
+ throw new EncodeError(`PDF417: unsupported compaction mode ${JSON.stringify(mode)}`);
162
+ if (typeof value === 'string' && /^\d{13,}$/.test(value))
163
+ return compactPdf417Numeric(value);
164
+ if (typeof value === 'string') {
165
+ try {
166
+ return compactPdf417Text(value);
167
+ }
168
+ catch (error) {
169
+ if (!(error instanceof EncodeError))
170
+ throw error;
171
+ }
172
+ }
173
+ return compactPdf417Bytes(value);
128
174
  }
129
-
130
175
  function assertCodeword(codeword) {
131
- if (!Number.isInteger(codeword) || codeword < 0 || codeword > 928) throw new FormatError('PDF417: codeword is outside 0..928');
176
+ if (!Number.isInteger(codeword) || codeword < 0 || codeword > 928)
177
+ throw new FormatError('PDF417: codeword is outside 0..928');
132
178
  }
133
-
134
179
  function decodeUtf8(bytes, eci) {
135
- if (eci === 3) return Array.from(bytes, (byte) => String.fromCharCode(byte)).join('');
136
- if (eci !== 26) throw new FormatError(`PDF417 ECI: unsupported assignment number ${eci}`);
137
- try { return new TextDecoder('utf-8', { fatal: true }).decode(new Uint8Array(bytes)); }
138
- catch { throw new FormatError('PDF417 byte: invalid UTF-8 sequence'); }
180
+ if (eci === 3)
181
+ return Array.from(bytes, (byte) => String.fromCharCode(byte)).join('');
182
+ if (eci !== 26)
183
+ throw new FormatError(`PDF417 ECI: unsupported assignment number ${eci}`);
184
+ try {
185
+ return new TextDecoder('utf-8', { fatal: true }).decode(new Uint8Array(bytes));
186
+ }
187
+ catch {
188
+ throw new FormatError('PDF417 byte: invalid UTF-8 sequence');
189
+ }
139
190
  }
140
-
141
191
  function decodeByteSegment(codewords, at, eci, sixOnly = false) {
142
- const values = [];
143
- while (at < codewords.length && codewords[at] < 900) values.push(codewords[at++]);
144
- if (sixOnly && values.length % 5) throw new FormatError('PDF417 byte: 924 segment must contain complete six-byte groups');
145
- const bytes = [];
146
- // In 901 mode an encoder can use five terminal literal codewords. The
147
- // unambiguous groups are therefore the ones followed by another codeword;
148
- // 924 is available whenever a segment consists exclusively of six-byte groups.
149
- const groupCount = sixOnly ? values.length / 5 : Math.max(0, Math.floor((values.length - 1) / 5));
150
- for (let groupAt = 0; groupAt < groupCount * 5; groupAt += 5) {
151
- let number = 0n;
152
- for (let i = 0; i < 5; i++) number = number * 900n + BigInt(values[groupAt + i]);
153
- const group = new Uint8Array(6);
154
- for (let i = 5; i >= 0; i--) { group[i] = Number(number & 255n); number >>= 8n; }
155
- if (number !== 0n) throw new FormatError('PDF417 byte: base-900 group exceeds six bytes');
156
- bytes.push(...group);
157
- }
158
- for (let i = groupCount * 5; i < values.length; i++) {
159
- if (values[i] > 255) throw new FormatError('PDF417 byte: literal tail is outside 0..255');
160
- bytes.push(values[i]);
161
- }
162
- return { at, text: decodeUtf8(bytes, eci), bytes: Uint8Array.from(bytes) };
163
- }
164
-
165
- function decodeTextSegment(codewords, at, eci) {
166
- let mode = 'alpha';
167
- let output = '';
168
- let shift = null;
169
- let shiftedBytes = [];
170
- const bytes = [];
171
- const flushShiftedBytes = () => {
172
- if (shiftedBytes.length) {
173
- output += decodeUtf8(shiftedBytes, eci);
174
- bytes.push(...shiftedBytes);
175
- shiftedBytes = [];
192
+ const values = [];
193
+ while (at < codewords.length && codewords[at] < 900)
194
+ values.push(codewords[at++]);
195
+ if (sixOnly && values.length % 5)
196
+ throw new FormatError('PDF417 byte: 924 segment must contain complete six-byte groups');
197
+ const bytes = [];
198
+ // In 901 mode an encoder can use five terminal literal codewords. The
199
+ // unambiguous groups are therefore the ones followed by another codeword;
200
+ // 924 is available whenever a segment consists exclusively of six-byte groups.
201
+ const groupCount = sixOnly ? values.length / 5 : Math.max(0, Math.floor((values.length - 1) / 5));
202
+ for (let groupAt = 0; groupAt < groupCount * 5; groupAt += 5) {
203
+ let number = 0n;
204
+ for (let i = 0; i < 5; i++)
205
+ number = number * 900n + BigInt(values[groupAt + i]);
206
+ const group = new Uint8Array(6);
207
+ for (let i = 5; i >= 0; i--) {
208
+ group[i] = Number(number & 255n);
209
+ number >>= 8n;
210
+ }
211
+ if (number !== 0n)
212
+ throw new FormatError('PDF417 byte: base-900 group exceeds six bytes');
213
+ bytes.push(...group);
176
214
  }
177
- };
178
- const emit = (alphabet, value) => {
179
- if (value < 0 || value >= alphabet.length) throw new FormatError('PDF417 text: invalid submode value');
180
- output += alphabet[value];
181
- };
182
- const process = (value) => {
183
- if (shift) { emit(shift === 'alpha' ? ALPHA : PUNCT, value); shift = null; return; }
184
- if (mode === 'alpha') {
185
- if (value < 26) emit(ALPHA, value);
186
- else if (value === 26) output += ' ';
187
- else if (value === 27) mode = 'lower';
188
- else if (value === 28) mode = 'mixed';
189
- else if (value === 29) shift = 'punct';
190
- } else if (mode === 'lower') {
191
- if (value < 26) emit(LOWER, value);
192
- else if (value === 26) output += ' ';
193
- else if (value === 27) shift = 'alpha';
194
- else if (value === 28) mode = 'mixed';
195
- else if (value === 29) shift = 'punct';
196
- } else if (mode === 'mixed') {
197
- if (value < 25) emit(MIXED, value);
198
- else if (value === 25) mode = 'punct';
199
- else if (value === 26) output += ' ';
200
- else if (value === 27) mode = 'lower';
201
- else if (value === 28) mode = 'alpha';
202
- else if (value === 29) shift = 'punct';
203
- } else {
204
- if (value < 29) emit(PUNCT, value);
205
- else if (value === 29) mode = 'alpha';
215
+ for (let i = groupCount * 5; i < values.length; i++) {
216
+ if (values[i] > 255)
217
+ throw new FormatError('PDF417 byte: literal tail is outside 0..255');
218
+ bytes.push(values[i]);
206
219
  }
207
- };
208
- while (at < codewords.length) {
209
- const codeword = codewords[at];
210
- if (codeword >= 900 && codeword !== 913) break;
211
- at++;
212
- if (codeword === 913) {
213
- if (at >= codewords.length || codewords[at] > 255) throw new FormatError('PDF417 text: invalid byte shift');
214
- shiftedBytes.push(codewords[at++]);
215
- continue;
220
+ return { at, text: decodeUtf8(bytes, eci), bytes: Uint8Array.from(bytes) };
221
+ }
222
+ function decodeTextSegment(codewords, at, eci) {
223
+ let mode = 'alpha';
224
+ let output = '';
225
+ let shift = null;
226
+ let shiftedBytes = [];
227
+ const bytes = [];
228
+ const flushShiftedBytes = () => {
229
+ if (shiftedBytes.length) {
230
+ output += decodeUtf8(shiftedBytes, eci);
231
+ bytes.push(...shiftedBytes);
232
+ shiftedBytes = [];
233
+ }
234
+ };
235
+ const emit = (alphabet, value) => {
236
+ if (value < 0 || value >= alphabet.length)
237
+ throw new FormatError('PDF417 text: invalid submode value');
238
+ output += alphabet[value];
239
+ };
240
+ const process = (value) => {
241
+ if (shift) {
242
+ emit(shift === 'alpha' ? ALPHA : PUNCT, value);
243
+ shift = null;
244
+ return;
245
+ }
246
+ if (mode === 'alpha') {
247
+ if (value < 26)
248
+ emit(ALPHA, value);
249
+ else if (value === 26)
250
+ output += ' ';
251
+ else if (value === 27)
252
+ mode = 'lower';
253
+ else if (value === 28)
254
+ mode = 'mixed';
255
+ else if (value === 29)
256
+ shift = 'punct';
257
+ }
258
+ else if (mode === 'lower') {
259
+ if (value < 26)
260
+ emit(LOWER, value);
261
+ else if (value === 26)
262
+ output += ' ';
263
+ else if (value === 27)
264
+ shift = 'alpha';
265
+ else if (value === 28)
266
+ mode = 'mixed';
267
+ else if (value === 29)
268
+ shift = 'punct';
269
+ }
270
+ else if (mode === 'mixed') {
271
+ if (value < 25)
272
+ emit(MIXED, value);
273
+ else if (value === 25)
274
+ mode = 'punct';
275
+ else if (value === 26)
276
+ output += ' ';
277
+ else if (value === 27)
278
+ mode = 'lower';
279
+ else if (value === 28)
280
+ mode = 'alpha';
281
+ else if (value === 29)
282
+ shift = 'punct';
283
+ }
284
+ else {
285
+ if (value < 29)
286
+ emit(PUNCT, value);
287
+ else if (value === 29)
288
+ mode = 'alpha';
289
+ }
290
+ };
291
+ while (at < codewords.length) {
292
+ const codeword = codewords[at];
293
+ if (codeword >= 900 && codeword !== 913)
294
+ break;
295
+ at++;
296
+ if (codeword === 913) {
297
+ if (at >= codewords.length || codewords[at] > 255)
298
+ throw new FormatError('PDF417 text: invalid byte shift');
299
+ shiftedBytes.push(codewords[at++]);
300
+ continue;
301
+ }
302
+ flushShiftedBytes();
303
+ process(Math.floor(codeword / 30));
304
+ process(codeword % 30);
216
305
  }
217
306
  flushShiftedBytes();
218
- process(Math.floor(codeword / 30));
219
- process(codeword % 30);
220
- }
221
- flushShiftedBytes();
222
- return { at, text: output, bytes: Uint8Array.from(bytes) };
307
+ return { at, text: output, bytes: Uint8Array.from(bytes) };
223
308
  }
224
-
225
309
  function decodeNumericSegment(codewords, at) {
226
- let output = '';
227
- while (at < codewords.length && codewords[at] < 900) {
228
- const end = Math.min(at + 15, codewords.length);
229
- let number = 0n;
230
- for (; at < end && codewords[at] < 900; at++) number = number * 900n + BigInt(codewords[at]);
231
- const decimal = number.toString();
232
- if (!decimal.startsWith('1')) throw new FormatError('PDF417 numeric: missing leading sentinel');
233
- output += decimal.slice(1);
234
- }
235
- return { at, text: output, bytes: new Uint8Array(0) };
310
+ let output = '';
311
+ while (at < codewords.length && codewords[at] < 900) {
312
+ const end = Math.min(at + 15, codewords.length);
313
+ let number = 0n;
314
+ for (; at < end && codewords[at] < 900; at++)
315
+ number = number * 900n + BigInt(codewords[at]);
316
+ const decimal = number.toString();
317
+ if (!decimal.startsWith('1'))
318
+ throw new FormatError('PDF417 numeric: missing leading sentinel');
319
+ output += decimal.slice(1);
320
+ }
321
+ return { at, text: output, bytes: new Uint8Array(0) };
236
322
  }
237
-
238
323
  /**
239
324
  * Decode PDF417 compaction while preserving raw Byte Compaction and byte-shift
240
325
  * payloads. Text and Numeric Compaction do not manufacture bytes: their text
@@ -242,57 +327,65 @@ function decodeNumericSegment(codewords, at) {
242
327
  * modes that encode octets explicitly.
243
328
  */
244
329
  export function decodePdf417CompactionDetailed(codewords) {
245
- if (!Array.isArray(codewords) && !ArrayBuffer.isView(codewords)) throw new FormatError('PDF417: codewords must be an array');
246
- for (const codeword of codewords) assertCodeword(codeword);
247
- let at = 0;
248
- // ISO/IEC 8859-1 is the PDF417 default; UTF-8 is selected explicitly with ECI 26.
249
- let eci = 3;
250
- let output = '';
251
- const bytes = [];
252
- const segments = [];
253
- while (at < codewords.length) {
254
- const codeword = codewords[at];
255
- if (codeword < 900 || codeword === 900 || codeword === 913) {
256
- const start = at;
257
- const latch = codeword === 900 ? codeword : null;
258
- if (latch !== null) at++;
259
- const segment = decodeTextSegment(codewords, at, eci);
260
- at = segment.at;
261
- output += segment.text;
262
- bytes.push(...segment.bytes);
263
- if (segment.text.length || segment.bytes.length) segments.push({ mode: 'text', text: segment.text, bytes: segment.bytes, eci, latch, codewordStart: start, codewordEnd: at });
264
- continue;
265
- }
266
- const start = at;
267
- at++;
268
- if (codeword === 901) {
269
- const segment = decodeByteSegment(codewords, at, eci);
270
- at = segment.at;
271
- output += segment.text;
272
- bytes.push(...segment.bytes);
273
- segments.push({ mode: 'byte', text: segment.text, bytes: segment.bytes, eci, latch: codeword, codewordStart: start, codewordEnd: at });
274
- } else if (codeword === 924) {
275
- const segment = decodeByteSegment(codewords, at, eci, true);
276
- at = segment.at;
277
- output += segment.text;
278
- bytes.push(...segment.bytes);
279
- segments.push({ mode: 'byte', text: segment.text, bytes: segment.bytes, eci, latch: codeword, codewordStart: start, codewordEnd: at });
280
- } else if (codeword === 902) {
281
- const segment = decodeNumericSegment(codewords, at);
282
- at = segment.at;
283
- output += segment.text;
284
- segments.push({ mode: 'numeric', text: segment.text, bytes: segment.bytes, eci, latch: codeword, codewordStart: start, codewordEnd: at });
285
- } else if (codeword === 927) {
286
- if (at >= codewords.length || codewords[at] > 899) throw new FormatError('PDF417 ECI: missing assignment number');
287
- eci = codewords[at++];
288
- } else {
289
- throw new FormatError(`PDF417: unsupported compaction codeword ${codeword}`);
330
+ if (!Array.isArray(codewords) && !ArrayBuffer.isView(codewords))
331
+ throw new FormatError('PDF417: codewords must be an array');
332
+ for (const codeword of codewords)
333
+ assertCodeword(codeword);
334
+ let at = 0;
335
+ // ISO/IEC 8859-1 is the PDF417 default; UTF-8 is selected explicitly with ECI 26.
336
+ let eci = 3;
337
+ let output = '';
338
+ const bytes = [];
339
+ const segments = [];
340
+ while (at < codewords.length) {
341
+ const codeword = codewords[at];
342
+ if (codeword < 900 || codeword === 900 || codeword === 913) {
343
+ const start = at;
344
+ const latch = codeword === 900 ? codeword : null;
345
+ if (latch !== null)
346
+ at++;
347
+ const segment = decodeTextSegment(codewords, at, eci);
348
+ at = segment.at;
349
+ output += segment.text;
350
+ bytes.push(...segment.bytes);
351
+ if (segment.text.length || segment.bytes.length)
352
+ segments.push({ mode: 'text', text: segment.text, bytes: segment.bytes, eci, latch, codewordStart: start, codewordEnd: at });
353
+ continue;
354
+ }
355
+ const start = at;
356
+ at++;
357
+ if (codeword === 901) {
358
+ const segment = decodeByteSegment(codewords, at, eci);
359
+ at = segment.at;
360
+ output += segment.text;
361
+ bytes.push(...segment.bytes);
362
+ segments.push({ mode: 'byte', text: segment.text, bytes: segment.bytes, eci, latch: codeword, codewordStart: start, codewordEnd: at });
363
+ }
364
+ else if (codeword === 924) {
365
+ const segment = decodeByteSegment(codewords, at, eci, true);
366
+ at = segment.at;
367
+ output += segment.text;
368
+ bytes.push(...segment.bytes);
369
+ segments.push({ mode: 'byte', text: segment.text, bytes: segment.bytes, eci, latch: codeword, codewordStart: start, codewordEnd: at });
370
+ }
371
+ else if (codeword === 902) {
372
+ const segment = decodeNumericSegment(codewords, at);
373
+ at = segment.at;
374
+ output += segment.text;
375
+ segments.push({ mode: 'numeric', text: segment.text, bytes: segment.bytes, eci, latch: codeword, codewordStart: start, codewordEnd: at });
376
+ }
377
+ else if (codeword === 927) {
378
+ if (at >= codewords.length || codewords[at] > 899)
379
+ throw new FormatError('PDF417 ECI: missing assignment number');
380
+ eci = codewords[at++];
381
+ }
382
+ else {
383
+ throw new FormatError(`PDF417: unsupported compaction codeword ${codeword}`);
384
+ }
290
385
  }
291
- }
292
- return { text: output, bytes: Uint8Array.from(bytes), segments };
386
+ return { text: output, bytes: Uint8Array.from(bytes), segments };
293
387
  }
294
-
295
388
  /** Decode PDF417 Text, Byte, Numeric and UTF-8 ECI compaction segments in source order. */
296
389
  export function decodePdf417Compaction(codewords) {
297
- return decodePdf417CompactionDetailed(codewords).text;
390
+ return decodePdf417CompactionDetailed(codewords).text;
298
391
  }