@sythos/js_barcode_universal 1.5.7 → 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 (267) hide show
  1. package/LICENSE +5 -4
  2. package/NOTICE.md +2 -2
  3. package/README.md +50 -37
  4. package/bundle/sythos-barcode.esm.js +12051 -11484
  5. package/bundle/sythos-barcode.js +12051 -11484
  6. package/package.json +52 -45
  7. package/src/index.d.ts +363 -0
  8. package/src/index.js +573 -428
  9. package/src/js/aztec/decoder.js +326 -0
  10. package/src/js/aztec/detector.js +251 -0
  11. package/src/js/aztec/encoder.js +276 -0
  12. package/src/js/aztec/high-level.js +216 -0
  13. package/src/js/aztec/index.js +34 -0
  14. package/src/js/aztec/tables.js +196 -0
  15. package/src/js/aztecrune/decoder.js +146 -0
  16. package/src/js/aztecrune/detector.js +180 -0
  17. package/src/js/aztecrune/encoder.js +103 -0
  18. package/src/js/aztecrune/index.js +34 -0
  19. package/src/js/aztecrune/tables.js +142 -0
  20. package/src/js/compactpdf417/decoder.js +123 -0
  21. package/src/js/compactpdf417/detector.js +138 -0
  22. package/src/js/compactpdf417/encoder.js +127 -0
  23. package/src/js/compactpdf417/index.js +5 -0
  24. package/src/js/compactpdf417/tables.js +164 -0
  25. package/src/js/core/bit-buffer.js +158 -0
  26. package/src/js/core/bit-matrix.js +243 -0
  27. package/src/js/core/errors.js +59 -0
  28. package/src/js/core/galois-field.js +193 -0
  29. package/src/js/core/index.js +39 -0
  30. package/src/js/core/reed-solomon.js +318 -0
  31. package/src/js/databar/codec.js +166 -0
  32. package/src/js/databar/decoder.js +224 -0
  33. package/src/js/databar/encoder.js +88 -0
  34. package/src/js/databar/gs1.js +176 -0
  35. package/src/js/databar/index.js +36 -0
  36. package/src/js/databar/patterns.js +139 -0
  37. package/src/js/databar/tables.js +123 -0
  38. package/src/js/datamatrix/decoder.js +296 -0
  39. package/src/js/datamatrix/detector.js +254 -0
  40. package/src/js/datamatrix/encoder.js +250 -0
  41. package/src/js/datamatrix/index.js +34 -0
  42. package/src/js/datamatrix/tables.js +122 -0
  43. package/src/js/frameqr/decoder.js +216 -0
  44. package/src/js/frameqr/detector.js +199 -0
  45. package/src/js/frameqr/encoder.js +143 -0
  46. package/src/js/frameqr/index.js +33 -0
  47. package/src/js/frameqr/tables.js +252 -0
  48. package/src/js/image/binarizer.js +254 -0
  49. package/src/js/image/grid-sampler.js +148 -0
  50. package/src/js/image/index.js +38 -0
  51. package/src/js/image/luminance.js +185 -0
  52. package/src/js/image/perspective.js +158 -0
  53. package/src/js/micropdf417/compaction.js +115 -0
  54. package/src/js/micropdf417/decoder.js +180 -0
  55. package/src/js/micropdf417/detector.js +152 -0
  56. package/src/js/micropdf417/encoder.js +184 -0
  57. package/src/js/micropdf417/error-correction.js +50 -0
  58. package/src/js/micropdf417/index.js +35 -0
  59. package/src/js/micropdf417/tables.js +197 -0
  60. package/src/js/microqr/decoder.js +240 -0
  61. package/src/js/microqr/detector.js +339 -0
  62. package/src/js/microqr/encoder.js +314 -0
  63. package/src/js/microqr/index.js +34 -0
  64. package/src/js/microqr/tables.js +324 -0
  65. package/src/js/oned/addons.js +396 -0
  66. package/src/js/oned/index.js +75 -0
  67. package/src/js/oned/patterns.js +365 -0
  68. package/src/js/oned/reader.js +1383 -0
  69. package/src/js/oned/writers.js +691 -0
  70. package/src/js/pdf417/compaction.js +391 -0
  71. package/src/js/pdf417/decoder.js +110 -0
  72. package/src/js/pdf417/detector.js +484 -0
  73. package/src/js/pdf417/encoder.js +102 -0
  74. package/src/js/pdf417/error-correction.js +44 -0
  75. package/src/{pdf417 → js/pdf417}/index.js +0 -5
  76. package/src/js/pdf417/tables.js +315 -0
  77. package/src/js/qr/decoder.js +539 -0
  78. package/src/js/qr/detector.js +613 -0
  79. package/src/js/qr/encoder.js +873 -0
  80. package/src/js/qr/index.js +42 -0
  81. package/src/js/qr/tables.js +690 -0
  82. package/src/js/render/image-data.js +120 -0
  83. package/src/js/render/index.js +128 -0
  84. package/src/js/render/options.js +152 -0
  85. package/src/js/render/png.js +270 -0
  86. package/src/js/render/svg.js +117 -0
  87. package/src/js/render/webgl.js +200 -0
  88. package/src/js/render/webgpu.js +357 -0
  89. package/src/js/rmqr/decoder.js +209 -0
  90. package/src/js/rmqr/detector.js +122 -0
  91. package/src/js/rmqr/encoder.js +321 -0
  92. package/src/js/rmqr/index.js +33 -0
  93. package/src/js/rmqr/tables.js +177 -0
  94. package/src/{aztec/decoder.js → ts/aztec/decoder.ts} +0 -1
  95. package/{typings → src/ts}/aztec/detector.d.ts +2 -2
  96. package/src/{aztec/detector.js → ts/aztec/detector.ts} +0 -1
  97. package/src/{aztec/encoder.js → ts/aztec/encoder.ts} +0 -1
  98. package/src/{aztec/high-level.js → ts/aztec/high-level.ts} +0 -1
  99. package/src/{aztec/index.js → ts/aztec/index.ts} +0 -1
  100. package/src/{aztec/tables.js → ts/aztec/tables.ts} +0 -1
  101. package/src/{aztecrune/decoder.js → ts/aztecrune/decoder.ts} +0 -1
  102. package/src/{aztecrune/detector.js → ts/aztecrune/detector.ts} +0 -1
  103. package/src/{aztecrune/encoder.js → ts/aztecrune/encoder.ts} +0 -1
  104. package/src/{aztecrune/index.js → ts/aztecrune/index.ts} +0 -1
  105. package/src/{aztecrune/tables.js → ts/aztecrune/tables.ts} +0 -1
  106. package/src/{compactpdf417/decoder.js → ts/compactpdf417/decoder.ts} +0 -1
  107. package/src/{compactpdf417/detector.js → ts/compactpdf417/detector.ts} +0 -1
  108. package/src/{compactpdf417/encoder.js → ts/compactpdf417/encoder.ts} +0 -1
  109. package/src/{compactpdf417/index.js → ts/compactpdf417/index.ts} +0 -5
  110. package/src/{compactpdf417/tables.js → ts/compactpdf417/tables.ts} +0 -1
  111. package/src/{core/bit-buffer.js → ts/core/bit-buffer.ts} +0 -1
  112. package/src/{core/bit-matrix.js → ts/core/bit-matrix.ts} +0 -1
  113. package/src/{core/errors.js → ts/core/errors.ts} +0 -1
  114. package/src/{core/galois-field.js → ts/core/galois-field.ts} +0 -1
  115. package/src/{core/index.js → ts/core/index.ts} +0 -1
  116. package/src/{core/reed-solomon.js → ts/core/reed-solomon.ts} +0 -1
  117. package/src/{databar/codec.js → ts/databar/codec.ts} +0 -1
  118. package/src/{databar/decoder.js → ts/databar/decoder.ts} +0 -1
  119. package/src/{databar/encoder.js → ts/databar/encoder.ts} +0 -1
  120. package/src/{databar/gs1.js → ts/databar/gs1.ts} +0 -1
  121. package/src/{databar/index.js → ts/databar/index.ts} +0 -1
  122. package/src/{databar/patterns.js → ts/databar/patterns.ts} +0 -1
  123. package/src/{databar/tables.js → ts/databar/tables.ts} +0 -1
  124. package/src/{datamatrix/decoder.js → ts/datamatrix/decoder.ts} +0 -1
  125. package/{typings → src/ts}/datamatrix/detector.d.ts +2 -2
  126. package/src/{datamatrix/detector.js → ts/datamatrix/detector.ts} +0 -1
  127. package/src/{datamatrix/encoder.js → ts/datamatrix/encoder.ts} +0 -1
  128. package/src/{datamatrix/index.js → ts/datamatrix/index.ts} +0 -1
  129. package/src/{datamatrix/tables.js → ts/datamatrix/tables.ts} +0 -1
  130. package/src/{frameqr/decoder.js → ts/frameqr/decoder.ts} +15 -16
  131. package/src/{frameqr/detector.js → ts/frameqr/detector.ts} +2 -3
  132. package/src/{frameqr/encoder.js → ts/frameqr/encoder.ts} +7 -8
  133. package/src/{frameqr/index.js → ts/frameqr/index.ts} +0 -1
  134. package/src/{frameqr/tables.js → ts/frameqr/tables.ts} +10 -11
  135. package/src/{image/binarizer.js → ts/image/binarizer.ts} +0 -1
  136. package/src/{image/grid-sampler.js → ts/image/grid-sampler.ts} +0 -1
  137. package/src/{image/index.js → ts/image/index.ts} +0 -1
  138. package/src/{image/luminance.js → ts/image/luminance.ts} +0 -1
  139. package/src/{image/perspective.js → ts/image/perspective.ts} +0 -1
  140. package/{typings → src/ts}/index.d.ts +3 -3
  141. package/src/ts/index.ts +790 -0
  142. package/src/{micropdf417/compaction.js → ts/micropdf417/compaction.ts} +0 -1
  143. package/src/{micropdf417/decoder.js → ts/micropdf417/decoder.ts} +0 -1
  144. package/src/{micropdf417/detector.js → ts/micropdf417/detector.ts} +0 -1
  145. package/src/{micropdf417/encoder.js → ts/micropdf417/encoder.ts} +0 -1
  146. package/src/{micropdf417/error-correction.js → ts/micropdf417/error-correction.ts} +0 -1
  147. package/src/{micropdf417/index.js → ts/micropdf417/index.ts} +0 -1
  148. package/src/{micropdf417/tables.js → ts/micropdf417/tables.ts} +0 -1
  149. package/src/{microqr/decoder.js → ts/microqr/decoder.ts} +0 -1
  150. package/src/{microqr/detector.js → ts/microqr/detector.ts} +0 -1
  151. package/src/{microqr/encoder.js → ts/microqr/encoder.ts} +0 -1
  152. package/src/{microqr/index.js → ts/microqr/index.ts} +0 -1
  153. package/src/{microqr/tables.js → ts/microqr/tables.ts} +0 -1
  154. package/src/{oned/addons.js → ts/oned/addons.ts} +0 -1
  155. package/src/{oned/index.js → ts/oned/index.ts} +0 -1
  156. package/src/{oned/patterns.js → ts/oned/patterns.ts} +0 -1
  157. package/src/{oned/reader.js → ts/oned/reader.ts} +0 -1
  158. package/src/{oned/writers.js → ts/oned/writers.ts} +0 -1
  159. package/src/{pdf417/compaction.js → ts/pdf417/compaction.ts} +0 -1
  160. package/src/{pdf417/decoder.js → ts/pdf417/decoder.ts} +0 -1
  161. package/src/{pdf417/detector.js → ts/pdf417/detector.ts} +0 -1
  162. package/src/{pdf417/encoder.js → ts/pdf417/encoder.ts} +0 -1
  163. package/src/{pdf417/error-correction.js → ts/pdf417/error-correction.ts} +0 -1
  164. package/src/ts/pdf417/index.ts +6 -0
  165. package/src/{pdf417/tables.js → ts/pdf417/tables.ts} +0 -1
  166. package/src/{qr/decoder.js → ts/qr/decoder.ts} +0 -1
  167. package/src/{qr/detector.js → ts/qr/detector.ts} +0 -1
  168. package/src/{qr/encoder.js → ts/qr/encoder.ts} +0 -1
  169. package/src/{qr/index.js → ts/qr/index.ts} +0 -1
  170. package/src/{qr/tables.js → ts/qr/tables.ts} +0 -1
  171. package/src/{render/image-data.js → ts/render/image-data.ts} +0 -1
  172. package/src/{render/index.js → ts/render/index.ts} +0 -1
  173. package/src/{render/options.js → ts/render/options.ts} +0 -1
  174. package/src/{render/png.js → ts/render/png.ts} +0 -1
  175. package/src/{render/svg.js → ts/render/svg.ts} +0 -1
  176. package/src/{render/webgl.js → ts/render/webgl.ts} +0 -1
  177. package/src/{render/webgpu.js → ts/render/webgpu.ts} +0 -1
  178. package/src/{rmqr/decoder.js → ts/rmqr/decoder.ts} +0 -1
  179. package/src/{rmqr/detector.js → ts/rmqr/detector.ts} +0 -1
  180. package/src/{rmqr/encoder.js → ts/rmqr/encoder.ts} +0 -1
  181. package/src/{rmqr/index.js → ts/rmqr/index.ts} +0 -1
  182. package/src/{rmqr/tables.js → ts/rmqr/tables.ts} +0 -1
  183. /package/{typings → src/ts}/aztec/decoder.d.ts +0 -0
  184. /package/{typings → src/ts}/aztec/encoder.d.ts +0 -0
  185. /package/{typings → src/ts}/aztec/high-level.d.ts +0 -0
  186. /package/{typings → src/ts}/aztec/index.d.ts +0 -0
  187. /package/{typings → src/ts}/aztec/tables.d.ts +0 -0
  188. /package/{typings → src/ts}/aztecrune/decoder.d.ts +0 -0
  189. /package/{typings → src/ts}/aztecrune/detector.d.ts +0 -0
  190. /package/{typings → src/ts}/aztecrune/encoder.d.ts +0 -0
  191. /package/{typings → src/ts}/aztecrune/index.d.ts +0 -0
  192. /package/{typings → src/ts}/aztecrune/tables.d.ts +0 -0
  193. /package/{typings → src/ts}/bundle/sythos-barcode.d.ts +0 -0
  194. /package/{typings → src/ts}/bundle/sythos-barcode.esm.d.ts +0 -0
  195. /package/{typings → src/ts}/compactpdf417/decoder.d.ts +0 -0
  196. /package/{typings → src/ts}/compactpdf417/detector.d.ts +0 -0
  197. /package/{typings → src/ts}/compactpdf417/encoder.d.ts +0 -0
  198. /package/{typings → src/ts}/compactpdf417/index.d.ts +0 -0
  199. /package/{typings → src/ts}/compactpdf417/tables.d.ts +0 -0
  200. /package/{typings → src/ts}/core/bit-buffer.d.ts +0 -0
  201. /package/{typings → src/ts}/core/bit-matrix.d.ts +0 -0
  202. /package/{typings → src/ts}/core/errors.d.ts +0 -0
  203. /package/{typings → src/ts}/core/galois-field.d.ts +0 -0
  204. /package/{typings → src/ts}/core/index.d.ts +0 -0
  205. /package/{typings → src/ts}/core/reed-solomon.d.ts +0 -0
  206. /package/{typings → src/ts}/databar/codec.d.ts +0 -0
  207. /package/{typings → src/ts}/databar/decoder.d.ts +0 -0
  208. /package/{typings → src/ts}/databar/encoder.d.ts +0 -0
  209. /package/{typings → src/ts}/databar/gs1.d.ts +0 -0
  210. /package/{typings → src/ts}/databar/index.d.ts +0 -0
  211. /package/{typings → src/ts}/databar/patterns.d.ts +0 -0
  212. /package/{typings → src/ts}/databar/tables.d.ts +0 -0
  213. /package/{typings → src/ts}/datamatrix/decoder.d.ts +0 -0
  214. /package/{typings → src/ts}/datamatrix/encoder.d.ts +0 -0
  215. /package/{typings → src/ts}/datamatrix/index.d.ts +0 -0
  216. /package/{typings → src/ts}/datamatrix/tables.d.ts +0 -0
  217. /package/{typings → src/ts}/frameqr/decoder.d.ts +0 -0
  218. /package/{typings → src/ts}/frameqr/detector.d.ts +0 -0
  219. /package/{typings → src/ts}/frameqr/encoder.d.ts +0 -0
  220. /package/{typings → src/ts}/frameqr/index.d.ts +0 -0
  221. /package/{typings → src/ts}/frameqr/tables.d.ts +0 -0
  222. /package/{typings → src/ts}/image/binarizer.d.ts +0 -0
  223. /package/{typings → src/ts}/image/grid-sampler.d.ts +0 -0
  224. /package/{typings → src/ts}/image/index.d.ts +0 -0
  225. /package/{typings → src/ts}/image/luminance.d.ts +0 -0
  226. /package/{typings → src/ts}/image/perspective.d.ts +0 -0
  227. /package/{typings → src/ts}/micropdf417/compaction.d.ts +0 -0
  228. /package/{typings → src/ts}/micropdf417/decoder.d.ts +0 -0
  229. /package/{typings → src/ts}/micropdf417/detector.d.ts +0 -0
  230. /package/{typings → src/ts}/micropdf417/encoder.d.ts +0 -0
  231. /package/{typings → src/ts}/micropdf417/error-correction.d.ts +0 -0
  232. /package/{typings → src/ts}/micropdf417/index.d.ts +0 -0
  233. /package/{typings → src/ts}/micropdf417/tables.d.ts +0 -0
  234. /package/{typings → src/ts}/microqr/decoder.d.ts +0 -0
  235. /package/{typings → src/ts}/microqr/detector.d.ts +0 -0
  236. /package/{typings → src/ts}/microqr/encoder.d.ts +0 -0
  237. /package/{typings → src/ts}/microqr/index.d.ts +0 -0
  238. /package/{typings → src/ts}/microqr/tables.d.ts +0 -0
  239. /package/{typings → src/ts}/oned/addons.d.ts +0 -0
  240. /package/{typings → src/ts}/oned/index.d.ts +0 -0
  241. /package/{typings → src/ts}/oned/patterns.d.ts +0 -0
  242. /package/{typings → src/ts}/oned/reader.d.ts +0 -0
  243. /package/{typings → src/ts}/oned/writers.d.ts +0 -0
  244. /package/{typings → src/ts}/pdf417/compaction.d.ts +0 -0
  245. /package/{typings → src/ts}/pdf417/decoder.d.ts +0 -0
  246. /package/{typings → src/ts}/pdf417/detector.d.ts +0 -0
  247. /package/{typings → src/ts}/pdf417/encoder.d.ts +0 -0
  248. /package/{typings → src/ts}/pdf417/error-correction.d.ts +0 -0
  249. /package/{typings → src/ts}/pdf417/index.d.ts +0 -0
  250. /package/{typings → src/ts}/pdf417/tables.d.ts +0 -0
  251. /package/{typings → src/ts}/qr/decoder.d.ts +0 -0
  252. /package/{typings → src/ts}/qr/detector.d.ts +0 -0
  253. /package/{typings → src/ts}/qr/encoder.d.ts +0 -0
  254. /package/{typings → src/ts}/qr/index.d.ts +0 -0
  255. /package/{typings → src/ts}/qr/tables.d.ts +0 -0
  256. /package/{typings → src/ts}/render/image-data.d.ts +0 -0
  257. /package/{typings → src/ts}/render/index.d.ts +0 -0
  258. /package/{typings → src/ts}/render/options.d.ts +0 -0
  259. /package/{typings → src/ts}/render/png.d.ts +0 -0
  260. /package/{typings → src/ts}/render/svg.d.ts +0 -0
  261. /package/{typings → src/ts}/render/webgl.d.ts +0 -0
  262. /package/{typings → src/ts}/render/webgpu.d.ts +0 -0
  263. /package/{typings → src/ts}/rmqr/decoder.d.ts +0 -0
  264. /package/{typings → src/ts}/rmqr/detector.d.ts +0 -0
  265. /package/{typings → src/ts}/rmqr/encoder.d.ts +0 -0
  266. /package/{typings → src/ts}/rmqr/index.d.ts +0 -0
  267. /package/{typings → src/ts}/rmqr/tables.d.ts +0 -0
@@ -0,0 +1,326 @@
1
+ /*!
2
+ * Sythos Barcode Suite
3
+ *
4
+ * MIT License
5
+ *
6
+ * Copyright (c) 2026 Sythos
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all
16
+ * copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
26
+ * SPDX-License-Identifier: MIT
27
+ *
28
+ * Original work. No code from any other barcode implementation.
29
+ */
30
+ /**
31
+ * Decoder for a sampled Aztec symbol.
32
+ *
33
+ * This module deliberately accepts only a square, module-aligned BitMatrix.
34
+ * Locating a bull's-eye in a photograph and perspective sampling are detector
35
+ * concerns. Keeping the two stages apart makes all bit order and ECC rules
36
+ * testable without image-processing noise.
37
+ *
38
+ * Contract with tables.js:
39
+ * - aztecSymbolForLayers(compact, layers) returns the nominal symbol data;
40
+ * - aztecWordSizeForLayers(layers) returns 6, 8, 10 or 12;
41
+ * - aztecFieldForLayers(layers) returns the matching binary Galois field;
42
+ * - aztecMatrixSize(compact, layers) returns the rendered square size.
43
+ *
44
+ * @module aztec/decoder
45
+ */
46
+ import { FormatError } from '../core/errors.js';
47
+ import { rsDecode } from '../core/reed-solomon.js';
48
+ import { aztecLayer as aztecSymbolForLayers, wordSizeForLayers as aztecWordSizeForLayers, fieldForLayers as aztecFieldForLayers, fieldForWordSize, aztecSymbolSize as aztecMatrixSize, } from './tables.js';
49
+ const UPPER = ['CTRL_PS', ' ', ...'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'CTRL_LL', 'CTRL_ML', 'CTRL_DL', 'CTRL_BS'];
50
+ const LOWER = ['CTRL_PS', ' ', ...'abcdefghijklmnopqrstuvwxyz', 'CTRL_US', 'CTRL_ML', 'CTRL_DL', 'CTRL_BS'];
51
+ const MIXED = [
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',
54
+ ];
55
+ const PUNCT = ['FLG(n)', '\r', '\r\n', '. ', ', ', ': ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}', 'CTRL_UL'];
56
+ const DIGIT = ['CTRL_PS', ' ', ...'0123456789', ',', '.', 'CTRL_UL'];
57
+ const TABLES = { UPPER, LOWER, MIXED, PUNCT, DIGIT };
58
+ /** @param {boolean[]} bits @param {number} offset @param {number} count */
59
+ function readBits(bits, offset, count) {
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;
66
+ }
67
+ /** @param {number} value @param {number} count @param {boolean[]} out */
68
+ function appendBits(value, count, out) {
69
+ for (let i = count - 1; i >= 0; i--)
70
+ out.push(((value >>> i) & 1) !== 0);
71
+ }
72
+ /**
73
+ * Decode an Aztec high-level bit stream to its exact byte payload.
74
+ *
75
+ * Text tables contribute their ISO-8859-1 byte values; Binary Shift appends
76
+ * raw bytes. ECI markers are consumed but intentionally not emitted: callers
77
+ * receive the transported byte payload and may select their own charset.
78
+ *
79
+ * @param {boolean[]} bits
80
+ * @returns {Uint8Array}
81
+ */
82
+ export function decodeHighLevelBits(bits) {
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;
107
+ }
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;
156
+ }
157
+ return Uint8Array.from(output);
158
+ }
159
+ /** @param {boolean} compact @param {number} layers */
160
+ function alignmentMap(compact, layers) {
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;
174
+ }
175
+ /**
176
+ * Read the four sides of the parameter message. The order mirrors the
177
+ * clockwise write order and is independent of the data spiral.
178
+ *
179
+ * @param {import('../core/bit-matrix.js').BitMatrix} matrix
180
+ * @param {boolean} compact
181
+ * @returns {boolean[]}
182
+ */
183
+ function readModeBits(matrix, compact) {
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;
200
+ }
201
+ /** @param {boolean[]} bits @param {boolean} compact */
202
+ function decodeModeMessage(bits, compact) {
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
+ }
216
+ /** @param {boolean} compact @param {number} layers */
217
+ function totalBitsInLayers(compact, layers) {
218
+ return ((compact ? 88 : 112) + 16 * layers) * layers;
219
+ }
220
+ /**
221
+ * Extract raw, stuffed codeword bits in logical ring order.
222
+ * @param {import('../core/bit-matrix.js').BitMatrix} matrix
223
+ * @param {boolean} compact @param {number} layers
224
+ * @returns {boolean[]}
225
+ */
226
+ function extractBits(matrix, compact, layers) {
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
+ }
244
+ return raw;
245
+ }
246
+ /** @param {boolean[]} raw @param {number} layers @param {number} dataCodewords */
247
+ function correctAndUnstuff(raw, layers, dataCodewords) {
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
+ }
270
+ }
271
+ return { bits: corrected, corrections };
272
+ }
273
+ /** @param {Uint8Array} bytes */
274
+ function bytesToText(bytes) {
275
+ try {
276
+ return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
277
+ }
278
+ catch {
279
+ return new TextDecoder('latin1').decode(bytes);
280
+ }
281
+ }
282
+ /**
283
+ * Decode a square Aztec symbol with one bit per module and no quiet zone.
284
+ * The matrix must already be oriented with the mode message at the top.
285
+ *
286
+ * @param {import('../core/bit-matrix.js').BitMatrix} matrix
287
+ * @returns {{text: string, bytes: Uint8Array, compact: boolean, layers: number, corrections: number, eccPercent: number}}
288
+ */
289
+ export function decodeAztec(matrix) {
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
+ };
326
+ }
@@ -0,0 +1,251 @@
1
+ /*!
2
+ * Sythos Barcode Suite
3
+ *
4
+ * MIT License
5
+ *
6
+ * Copyright (c) 2026 Sythos
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all
16
+ * copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
26
+ * SPDX-License-Identifier: MIT
27
+ *
28
+ * Original work. No code from any other barcode implementation.
29
+ */
30
+ /**
31
+ * Aztec image detection.
32
+ *
33
+ * Aztec has no finder pattern at its outer border. Its reliable geometric
34
+ * anchor is instead the alternating square bull's-eye in the centre: five
35
+ * rings in Compact symbols, seven rings in Full symbols. The detector finds
36
+ * isolated central modules, verifies those rings at module centres, then
37
+ * samples each legal symbol dimension. The decoder is deliberately the final
38
+ * arbiter: its mode-message Reed--Solomon check rejects accidental concentric
39
+ * artwork and tells us which of the compact/full dimensions is real.
40
+ *
41
+ * Sampling uses a quadrilateral, not a cropped bitmap, so the detected
42
+ * rotation is corrected before decoding. The ring search covers arbitrary
43
+ * in-plane rotations (four-degree coarse search; at normal camera scales its
44
+ * positional error remains well inside a module). The optional inverse pass
45
+ * supports light modules on a dark field.
46
+ *
47
+ * @module aztec/detector
48
+ */
49
+ import { NotFoundError } from '../core/errors.js';
50
+ import { sampleQuad } from '../image/grid-sampler.js';
51
+ import { decodeAztec } from './decoder.js';
52
+ /** @typedef {{x:number, y:number}} Point */
53
+ /** @typedef {{corners: Point[], dimension: number, compact: boolean, moduleSize: number, matrix: import('../core/bit-matrix.js').BitMatrix}} Detection */
54
+ // Compact: 11 + 4 layers. Full symbols add reference-grid rows/columns every
55
+ // 15 modules measured from their central 14-module base, not every 15 layers.
56
+ const DIMENSIONS = [
57
+ ...[1, 2, 3, 4].map((layers) => ({ compact: true, dimension: 11 + 4 * layers })),
58
+ ...Array.from({ length: 32 }, (_, index) => {
59
+ const layers = index + 1;
60
+ return { compact: false, dimension: 15 + 4 * layers + 2 * Math.floor((2 * layers + 6) / 15) };
61
+ }),
62
+ ];
63
+ function pixel(image, x, y) {
64
+ const ix = Math.round(x);
65
+ const iy = Math.round(y);
66
+ return ix >= 0 && iy >= 0 && ix < image.width && iy < image.height && image.get(ix, iy);
67
+ }
68
+ /** Connected components of either polarity, retaining only plausible modules. */
69
+ function components(image, value) {
70
+ const seen = new Uint8Array(image.width * image.height);
71
+ const out = [];
72
+ const maximumArea = Math.max(4, Math.floor(image.width * image.height * 0.08));
73
+ for (let y = 0; y < image.height; y++)
74
+ for (let x = 0; x < image.width; x++) {
75
+ const start = y * image.width + x;
76
+ if (seen[start] || image.get(x, y) !== value)
77
+ continue;
78
+ const xs = [x];
79
+ const ys = [y];
80
+ seen[start] = 1;
81
+ let head = 0;
82
+ let minX = x;
83
+ let maxX = x;
84
+ let minY = y;
85
+ let maxY = y;
86
+ while (head < xs.length) {
87
+ const px = xs[head];
88
+ const py = ys[head++];
89
+ if (px < minX)
90
+ minX = px;
91
+ if (px > maxX)
92
+ maxX = px;
93
+ if (py < minY)
94
+ minY = py;
95
+ if (py > maxY)
96
+ maxY = py;
97
+ for (const [nx, ny] of [[px - 1, py], [px + 1, py], [px, py - 1], [px, py + 1]]) {
98
+ if (nx < 0 || ny < 0 || nx >= image.width || ny >= image.height)
99
+ continue;
100
+ const at = ny * image.width + nx;
101
+ if (!seen[at] && image.get(nx, ny) === value) {
102
+ seen[at] = 1;
103
+ xs.push(nx);
104
+ ys.push(ny);
105
+ }
106
+ }
107
+ }
108
+ const width = maxX - minX + 1;
109
+ const height = maxY - minY + 1;
110
+ const area = width * height;
111
+ // The central module is solid and approximately square. This filter is
112
+ // intentionally permissive because a rotated raster module is diamond-ish.
113
+ if (xs.length <= maximumArea && Math.abs(width - height) <= Math.max(1, Math.ceil(Math.max(width, height) * 0.35)) &&
114
+ xs.length >= area * 0.45) {
115
+ out.push({ x: (minX + maxX) / 2, y: (minY + maxY) / 2, width, height, pixels: xs.length });
116
+ }
117
+ }
118
+ return out.sort((a, b) => b.pixels - a.pixels).slice(0, 2000);
119
+ }
120
+ function expectedDark(ring, inverted) {
121
+ return inverted ? (ring & 1) === 1 : (ring & 1) === 0;
122
+ }
123
+ /** Score one square bull's-eye at an angle and a candidate module pitch. */
124
+ function ringScore(image, centre, pitch, angle, inverted, rings) {
125
+ const cos = Math.cos(angle);
126
+ const sin = Math.sin(angle);
127
+ let correct = 0;
128
+ let total = 0;
129
+ for (let ring = 0; ring < rings; ring++) {
130
+ const wanted = expectedDark(ring, inverted);
131
+ for (let j = -ring; j <= ring; j++)
132
+ for (let i = -ring; i <= ring; i++) {
133
+ if (ring && Math.abs(i) !== ring && Math.abs(j) !== ring)
134
+ continue;
135
+ const x = centre.x + (i * cos - j * sin) * pitch;
136
+ const y = centre.y + (i * sin + j * cos) * pitch;
137
+ if (pixel(image, x, y) === wanted)
138
+ correct++;
139
+ total++;
140
+ }
141
+ }
142
+ return correct / total;
143
+ }
144
+ function rotateCorners(corners, turn) {
145
+ return corners.slice(turn).concat(corners.slice(0, turn));
146
+ }
147
+ function invert(matrix) {
148
+ const out = matrix.clone();
149
+ for (let y = 0; y < out.height; y++)
150
+ for (let x = 0; x < out.width; x++)
151
+ out.flip(x, y);
152
+ return out;
153
+ }
154
+ function cornersFor(centre, pitch, angle, dimension) {
155
+ const half = dimension * pitch / 2;
156
+ const cos = Math.cos(angle);
157
+ const sin = Math.sin(angle);
158
+ const point = (x, y) => ({ x: centre.x + x * cos - y * sin, y: centre.y + x * sin + y * cos });
159
+ return [point(-half, -half), point(half, -half), point(half, half), point(-half, half)];
160
+ }
161
+ /**
162
+ * Find an Aztec symbol in a binarized image.
163
+ *
164
+ * The returned matrix is in the orientation accepted by the Aztec decoder.
165
+ * A valid mode message is required before a geometric candidate is returned,
166
+ * making false positives from decorative concentric squares very unlikely.
167
+ *
168
+ * @param {import('../core/bit-matrix.js').BitMatrix} binaryImage Set bit = dark.
169
+ * @returns {Detection | null}
170
+ */
171
+ export function detectAztec(binaryImage) {
172
+ if (!binaryImage || !binaryImage.width || !binaryImage.height) {
173
+ throw new NotFoundError('detectAztec: no image supplied');
174
+ }
175
+ const candidates = [];
176
+ for (const inverted of [false, true]) {
177
+ for (const core of components(binaryImage, !inverted)) {
178
+ // A non-rotated one-module component directly gives its pitch. For
179
+ // rotated modules its bounding box grows by |sin| + |cos|, compensated
180
+ // below for every tested angle.
181
+ for (let degrees = 0; degrees < 180; degrees += 4) {
182
+ const angle = degrees * Math.PI / 180;
183
+ const scale = Math.abs(Math.cos(angle)) + Math.abs(Math.sin(angle));
184
+ const pitch = ((core.width + core.height) / 2) / scale;
185
+ if (pitch < 0.8)
186
+ continue;
187
+ // Test Full first: its seven rings also exclude Compact candidates.
188
+ const fullScore = ringScore(binaryImage, core, pitch, angle, inverted, 7);
189
+ const rings = fullScore >= 0.88 ? 7 : 5;
190
+ const score = rings === 7 ? fullScore : ringScore(binaryImage, core, pitch, angle, inverted, 5);
191
+ if (score < 0.91)
192
+ continue;
193
+ const symbolKinds = rings === 7 ? DIMENSIONS.filter((item) => !item.compact) : DIMENSIONS.filter((item) => item.compact);
194
+ for (const kind of symbolKinds) {
195
+ const baseCorners = cornersFor(core, pitch, angle, kind.dimension);
196
+ for (let turn = 0; turn < 4; turn++) {
197
+ const corners = rotateCorners(baseCorners, turn);
198
+ let matrix;
199
+ try {
200
+ matrix = sampleQuad(binaryImage, kind.dimension, corners);
201
+ }
202
+ catch (e) {
203
+ continue;
204
+ }
205
+ if (inverted)
206
+ matrix = invert(matrix);
207
+ try {
208
+ // The decoder verifies the mode-message ECC and exact geometry.
209
+ // We do not expose its result here so callers can use pure
210
+ // detection without treating payload decoding as an API contract.
211
+ decodeAztec(matrix);
212
+ candidates.push({ corners, dimension: kind.dimension, compact: kind.compact,
213
+ moduleSize: pitch, matrix, score });
214
+ }
215
+ catch (e) { /* Not an Aztec mode message at this dimension. */ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ }
221
+ candidates.sort((a, b) => b.score - a.score || b.moduleSize - a.moduleSize);
222
+ const best = candidates[0];
223
+ if (!best)
224
+ return null;
225
+ delete best.score;
226
+ return best;
227
+ }
228
+ /**
229
+ * Detect then decode an Aztec symbol. Detection failure is a normal result for
230
+ * images without an Aztec code, therefore invalid candidates return null.
231
+ *
232
+ * @param {import('../core/bit-matrix.js').BitMatrix} binaryImage
233
+ * @returns {(import('./decoder.js').DecodeResult & {corners: Point[]}) | null}
234
+ */
235
+ export function detectAndDecodeAztec(binaryImage) {
236
+ let detection;
237
+ try {
238
+ detection = detectAztec(binaryImage);
239
+ }
240
+ catch (e) {
241
+ return null;
242
+ }
243
+ if (!detection)
244
+ return null;
245
+ try {
246
+ return Object.assign({ corners: detection.corners }, decodeAztec(detection.matrix));
247
+ }
248
+ catch (e) {
249
+ return null;
250
+ }
251
+ }