@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,7 +27,6 @@
27
27
  *
28
28
  * Original work. No code from any other barcode implementation.
29
29
  */
30
-
31
30
  /**
32
31
  * Micro QR Code structural facts and geometry.
33
32
  *
@@ -39,278 +38,287 @@
39
38
  *
40
39
  * @module microqr/tables
41
40
  */
42
-
43
41
  import { BitMatrix } from '../core/bit-matrix.js';
44
-
45
42
  /** Numeric version identifiers used by the encoder selection loop. */
46
43
  export const MICROQR_VERSIONS = Object.freeze([1, 2, 3, 4]);
47
44
  export const MICROQR_VERSION_NAMES = Object.freeze(['M1', 'M2', 'M3', 'M4']);
48
45
  export const MICROQR_ECC_LEVELS = Object.freeze(['DETECT', 'L', 'M', 'Q']);
49
46
  export const MICROQR_FORMAT_MASK = 0x4445;
50
47
  export const MICROQR_FORMAT_GENERATOR = 0x537;
51
-
52
48
  const symbol = (version, ecc, symbolNumber, totalCodewords, dataCodewords, dataBits, eccCodewords) => Object.freeze({
53
- version,
54
- ecc,
55
- symbolNumber,
56
- size: 9 + Number(version.slice(1)) * 2,
57
- totalCodewords,
58
- dataCodewords,
59
- dataBits,
60
- eccCodewords,
61
- blockCount: 1,
62
- shortDataCodewordBits: dataBits % 8 || 8,
63
- remainderBits: 0,
49
+ version,
50
+ ecc,
51
+ symbolNumber,
52
+ size: 9 + Number(version.slice(1)) * 2,
53
+ totalCodewords,
54
+ dataCodewords,
55
+ dataBits,
56
+ eccCodewords,
57
+ blockCount: 1,
58
+ shortDataCodewordBits: dataBits % 8 || 8,
59
+ remainderBits: 0,
64
60
  });
65
-
66
61
  /** The eight legal Micro QR version/error-correction combinations. */
67
62
  export const MICROQR_SYMBOLS = Object.freeze([
68
- symbol('M1', 'DETECT', 0, 5, 3, 20, 2),
69
- symbol('M2', 'L', 1, 10, 5, 40, 5),
70
- symbol('M2', 'M', 2, 10, 4, 32, 6),
71
- symbol('M3', 'L', 3, 17, 11, 84, 6),
72
- symbol('M3', 'M', 4, 17, 9, 68, 8),
73
- symbol('M4', 'L', 5, 24, 16, 128, 8),
74
- symbol('M4', 'M', 6, 24, 14, 112, 10),
75
- symbol('M4', 'Q', 7, 24, 10, 80, 14),
63
+ symbol('M1', 'DETECT', 0, 5, 3, 20, 2),
64
+ symbol('M2', 'L', 1, 10, 5, 40, 5),
65
+ symbol('M2', 'M', 2, 10, 4, 32, 6),
66
+ symbol('M3', 'L', 3, 17, 11, 84, 6),
67
+ symbol('M3', 'M', 4, 17, 9, 68, 8),
68
+ symbol('M4', 'L', 5, 24, 16, 128, 8),
69
+ symbol('M4', 'M', 6, 24, 14, 112, 10),
70
+ symbol('M4', 'Q', 7, 24, 10, 80, 14),
76
71
  ]);
77
-
78
72
  const symbolByKey = new Map(MICROQR_SYMBOLS.map((entry) => [`${entry.version}:${entry.ecc}`, entry]));
79
73
  const symbolByNumber = new Map(MICROQR_SYMBOLS.map((entry) => [entry.symbolNumber, entry]));
80
-
81
74
  function canonicalVersion(version) {
82
- const result = typeof version === 'number' ? `M${version}` : String(version).toUpperCase();
83
- if (!MICROQR_VERSION_NAMES.includes(result)) throw new RangeError(`Micro QR: version must be M1-M4, got ${version}`);
84
- return result;
75
+ const result = typeof version === 'number' ? `M${version}` : String(version).toUpperCase();
76
+ if (!MICROQR_VERSION_NAMES.includes(result))
77
+ throw new RangeError(`Micro QR: version must be M1-M4, got ${version}`);
78
+ return result;
85
79
  }
86
-
87
80
  /** @param {string|number} version @returns {number} */
88
81
  export function microQrVersionSize(version) {
89
- return 9 + Number(canonicalVersion(version).slice(1)) * 2;
82
+ return 9 + Number(canonicalVersion(version).slice(1)) * 2;
90
83
  }
91
-
92
84
  /** Resolve the format symbol number for a legal version/ECC pair. */
93
85
  export function microQrSymbolNumber(version, ecc) {
94
- return microQrBlockLayout(version, ecc).symbolNumber;
86
+ return microQrBlockLayout(version, ecc).symbolNumber;
95
87
  }
96
-
97
88
  /** Resolve the immutable single-block layout for a legal version/ECC pair. */
98
89
  export function microQrBlockLayout(version, ecc) {
99
- const canonical = canonicalVersion(version);
100
- const level = ecc == null && canonical === 'M1' ? 'DETECT' : String(ecc).toUpperCase();
101
- const entry = symbolByKey.get(`${canonical}:${level}`);
102
- if (!entry) throw new RangeError(`Micro QR: error correction level ${ecc} is not valid for ${canonical}`);
103
- return entry;
90
+ const canonical = canonicalVersion(version);
91
+ const level = ecc == null && canonical === 'M1' ? 'DETECT' : String(ecc).toUpperCase();
92
+ const entry = symbolByKey.get(`${canonical}:${level}`);
93
+ if (!entry)
94
+ throw new RangeError(`Micro QR: error correction level ${ecc} is not valid for ${canonical}`);
95
+ return entry;
104
96
  }
105
-
106
97
  /** @returns {number} Usable message bits, including mode/count overhead. */
107
98
  export function microQrDataCapacityBits(version, ecc) {
108
- return microQrBlockLayout(version, ecc).dataBits;
99
+ return microQrBlockLayout(version, ecc).dataBits;
109
100
  }
110
-
111
101
  /**
112
102
  * Encode the five format data bits with BCH(15,5), then apply the Micro QR
113
103
  * format mask. `symbolNumber` occupies the high three data bits and `mask`
114
104
  * the low two.
115
105
  */
116
106
  export function microQrFormatInfo(symbolNumber, mask, maybeMask) {
117
- // Public convenience overload: (version, ecc, mask).
118
- if (arguments.length === 3) {
119
- symbolNumber = microQrSymbolNumber(symbolNumber, mask);
120
- mask = maybeMask;
121
- }
122
- if (!Number.isInteger(symbolNumber) || symbolNumber < 0 || symbolNumber > 7) {
123
- throw new RangeError('Micro QR: symbol number must be an integer in 0..7');
124
- }
125
- if (!Number.isInteger(mask) || mask < 0 || mask > 3) {
126
- throw new RangeError('Micro QR: mask must be an integer in 0..3');
127
- }
128
- const data = (symbolNumber << 2) | mask;
129
- let remainder = data << 10;
130
- for (let bit = 14; bit >= 10; bit--) {
131
- if ((remainder & (1 << bit)) !== 0) remainder ^= MICROQR_FORMAT_GENERATOR << (bit - 10);
132
- }
133
- return ((data << 10) | remainder) ^ MICROQR_FORMAT_MASK;
107
+ // Public convenience overload: (version, ecc, mask).
108
+ if (arguments.length === 3) {
109
+ symbolNumber = microQrSymbolNumber(symbolNumber, mask);
110
+ mask = maybeMask;
111
+ }
112
+ if (!Number.isInteger(symbolNumber) || symbolNumber < 0 || symbolNumber > 7) {
113
+ throw new RangeError('Micro QR: symbol number must be an integer in 0..7');
114
+ }
115
+ if (!Number.isInteger(mask) || mask < 0 || mask > 3) {
116
+ throw new RangeError('Micro QR: mask must be an integer in 0..3');
117
+ }
118
+ const data = (symbolNumber << 2) | mask;
119
+ let remainder = data << 10;
120
+ for (let bit = 14; bit >= 10; bit--) {
121
+ if ((remainder & (1 << bit)) !== 0)
122
+ remainder ^= MICROQR_FORMAT_GENERATOR << (bit - 10);
123
+ }
124
+ return ((data << 10) | remainder) ^ MICROQR_FORMAT_MASK;
134
125
  }
135
-
136
126
  function hammingDistance(a, b) {
137
- let bits = (a ^ b) & 0x7fff;
138
- let count = 0;
139
- while (bits) { bits &= bits - 1; count++; }
140
- return count;
127
+ let bits = (a ^ b) & 0x7fff;
128
+ let count = 0;
129
+ while (bits) {
130
+ bits &= bits - 1;
131
+ count++;
132
+ }
133
+ return count;
141
134
  }
142
-
143
135
  /** Decode/correct a 15-bit format word. Returns null beyond three errors. */
144
136
  export function microQrDecodeFormatInfo(bits) {
145
- if (!Number.isInteger(bits) || bits < 0 || bits > 0x7fff) {
146
- throw new RangeError('Micro QR: format information must be a 15-bit integer');
147
- }
148
- let best = null;
149
- let bestDistance = 16;
150
- for (const entry of MICROQR_SYMBOLS) for (let mask = 0; mask < 4; mask++) {
151
- const expected = microQrFormatInfo(entry.symbolNumber, mask);
152
- const distance = hammingDistance(bits, expected);
153
- if (distance < bestDistance) {
154
- bestDistance = distance;
155
- best = { version: entry.version, ecc: entry.ecc, symbolNumber: entry.symbolNumber, mask, correctedBits: distance, bits: expected };
137
+ if (!Number.isInteger(bits) || bits < 0 || bits > 0x7fff) {
138
+ throw new RangeError('Micro QR: format information must be a 15-bit integer');
156
139
  }
157
- }
158
- return bestDistance <= 3 ? best : null;
140
+ let best = null;
141
+ let bestDistance = 16;
142
+ for (const entry of MICROQR_SYMBOLS)
143
+ for (let mask = 0; mask < 4; mask++) {
144
+ const expected = microQrFormatInfo(entry.symbolNumber, mask);
145
+ const distance = hammingDistance(bits, expected);
146
+ if (distance < bestDistance) {
147
+ bestDistance = distance;
148
+ best = { version: entry.version, ecc: entry.ecc, symbolNumber: entry.symbolNumber, mask, correctedBits: distance, bits: expected };
149
+ }
150
+ }
151
+ return bestDistance <= 3 ? best : null;
159
152
  }
160
-
161
153
  /**
162
154
  * Format modules in bit-number order, least significant bit first. Bits 0..7
163
155
  * run down column 8; bits 8..14 continue right-to-left along row 8.
164
156
  * Position (8,8) is shared by the two arms and appears once.
165
157
  */
166
158
  export function microQrFormatInfoPositions(sizeOrVersion) {
167
- const size = typeof sizeOrVersion === 'number' && sizeOrVersion >= 11
168
- ? sizeOrVersion
169
- : microQrVersionSize(sizeOrVersion);
170
- if (![11, 13, 15, 17].includes(size)) throw new RangeError(`Micro QR: invalid symbol size ${size}`);
171
- const positions = [];
172
- for (let y = 1; y <= 8; y++) positions.push([8, y]);
173
- for (let x = 7; x >= 1; x--) positions.push([x, 8]);
174
- return positions;
159
+ const size = typeof sizeOrVersion === 'number' && sizeOrVersion >= 11
160
+ ? sizeOrVersion
161
+ : microQrVersionSize(sizeOrVersion);
162
+ if (![11, 13, 15, 17].includes(size))
163
+ throw new RangeError(`Micro QR: invalid symbol size ${size}`);
164
+ const positions = [];
165
+ for (let y = 1; y <= 8; y++)
166
+ positions.push([8, y]);
167
+ for (let x = 7; x >= 1; x--)
168
+ positions.push([x, 8]);
169
+ return positions;
175
170
  }
176
-
177
171
  const reservedCache = new Map();
178
172
  const functionCache = new Map();
179
-
180
173
  /**
181
174
  * Fixed dark function modules before format information is written. Light
182
175
  * separator and light timing modules remain unset; use
183
176
  * {@link microQrReservedModules} to distinguish them from payload modules.
184
177
  */
185
178
  export function microQrFunctionModules(version) {
186
- const canonical = canonicalVersion(version);
187
- const cached = functionCache.get(canonical);
188
- if (cached) return cached;
189
- const size = microQrVersionSize(canonical);
190
- const matrix = new BitMatrix(size, size);
191
- for (let y = 0; y < 7; y++) for (let x = 0; x < 7; x++) {
192
- const outer = x === 0 || x === 6 || y === 0 || y === 6;
193
- const centre = x >= 2 && x <= 4 && y >= 2 && y <= 4;
194
- if (outer || centre) matrix.set(x, y);
195
- }
196
- for (let coordinate = 8; coordinate < size; coordinate += 2) {
197
- matrix.set(coordinate, 0);
198
- matrix.set(0, coordinate);
199
- }
200
- functionCache.set(canonical, matrix);
201
- return matrix;
179
+ const canonical = canonicalVersion(version);
180
+ const cached = functionCache.get(canonical);
181
+ if (cached)
182
+ return cached;
183
+ const size = microQrVersionSize(canonical);
184
+ const matrix = new BitMatrix(size, size);
185
+ for (let y = 0; y < 7; y++)
186
+ for (let x = 0; x < 7; x++) {
187
+ const outer = x === 0 || x === 6 || y === 0 || y === 6;
188
+ const centre = x >= 2 && x <= 4 && y >= 2 && y <= 4;
189
+ if (outer || centre)
190
+ matrix.set(x, y);
191
+ }
192
+ for (let coordinate = 8; coordinate < size; coordinate += 2) {
193
+ matrix.set(coordinate, 0);
194
+ matrix.set(0, coordinate);
195
+ }
196
+ functionCache.set(canonical, matrix);
197
+ return matrix;
202
198
  }
203
-
204
199
  /** Shared immutable-in-use map of finder, separator, timing and format modules. */
205
200
  export function microQrReservedModules(version) {
206
- const canonical = canonicalVersion(version);
207
- const cached = reservedCache.get(canonical);
208
- if (cached) return cached;
209
- const size = microQrVersionSize(canonical);
210
- const matrix = new BitMatrix(size, size);
211
- matrix.setRegion(0, 0, 8, 8); // 7x7 finder plus inner separator
212
- for (let coordinate = 8; coordinate < size; coordinate++) {
213
- matrix.set(coordinate, 0); // horizontal timing
214
- matrix.set(0, coordinate); // vertical timing
215
- }
216
- for (const [x, y] of microQrFormatInfoPositions(size)) matrix.set(x, y);
217
- reservedCache.set(canonical, matrix);
218
- return matrix;
201
+ const canonical = canonicalVersion(version);
202
+ const cached = reservedCache.get(canonical);
203
+ if (cached)
204
+ return cached;
205
+ const size = microQrVersionSize(canonical);
206
+ const matrix = new BitMatrix(size, size);
207
+ matrix.setRegion(0, 0, 8, 8); // 7x7 finder plus inner separator
208
+ for (let coordinate = 8; coordinate < size; coordinate++) {
209
+ matrix.set(coordinate, 0); // horizontal timing
210
+ matrix.set(0, coordinate); // vertical timing
211
+ }
212
+ for (const [x, y] of microQrFormatInfoPositions(size))
213
+ matrix.set(x, y);
214
+ reservedCache.set(canonical, matrix);
215
+ return matrix;
219
216
  }
220
-
221
217
  /** Number of modules carrying data or error-correction bits. */
222
218
  export function microQrFreeModuleCount(version) {
223
- const size = microQrVersionSize(version);
224
- const reserved = microQrReservedModules(version);
225
- let count = 0;
226
- for (let y = 0; y < size; y++) for (let x = 0; x < size; x++) {
227
- if (!reserved.get(x, y)) count++;
228
- }
229
- return count;
219
+ const size = microQrVersionSize(version);
220
+ const reserved = microQrReservedModules(version);
221
+ let count = 0;
222
+ for (let y = 0; y < size; y++)
223
+ for (let x = 0; x < size; x++) {
224
+ if (!reserved.get(x, y))
225
+ count++;
226
+ }
227
+ return count;
230
228
  }
231
-
232
229
  const orderCache = new Map();
233
-
234
230
  /** Payload module coordinates as interleaved x,y pairs, MSB-first stream order. */
235
231
  export function microQrDataModuleOrder(version) {
236
- const canonical = canonicalVersion(version);
237
- const cached = orderCache.get(canonical);
238
- if (cached) return cached;
239
- const size = microQrVersionSize(canonical);
240
- const reserved = microQrReservedModules(canonical);
241
- const order = new Int32Array(microQrFreeModuleCount(canonical) * 2);
242
- let offset = 0;
243
- let upward = true;
244
- for (let column = size - 1; column > 0; column -= 2) {
245
- for (let rowOffset = 0; rowOffset < size; rowOffset++) {
246
- const y = upward ? size - 1 - rowOffset : rowOffset;
247
- for (let side = 0; side < 2; side++) {
248
- const x = column - side;
249
- if (reserved.get(x, y)) continue;
250
- order[offset++] = x;
251
- order[offset++] = y;
252
- }
232
+ const canonical = canonicalVersion(version);
233
+ const cached = orderCache.get(canonical);
234
+ if (cached)
235
+ return cached;
236
+ const size = microQrVersionSize(canonical);
237
+ const reserved = microQrReservedModules(canonical);
238
+ const order = new Int32Array(microQrFreeModuleCount(canonical) * 2);
239
+ let offset = 0;
240
+ let upward = true;
241
+ for (let column = size - 1; column > 0; column -= 2) {
242
+ for (let rowOffset = 0; rowOffset < size; rowOffset++) {
243
+ const y = upward ? size - 1 - rowOffset : rowOffset;
244
+ for (let side = 0; side < 2; side++) {
245
+ const x = column - side;
246
+ if (reserved.get(x, y))
247
+ continue;
248
+ order[offset++] = x;
249
+ order[offset++] = y;
250
+ }
251
+ }
252
+ upward = !upward;
253
253
  }
254
- upward = !upward;
255
- }
256
- orderCache.set(canonical, order);
257
- return order;
254
+ orderCache.set(canonical, order);
255
+ return order;
258
256
  }
259
-
260
257
  /** The four Micro QR data-mask predicates. */
261
258
  export function microQrMaskBit(mask, x, y) {
262
- switch (mask) {
263
- case 0: return (y & 1) === 0;
264
- case 1: return (((y >> 1) + Math.floor(x / 3)) & 1) === 0;
265
- case 2: return ((((y * x) & 1) + ((y * x) % 3)) & 1) === 0;
266
- case 3: return ((((y + x) & 1) + ((y * x) % 3)) & 1) === 0;
267
- default: throw new RangeError(`Micro QR: mask must be an integer in 0..3, got ${mask}`);
268
- }
259
+ switch (mask) {
260
+ case 0: return (y & 1) === 0;
261
+ case 1: return (((y >> 1) + Math.floor(x / 3)) & 1) === 0;
262
+ case 2: return ((((y * x) & 1) + ((y * x) % 3)) & 1) === 0;
263
+ case 3: return ((((y + x) & 1) + ((y * x) % 3)) & 1) === 0;
264
+ default: throw new RangeError(`Micro QR: mask must be an integer in 0..3, got ${mask}`);
265
+ }
269
266
  }
270
-
271
267
  /** Return all internal table/geometry invariant failures. */
272
268
  export function validateMicroQrTables() {
273
- const issues = [];
274
- if (MICROQR_SYMBOLS.length !== 8) issues.push('expected eight symbol/ECC combinations');
275
- const numbers = new Set();
276
- for (const entry of MICROQR_SYMBOLS) {
277
- const tag = `${entry.version}-${entry.ecc}`;
278
- if (numbers.has(entry.symbolNumber)) issues.push(`${tag}: duplicate symbol number`);
279
- numbers.add(entry.symbolNumber);
280
- if (entry.blockCount !== 1) issues.push(`${tag}: Micro QR must use one block`);
281
- if (entry.dataBits + entry.eccCodewords * 8 !== microQrFreeModuleCount(entry.version)) {
282
- issues.push(`${tag}: data/ECC bits do not fill the encoding region`);
283
- }
284
- if (entry.totalCodewords !== entry.dataCodewords + entry.eccCodewords) issues.push(`${tag}: codeword count mismatch`);
285
- if (entry.dataBits !== (entry.dataCodewords - 1) * 8 + entry.shortDataCodewordBits) issues.push(`${tag}: final data codeword mismatch`);
286
- if (entry.shortDataCodewordBits !== (entry.version === 'M1' || entry.version === 'M3' ? 4 : 8)) issues.push(`${tag}: wrong final data codeword width`);
287
- }
288
- for (const version of MICROQR_VERSIONS) {
289
- const size = microQrVersionSize(version);
290
- const positions = microQrFormatInfoPositions(size);
291
- const unique = new Set(positions.map(([x, y]) => `${x},${y}`));
292
- if (positions.length !== 15 || unique.size !== 15) issues.push(`${version}: format positions must be 15 unique modules`);
293
- const order = microQrDataModuleOrder(version);
294
- const orderUnique = new Set();
295
- for (let i = 0; i < order.length; i += 2) {
296
- const x = order[i], y = order[i + 1];
297
- if (microQrReservedModules(version).get(x, y)) issues.push(`${version}: placement enters reserved module ${x},${y}`);
298
- orderUnique.add(`${x},${y}`);
299
- }
300
- if (orderUnique.size * 2 !== order.length) issues.push(`${version}: placement repeats a module`);
301
- if (order.length !== microQrFreeModuleCount(version) * 2) issues.push(`${version}: placement does not cover encoding region`);
302
- const functions = microQrFunctionModules(version);
303
- for (let y = 0; y < size; y++) for (let x = 0; x < size; x++) {
304
- if (functions.get(x, y) && !microQrReservedModules(version).get(x, y)) {
305
- issues.push(`${version}: dark function module ${x},${y} is not reserved`);
306
- }
269
+ const issues = [];
270
+ if (MICROQR_SYMBOLS.length !== 8)
271
+ issues.push('expected eight symbol/ECC combinations');
272
+ const numbers = new Set();
273
+ for (const entry of MICROQR_SYMBOLS) {
274
+ const tag = `${entry.version}-${entry.ecc}`;
275
+ if (numbers.has(entry.symbolNumber))
276
+ issues.push(`${tag}: duplicate symbol number`);
277
+ numbers.add(entry.symbolNumber);
278
+ if (entry.blockCount !== 1)
279
+ issues.push(`${tag}: Micro QR must use one block`);
280
+ if (entry.dataBits + entry.eccCodewords * 8 !== microQrFreeModuleCount(entry.version)) {
281
+ issues.push(`${tag}: data/ECC bits do not fill the encoding region`);
282
+ }
283
+ if (entry.totalCodewords !== entry.dataCodewords + entry.eccCodewords)
284
+ issues.push(`${tag}: codeword count mismatch`);
285
+ if (entry.dataBits !== (entry.dataCodewords - 1) * 8 + entry.shortDataCodewordBits)
286
+ issues.push(`${tag}: final data codeword mismatch`);
287
+ if (entry.shortDataCodewordBits !== (entry.version === 'M1' || entry.version === 'M3' ? 4 : 8))
288
+ issues.push(`${tag}: wrong final data codeword width`);
307
289
  }
308
- }
309
- for (const entry of MICROQR_SYMBOLS) for (let mask = 0; mask < 4; mask++) {
310
- const decoded = microQrDecodeFormatInfo(microQrFormatInfo(entry.symbolNumber, mask));
311
- if (!decoded || decoded.symbolNumber !== entry.symbolNumber || decoded.mask !== mask || decoded.correctedBits !== 0) {
312
- issues.push(`${entry.version}-${entry.ecc}: format round-trip failed for mask ${mask}`);
290
+ for (const version of MICROQR_VERSIONS) {
291
+ const size = microQrVersionSize(version);
292
+ const positions = microQrFormatInfoPositions(size);
293
+ const unique = new Set(positions.map(([x, y]) => `${x},${y}`));
294
+ if (positions.length !== 15 || unique.size !== 15)
295
+ issues.push(`${version}: format positions must be 15 unique modules`);
296
+ const order = microQrDataModuleOrder(version);
297
+ const orderUnique = new Set();
298
+ for (let i = 0; i < order.length; i += 2) {
299
+ const x = order[i], y = order[i + 1];
300
+ if (microQrReservedModules(version).get(x, y))
301
+ issues.push(`${version}: placement enters reserved module ${x},${y}`);
302
+ orderUnique.add(`${x},${y}`);
303
+ }
304
+ if (orderUnique.size * 2 !== order.length)
305
+ issues.push(`${version}: placement repeats a module`);
306
+ if (order.length !== microQrFreeModuleCount(version) * 2)
307
+ issues.push(`${version}: placement does not cover encoding region`);
308
+ const functions = microQrFunctionModules(version);
309
+ for (let y = 0; y < size; y++)
310
+ for (let x = 0; x < size; x++) {
311
+ if (functions.get(x, y) && !microQrReservedModules(version).get(x, y)) {
312
+ issues.push(`${version}: dark function module ${x},${y} is not reserved`);
313
+ }
314
+ }
313
315
  }
314
- }
315
- return issues;
316
+ for (const entry of MICROQR_SYMBOLS)
317
+ for (let mask = 0; mask < 4; mask++) {
318
+ const decoded = microQrDecodeFormatInfo(microQrFormatInfo(entry.symbolNumber, mask));
319
+ if (!decoded || decoded.symbolNumber !== entry.symbolNumber || decoded.mask !== mask || decoded.correctedBits !== 0) {
320
+ issues.push(`${entry.version}-${entry.ecc}: format round-trip failed for mask ${mask}`);
321
+ }
322
+ }
323
+ return issues;
316
324
  }