@sythos/js_barcode_universal 1.5.8 → 1.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/LICENSE +5 -4
  2. package/NOTICE.md +2 -2
  3. package/README.md +61 -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,7 +27,6 @@
27
27
  *
28
28
  * Original work. No code from any other barcode implementation.
29
29
  */
30
-
31
30
  /**
32
31
  * Decoder for a sampled Aztec symbol.
33
32
  *
@@ -44,40 +43,32 @@
44
43
  *
45
44
  * @module aztec/decoder
46
45
  */
47
-
48
46
  import { FormatError } from '../core/errors.js';
49
47
  import { rsDecode } from '../core/reed-solomon.js';
50
- import {
51
- aztecLayer as aztecSymbolForLayers,
52
- wordSizeForLayers as aztecWordSizeForLayers,
53
- fieldForLayers as aztecFieldForLayers,
54
- fieldForWordSize,
55
- aztecSymbolSize as aztecMatrixSize,
56
- } from './tables.js';
57
-
48
+ import { aztecLayer as aztecSymbolForLayers, wordSizeForLayers as aztecWordSizeForLayers, fieldForLayers as aztecFieldForLayers, fieldForWordSize, aztecSymbolSize as aztecMatrixSize, } from './tables.js';
58
49
  const UPPER = ['CTRL_PS', ' ', ...'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'CTRL_LL', 'CTRL_ML', 'CTRL_DL', 'CTRL_BS'];
59
50
  const LOWER = ['CTRL_PS', ' ', ...'abcdefghijklmnopqrstuvwxyz', 'CTRL_US', 'CTRL_ML', 'CTRL_DL', 'CTRL_BS'];
60
51
  const MIXED = [
61
- 'CTRL_PS', ' ', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\b', '\t', '\n', '\x0b', '\f', '\r', '\x1b',
62
- '\x1c', '\x1d', '\x1e', '\x1f', '@', '\\', '^', '_', '`', '|', '~', '\x7f', 'CTRL_LL', 'CTRL_UL', 'CTRL_PL', 'CTRL_BS',
52
+ 'CTRL_PS', ' ', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\b', '\t', '\n', '\x0b', '\f', '\r', '\x1b',
53
+ '\x1c', '\x1d', '\x1e', '\x1f', '@', '\\', '^', '_', '`', '|', '~', '\x7f', 'CTRL_LL', 'CTRL_UL', 'CTRL_PL', 'CTRL_BS',
63
54
  ];
64
55
  const PUNCT = ['FLG(n)', '\r', '\r\n', '. ', ', ', ': ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}', 'CTRL_UL'];
65
56
  const DIGIT = ['CTRL_PS', ' ', ...'0123456789', ',', '.', 'CTRL_UL'];
66
57
  const TABLES = { UPPER, LOWER, MIXED, PUNCT, DIGIT };
67
-
68
58
  /** @param {boolean[]} bits @param {number} offset @param {number} count */
69
59
  function readBits(bits, offset, count) {
70
- if (offset + count > bits.length) throw new FormatError('Aztec: truncated high-level stream');
71
- let value = 0;
72
- for (let i = 0; i < count; i++) value = (value << 1) | (bits[offset + i] ? 1 : 0);
73
- return value;
60
+ if (offset + count > bits.length)
61
+ throw new FormatError('Aztec: truncated high-level stream');
62
+ let value = 0;
63
+ for (let i = 0; i < count; i++)
64
+ value = (value << 1) | (bits[offset + i] ? 1 : 0);
65
+ return value;
74
66
  }
75
-
76
67
  /** @param {number} value @param {number} count @param {boolean[]} out */
77
68
  function appendBits(value, count, out) {
78
- for (let i = count - 1; i >= 0; i--) out.push(((value >>> i) & 1) !== 0);
69
+ for (let i = count - 1; i >= 0; i--)
70
+ out.push(((value >>> i) & 1) !== 0);
79
71
  }
80
-
81
72
  /**
82
73
  * Decode an Aztec high-level bit stream to its exact byte payload.
83
74
  *
@@ -89,91 +80,98 @@ function appendBits(value, count, out) {
89
80
  * @returns {Uint8Array}
90
81
  */
91
82
  export function decodeHighLevelBits(bits) {
92
- const output = [];
93
- let latch = 'UPPER';
94
- let shift = 'UPPER';
95
- let offset = 0;
96
-
97
- while (offset < bits.length) {
98
- if (shift === 'BINARY') {
99
- if (offset + 5 > bits.length) break; // legal trailing pad
100
- let length = readBits(bits, offset, 5);
101
- offset += 5;
102
- if (length === 0) {
103
- if (offset + 11 > bits.length) throw new FormatError('Aztec: truncated Binary Shift length');
104
- length = readBits(bits, offset, 11) + 31;
105
- offset += 11;
106
- }
107
- if (offset + length * 8 > bits.length) throw new FormatError('Aztec: truncated Binary Shift data');
108
- for (let i = 0; i < length; i++) {
109
- output.push(readBits(bits, offset, 8));
110
- offset += 8;
111
- }
112
- shift = latch;
113
- continue;
114
- }
115
-
116
- const size = shift === 'DIGIT' ? 4 : 5;
117
- if (offset + size > bits.length) break; // trailing pad after unstuffing
118
- const code = readBits(bits, offset, size);
119
- offset += size;
120
- const table = TABLES[shift];
121
- const token = table[code];
122
- if (token === undefined) throw new FormatError(`Aztec: invalid ${shift} code ${code}`);
123
-
124
- if (token === 'FLG(n)') {
125
- if (offset + 3 > bits.length) throw new FormatError('Aztec: truncated FLG(n)');
126
- const count = readBits(bits, offset, 3);
127
- offset += 3;
128
- if (count === 0) output.push(0x1d); // FNC1 / GS
129
- else if (count <= 6) {
130
- // ECI assignment number, encoded as count decimal digits. It changes
131
- // interpretation, not the wire bytes, so consume it without output.
132
- for (let i = 0; i < count; i++) {
133
- if (offset + 4 > bits.length) throw new FormatError('Aztec: truncated ECI');
134
- const digit = readBits(bits, offset, 4);
135
- offset += 4;
136
- if (digit < 2 || digit > 11) throw new FormatError('Aztec: invalid ECI digit');
83
+ const output = [];
84
+ let latch = 'UPPER';
85
+ let shift = 'UPPER';
86
+ let offset = 0;
87
+ while (offset < bits.length) {
88
+ if (shift === 'BINARY') {
89
+ if (offset + 5 > bits.length)
90
+ break; // legal trailing pad
91
+ let length = readBits(bits, offset, 5);
92
+ offset += 5;
93
+ if (length === 0) {
94
+ if (offset + 11 > bits.length)
95
+ throw new FormatError('Aztec: truncated Binary Shift length');
96
+ length = readBits(bits, offset, 11) + 31;
97
+ offset += 11;
98
+ }
99
+ if (offset + length * 8 > bits.length)
100
+ throw new FormatError('Aztec: truncated Binary Shift data');
101
+ for (let i = 0; i < length; i++) {
102
+ output.push(readBits(bits, offset, 8));
103
+ offset += 8;
104
+ }
105
+ shift = latch;
106
+ continue;
137
107
  }
138
- } else {
139
- throw new FormatError(`Aztec: unsupported FLG(${count})`);
140
- }
141
- shift = latch;
142
- continue;
143
- }
144
-
145
- if (token.startsWith('CTRL_')) {
146
- const targetCode = token.slice(5, -1);
147
- const latchMode = token.endsWith('L');
148
- const target = ({ P: 'PUNCT', L: 'LOWER', M: 'MIXED', D: 'DIGIT', U: 'UPPER', B: 'BINARY' })[targetCode];
149
- if (!target) throw new FormatError(`Aztec: invalid control ${token}`);
150
- shift = target;
151
- if (latchMode) latch = shift;
152
- continue;
108
+ const size = shift === 'DIGIT' ? 4 : 5;
109
+ if (offset + size > bits.length)
110
+ break; // trailing pad after unstuffing
111
+ const code = readBits(bits, offset, size);
112
+ offset += size;
113
+ const table = TABLES[shift];
114
+ const token = table[code];
115
+ if (token === undefined)
116
+ throw new FormatError(`Aztec: invalid ${shift} code ${code}`);
117
+ if (token === 'FLG(n)') {
118
+ if (offset + 3 > bits.length)
119
+ throw new FormatError('Aztec: truncated FLG(n)');
120
+ const count = readBits(bits, offset, 3);
121
+ offset += 3;
122
+ if (count === 0)
123
+ output.push(0x1d); // FNC1 / GS
124
+ else if (count <= 6) {
125
+ // ECI assignment number, encoded as count decimal digits. It changes
126
+ // interpretation, not the wire bytes, so consume it without output.
127
+ for (let i = 0; i < count; i++) {
128
+ if (offset + 4 > bits.length)
129
+ throw new FormatError('Aztec: truncated ECI');
130
+ const digit = readBits(bits, offset, 4);
131
+ offset += 4;
132
+ if (digit < 2 || digit > 11)
133
+ throw new FormatError('Aztec: invalid ECI digit');
134
+ }
135
+ }
136
+ else {
137
+ throw new FormatError(`Aztec: unsupported FLG(${count})`);
138
+ }
139
+ shift = latch;
140
+ continue;
141
+ }
142
+ if (token.startsWith('CTRL_')) {
143
+ const targetCode = token.slice(5, -1);
144
+ const latchMode = token.endsWith('L');
145
+ const target = ({ P: 'PUNCT', L: 'LOWER', M: 'MIXED', D: 'DIGIT', U: 'UPPER', B: 'BINARY' })[targetCode];
146
+ if (!target)
147
+ throw new FormatError(`Aztec: invalid control ${token}`);
148
+ shift = target;
149
+ if (latchMode)
150
+ latch = shift;
151
+ continue;
152
+ }
153
+ for (let i = 0; i < token.length; i++)
154
+ output.push(token.charCodeAt(i));
155
+ shift = latch;
153
156
  }
154
-
155
- for (let i = 0; i < token.length; i++) output.push(token.charCodeAt(i));
156
- shift = latch;
157
- }
158
- return Uint8Array.from(output);
157
+ return Uint8Array.from(output);
159
158
  }
160
-
161
159
  /** @param {boolean} compact @param {number} layers */
162
160
  function alignmentMap(compact, layers) {
163
- const baseSize = (compact ? 11 : 14) + layers * 4;
164
- if (compact) return Array.from({ length: baseSize }, (_, i) => i);
165
- const size = aztecMatrixSize(layers, false);
166
- const map = new Array(baseSize);
167
- const baseCenter = baseSize >> 1;
168
- const center = size >> 1;
169
- for (let i = 0; i < baseCenter; i++) {
170
- const offset = i + Math.floor(i / 15);
171
- map[baseCenter - i - 1] = center - offset - 1;
172
- map[baseCenter + i] = center + offset + 1;
173
- }
174
- return map;
161
+ const baseSize = (compact ? 11 : 14) + layers * 4;
162
+ if (compact)
163
+ return Array.from({ length: baseSize }, (_, i) => i);
164
+ const size = aztecMatrixSize(layers, false);
165
+ const map = new Array(baseSize);
166
+ const baseCenter = baseSize >> 1;
167
+ const center = size >> 1;
168
+ for (let i = 0; i < baseCenter; i++) {
169
+ const offset = i + Math.floor(i / 15);
170
+ map[baseCenter - i - 1] = center - offset - 1;
171
+ map[baseCenter + i] = center + offset + 1;
172
+ }
173
+ return map;
175
174
  }
176
-
177
175
  /**
178
176
  * Read the four sides of the parameter message. The order mirrors the
179
177
  * clockwise write order and is independent of the data spiral.
@@ -183,42 +181,42 @@ function alignmentMap(compact, layers) {
183
181
  * @returns {boolean[]}
184
182
  */
185
183
  function readModeBits(matrix, compact) {
186
- const center = matrix.width >> 1;
187
- const side = compact ? 7 : 10;
188
- const offset = compact ? 5 : 7;
189
- // Full symbols skip the reference grid line through the bull's-eye. This
190
- // exact sequence is also used by drawModeMessage() in encoder.js.
191
- const positions = Array.from(
192
- { length: side },
193
- (_, i) => compact ? center - 3 + i : center - 5 + i + Math.floor(i / 5),
194
- );
195
- const bits = [];
196
- for (let i = 0; i < side; i++) bits.push(matrix.get(positions[i], center - offset));
197
- for (let i = 0; i < side; i++) bits.push(matrix.get(center + offset, positions[i]));
198
- for (let i = 0; i < side; i++) bits.push(matrix.get(positions[side - 1 - i], center + offset));
199
- for (let i = 0; i < side; i++) bits.push(matrix.get(center - offset, positions[side - 1 - i]));
200
- return bits;
184
+ const center = matrix.width >> 1;
185
+ const side = compact ? 7 : 10;
186
+ const offset = compact ? 5 : 7;
187
+ // Full symbols skip the reference grid line through the bull's-eye. This
188
+ // exact sequence is also used by drawModeMessage() in encoder.js.
189
+ const positions = Array.from({ length: side }, (_, i) => compact ? center - 3 + i : center - 5 + i + Math.floor(i / 5));
190
+ const bits = [];
191
+ for (let i = 0; i < side; i++)
192
+ bits.push(matrix.get(positions[i], center - offset));
193
+ for (let i = 0; i < side; i++)
194
+ bits.push(matrix.get(center + offset, positions[i]));
195
+ for (let i = 0; i < side; i++)
196
+ bits.push(matrix.get(positions[side - 1 - i], center + offset));
197
+ for (let i = 0; i < side; i++)
198
+ bits.push(matrix.get(center - offset, positions[side - 1 - i]));
199
+ return bits;
201
200
  }
202
-
203
201
  /** @param {boolean[]} bits @param {boolean} compact */
204
202
  function decodeModeMessage(bits, compact) {
205
- const total = compact ? 7 : 10;
206
- const dataWords = compact ? 2 : 4;
207
- const words = new Array(total);
208
- for (let i = 0; i < total; i++) words[i] = readBits(bits, i * 4, 4);
209
- const corrections = rsDecode(words, total - dataWords, fieldForWordSize(4), 1);
210
- let data = 0;
211
- for (let i = 0; i < dataWords; i++) data = (data << 4) | words[i];
212
- const layers = compact ? (data >>> 6) + 1 : (data >>> 11) + 1;
213
- const dataCodewords = compact ? (data & 0x3f) + 1 : (data & 0x7ff) + 1;
214
- return { layers, dataCodewords, corrections };
203
+ const total = compact ? 7 : 10;
204
+ const dataWords = compact ? 2 : 4;
205
+ const words = new Array(total);
206
+ for (let i = 0; i < total; i++)
207
+ words[i] = readBits(bits, i * 4, 4);
208
+ const corrections = rsDecode(words, total - dataWords, fieldForWordSize(4), 1);
209
+ let data = 0;
210
+ for (let i = 0; i < dataWords; i++)
211
+ data = (data << 4) | words[i];
212
+ const layers = compact ? (data >>> 6) + 1 : (data >>> 11) + 1;
213
+ const dataCodewords = compact ? (data & 0x3f) + 1 : (data & 0x7ff) + 1;
214
+ return { layers, dataCodewords, corrections };
215
215
  }
216
-
217
216
  /** @param {boolean} compact @param {number} layers */
218
217
  function totalBitsInLayers(compact, layers) {
219
- return ((compact ? 88 : 112) + 16 * layers) * layers;
218
+ return ((compact ? 88 : 112) + 16 * layers) * layers;
220
219
  }
221
-
222
220
  /**
223
221
  * Extract raw, stuffed codeword bits in logical ring order.
224
222
  * @param {import('../core/bit-matrix.js').BitMatrix} matrix
@@ -226,55 +224,61 @@ function totalBitsInLayers(compact, layers) {
226
224
  * @returns {boolean[]}
227
225
  */
228
226
  function extractBits(matrix, compact, layers) {
229
- const baseSize = (compact ? 11 : 14) + layers * 4;
230
- const map = alignmentMap(compact, layers);
231
- const raw = new Array(totalBitsInLayers(compact, layers));
232
- let offset = 0;
233
- for (let layer = 0; layer < layers; layer++) {
234
- const rowSize = (layers - layer) * 4 + (compact ? 9 : 12);
235
- for (let j = 0; j < rowSize; j++) {
236
- const col = j * 2;
237
- for (let k = 0; k < 2; k++) {
238
- raw[offset + col + k] = matrix.get(map[layer * 2 + k], map[layer * 2 + j]);
239
- raw[offset + rowSize * 2 + col + k] = matrix.get(map[layer * 2 + j], map[baseSize - 1 - layer * 2 - k]);
240
- raw[offset + rowSize * 4 + col + k] = matrix.get(map[baseSize - 1 - layer * 2 - k], map[baseSize - 1 - layer * 2 - j]);
241
- raw[offset + rowSize * 6 + col + k] = matrix.get(map[baseSize - 1 - layer * 2 - j], map[layer * 2 + k]);
242
- }
227
+ const baseSize = (compact ? 11 : 14) + layers * 4;
228
+ const map = alignmentMap(compact, layers);
229
+ const raw = new Array(totalBitsInLayers(compact, layers));
230
+ let offset = 0;
231
+ for (let layer = 0; layer < layers; layer++) {
232
+ const rowSize = (layers - layer) * 4 + (compact ? 9 : 12);
233
+ for (let j = 0; j < rowSize; j++) {
234
+ const col = j * 2;
235
+ for (let k = 0; k < 2; k++) {
236
+ raw[offset + col + k] = matrix.get(map[layer * 2 + k], map[layer * 2 + j]);
237
+ raw[offset + rowSize * 2 + col + k] = matrix.get(map[layer * 2 + j], map[baseSize - 1 - layer * 2 - k]);
238
+ raw[offset + rowSize * 4 + col + k] = matrix.get(map[baseSize - 1 - layer * 2 - k], map[baseSize - 1 - layer * 2 - j]);
239
+ raw[offset + rowSize * 6 + col + k] = matrix.get(map[baseSize - 1 - layer * 2 - j], map[layer * 2 + k]);
240
+ }
241
+ }
242
+ offset += rowSize * 8;
243
243
  }
244
- offset += rowSize * 8;
245
- }
246
- return raw;
244
+ return raw;
247
245
  }
248
-
249
246
  /** @param {boolean[]} raw @param {number} layers @param {number} dataCodewords */
250
247
  function correctAndUnstuff(raw, layers, dataCodewords) {
251
- const wordSize = aztecWordSizeForLayers(layers);
252
- const totalWords = Math.floor(raw.length / wordSize);
253
- if (dataCodewords <= 0 || dataCodewords > totalWords) throw new FormatError('Aztec: invalid data word count');
254
- const start = raw.length % wordSize;
255
- const words = new Array(totalWords);
256
- for (let i = 0; i < totalWords; i++) words[i] = readBits(raw, start + i * wordSize, wordSize);
257
- const corrections = rsDecode(words, totalWords - dataCodewords, aztecFieldForLayers(layers), 1);
258
- const mask = (1 << wordSize) - 1;
259
- const corrected = [];
260
- for (let i = 0; i < dataCodewords; i++) {
261
- const word = words[i];
262
- if (word === 0 || word === mask) throw new FormatError('Aztec: invalid stuffed codeword');
263
- if (word === 1 || word === mask - 1) {
264
- for (let j = 0; j < wordSize - 1; j++) corrected.push(word === mask - 1);
265
- } else {
266
- appendBits(word, wordSize, corrected);
248
+ const wordSize = aztecWordSizeForLayers(layers);
249
+ const totalWords = Math.floor(raw.length / wordSize);
250
+ if (dataCodewords <= 0 || dataCodewords > totalWords)
251
+ throw new FormatError('Aztec: invalid data word count');
252
+ const start = raw.length % wordSize;
253
+ const words = new Array(totalWords);
254
+ for (let i = 0; i < totalWords; i++)
255
+ words[i] = readBits(raw, start + i * wordSize, wordSize);
256
+ const corrections = rsDecode(words, totalWords - dataCodewords, aztecFieldForLayers(layers), 1);
257
+ const mask = (1 << wordSize) - 1;
258
+ const corrected = [];
259
+ for (let i = 0; i < dataCodewords; i++) {
260
+ const word = words[i];
261
+ if (word === 0 || word === mask)
262
+ throw new FormatError('Aztec: invalid stuffed codeword');
263
+ if (word === 1 || word === mask - 1) {
264
+ for (let j = 0; j < wordSize - 1; j++)
265
+ corrected.push(word === mask - 1);
266
+ }
267
+ else {
268
+ appendBits(word, wordSize, corrected);
269
+ }
267
270
  }
268
- }
269
- return { bits: corrected, corrections };
271
+ return { bits: corrected, corrections };
270
272
  }
271
-
272
273
  /** @param {Uint8Array} bytes */
273
274
  function bytesToText(bytes) {
274
- try { return new TextDecoder('utf-8', { fatal: true }).decode(bytes); }
275
- catch { return new TextDecoder('latin1').decode(bytes); }
275
+ try {
276
+ return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
277
+ }
278
+ catch {
279
+ return new TextDecoder('latin1').decode(bytes);
280
+ }
276
281
  }
277
-
278
282
  /**
279
283
  * Decode a square Aztec symbol with one bit per module and no quiet zone.
280
284
  * The matrix must already be oriented with the mode message at the top.
@@ -283,35 +287,40 @@ function bytesToText(bytes) {
283
287
  * @returns {{text: string, bytes: Uint8Array, compact: boolean, layers: number, corrections: number, eccPercent: number}}
284
288
  */
285
289
  export function decodeAztec(matrix) {
286
- if (!matrix || matrix.width !== matrix.height) throw new FormatError('Aztec: expected a square BitMatrix');
287
- let compact;
288
- let mode;
289
- // Compact and full dimensions are disjoint; trying both also makes malformed
290
- // candidate handling deterministic for the future image detector.
291
- for (const candidate of [true, false]) {
292
- try {
293
- const value = decodeModeMessage(readModeBits(matrix, candidate), candidate);
294
- if (value.layers < 1 || value.layers > (candidate ? 4 : 32)) continue;
295
- if (aztecMatrixSize(value.layers, candidate) !== matrix.width) continue;
296
- compact = candidate;
297
- mode = value;
298
- break;
299
- } catch { /* Try the other family. */ }
300
- }
301
- if (compact === undefined || !mode) throw new FormatError('Aztec: invalid mode message or dimensions');
302
- // Ensure the declared layer data agrees with the table module, so a future
303
- // tables refactor cannot silently make decoder capacity calculations stale.
304
- aztecSymbolForLayers(mode.layers, compact);
305
- const raw = extractBits(matrix, compact, mode.layers);
306
- const payload = correctAndUnstuff(raw, mode.layers, mode.dataCodewords);
307
- const bytes = decodeHighLevelBits(payload.bits);
308
- const totalWords = Math.floor(raw.length / aztecWordSizeForLayers(mode.layers));
309
- return {
310
- text: bytesToText(bytes),
311
- bytes,
312
- compact,
313
- layers: mode.layers,
314
- corrections: mode.corrections + payload.corrections,
315
- eccPercent: Math.round(((totalWords - mode.dataCodewords) * 100) / totalWords),
316
- };
290
+ if (!matrix || matrix.width !== matrix.height)
291
+ throw new FormatError('Aztec: expected a square BitMatrix');
292
+ let compact;
293
+ let mode;
294
+ // Compact and full dimensions are disjoint; trying both also makes malformed
295
+ // candidate handling deterministic for the future image detector.
296
+ for (const candidate of [true, false]) {
297
+ try {
298
+ const value = decodeModeMessage(readModeBits(matrix, candidate), candidate);
299
+ if (value.layers < 1 || value.layers > (candidate ? 4 : 32))
300
+ continue;
301
+ if (aztecMatrixSize(value.layers, candidate) !== matrix.width)
302
+ continue;
303
+ compact = candidate;
304
+ mode = value;
305
+ break;
306
+ }
307
+ catch { /* Try the other family. */ }
308
+ }
309
+ if (compact === undefined || !mode)
310
+ throw new FormatError('Aztec: invalid mode message or dimensions');
311
+ // Ensure the declared layer data agrees with the table module, so a future
312
+ // tables refactor cannot silently make decoder capacity calculations stale.
313
+ aztecSymbolForLayers(mode.layers, compact);
314
+ const raw = extractBits(matrix, compact, mode.layers);
315
+ const payload = correctAndUnstuff(raw, mode.layers, mode.dataCodewords);
316
+ const bytes = decodeHighLevelBits(payload.bits);
317
+ const totalWords = Math.floor(raw.length / aztecWordSizeForLayers(mode.layers));
318
+ return {
319
+ text: bytesToText(bytes),
320
+ bytes,
321
+ compact,
322
+ layers: mode.layers,
323
+ corrections: mode.corrections + payload.corrections,
324
+ eccPercent: Math.round(((totalWords - mode.dataCodewords) * 100) / totalWords),
325
+ };
317
326
  }