react-native-nitro-zxing 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (423) hide show
  1. package/README.md +34 -0
  2. package/VisionCameraZxing.podspec +48 -0
  3. package/android/CMakeLists.txt +43 -0
  4. package/android/build.gradle +150 -0
  5. package/android/fix-prefab.gradle +51 -0
  6. package/android/gradle.properties +5 -0
  7. package/android/src/main/AndroidManifest.xml +3 -0
  8. package/android/src/main/cpp/cpp-adapter.cpp +7 -0
  9. package/android/src/main/java/com/margelo/nitro/camera/zxing/VisionCameraZxingPackage.kt +21 -0
  10. package/cpp/BarcodeValueTypeClassifier.cpp +70 -0
  11. package/cpp/BarcodeValueTypeClassifier.hpp +14 -0
  12. package/cpp/FrameImageView.cpp +75 -0
  13. package/cpp/FrameImageView.hpp +34 -0
  14. package/cpp/HybridBarcode.cpp +59 -0
  15. package/cpp/HybridBarcode.hpp +26 -0
  16. package/cpp/HybridBarcodeScanner.cpp +121 -0
  17. package/cpp/HybridBarcodeScanner.hpp +26 -0
  18. package/cpp/HybridBarcodeScannerFactory.cpp +11 -0
  19. package/cpp/HybridBarcodeScannerFactory.hpp +14 -0
  20. package/cpp/ImageDownscaler.cpp +34 -0
  21. package/cpp/ImageDownscaler.hpp +21 -0
  22. package/cpp/ZXingDecoder.cpp +189 -0
  23. package/cpp/ZXingDecoder.hpp +72 -0
  24. package/cpp/zxing-core/LICENSE +202 -0
  25. package/cpp/zxing-core/README.md +156 -0
  26. package/cpp/zxing-core/core/CMakeLists.txt +784 -0
  27. package/cpp/zxing-core/core/Version.h.in +28 -0
  28. package/cpp/zxing-core/core/ZXingConfig.cmake.in +9 -0
  29. package/cpp/zxing-core/core/src/Barcode.cpp +255 -0
  30. package/cpp/zxing-core/core/src/Barcode.h +191 -0
  31. package/cpp/zxing-core/core/src/BarcodeData.h +100 -0
  32. package/cpp/zxing-core/core/src/BarcodeFormat.cpp +286 -0
  33. package/cpp/zxing-core/core/src/BarcodeFormat.h +272 -0
  34. package/cpp/zxing-core/core/src/BinaryBitmap.cpp +111 -0
  35. package/cpp/zxing-core/core/src/BinaryBitmap.h +66 -0
  36. package/cpp/zxing-core/core/src/BitArray.cpp +38 -0
  37. package/cpp/zxing-core/core/src/BitArray.h +181 -0
  38. package/cpp/zxing-core/core/src/BitMatrix.cpp +175 -0
  39. package/cpp/zxing-core/core/src/BitMatrix.h +199 -0
  40. package/cpp/zxing-core/core/src/BitMatrixCursor.h +253 -0
  41. package/cpp/zxing-core/core/src/BitMatrixIO.cpp +101 -0
  42. package/cpp/zxing-core/core/src/BitMatrixIO.h +21 -0
  43. package/cpp/zxing-core/core/src/BitSource.cpp +77 -0
  44. package/cpp/zxing-core/core/src/BitSource.h +72 -0
  45. package/cpp/zxing-core/core/src/ByteArray.h +42 -0
  46. package/cpp/zxing-core/core/src/CharacterSet.cpp +78 -0
  47. package/cpp/zxing-core/core/src/CharacterSet.h +58 -0
  48. package/cpp/zxing-core/core/src/ConcentricFinder.cpp +312 -0
  49. package/cpp/zxing-core/core/src/ConcentricFinder.h +156 -0
  50. package/cpp/zxing-core/core/src/Content.cpp +471 -0
  51. package/cpp/zxing-core/core/src/Content.h +82 -0
  52. package/cpp/zxing-core/core/src/ContentType.h +19 -0
  53. package/cpp/zxing-core/core/src/CreateBarcode.cpp +490 -0
  54. package/cpp/zxing-core/core/src/CreateBarcode.h +132 -0
  55. package/cpp/zxing-core/core/src/DecoderResult.h +92 -0
  56. package/cpp/zxing-core/core/src/DetectorResult.h +44 -0
  57. package/cpp/zxing-core/core/src/ECI.cpp +81 -0
  58. package/cpp/zxing-core/core/src/ECI.h +78 -0
  59. package/cpp/zxing-core/core/src/Error.cpp +29 -0
  60. package/cpp/zxing-core/core/src/Error.h +79 -0
  61. package/cpp/zxing-core/core/src/Flags.h +165 -0
  62. package/cpp/zxing-core/core/src/GTIN.cpp +253 -0
  63. package/cpp/zxing-core/core/src/GTIN.h +58 -0
  64. package/cpp/zxing-core/core/src/GlobalHistogramBinarizer.cpp +197 -0
  65. package/cpp/zxing-core/core/src/GlobalHistogramBinarizer.h +34 -0
  66. package/cpp/zxing-core/core/src/GridSampler.cpp +124 -0
  67. package/cpp/zxing-core/core/src/GridSampler.h +59 -0
  68. package/cpp/zxing-core/core/src/HRI.cpp +343 -0
  69. package/cpp/zxing-core/core/src/HRI.h +16 -0
  70. package/cpp/zxing-core/core/src/HybridBinarizer.cpp +315 -0
  71. package/cpp/zxing-core/core/src/HybridBinarizer.h +40 -0
  72. package/cpp/zxing-core/core/src/ImageView.h +168 -0
  73. package/cpp/zxing-core/core/src/JSON.cpp +154 -0
  74. package/cpp/zxing-core/core/src/JSON.h +66 -0
  75. package/cpp/zxing-core/core/src/LocalGrid.cpp +242 -0
  76. package/cpp/zxing-core/core/src/LocalGrid.h +91 -0
  77. package/cpp/zxing-core/core/src/LogMatrix.h +105 -0
  78. package/cpp/zxing-core/core/src/Matrix.h +125 -0
  79. package/cpp/zxing-core/core/src/MultiFormatReader.cpp +107 -0
  80. package/cpp/zxing-core/core/src/MultiFormatReader.h +34 -0
  81. package/cpp/zxing-core/core/src/MultiFormatWriter.cpp +111 -0
  82. package/cpp/zxing-core/core/src/MultiFormatWriter.h +62 -0
  83. package/cpp/zxing-core/core/src/Pattern.h +472 -0
  84. package/cpp/zxing-core/core/src/PerspectiveTransform.cpp +81 -0
  85. package/cpp/zxing-core/core/src/PerspectiveTransform.h +47 -0
  86. package/cpp/zxing-core/core/src/Point.h +185 -0
  87. package/cpp/zxing-core/core/src/Quadrilateral.h +215 -0
  88. package/cpp/zxing-core/core/src/Range.h +112 -0
  89. package/cpp/zxing-core/core/src/ReadBarcode.cpp +335 -0
  90. package/cpp/zxing-core/core/src/ReadBarcode.h +33 -0
  91. package/cpp/zxing-core/core/src/Reader.h +32 -0
  92. package/cpp/zxing-core/core/src/ReaderOptions.h +210 -0
  93. package/cpp/zxing-core/core/src/ReedSolomon.cpp +100 -0
  94. package/cpp/zxing-core/core/src/ReedSolomon.h +66 -0
  95. package/cpp/zxing-core/core/src/RegressionLine.h +161 -0
  96. package/cpp/zxing-core/core/src/ResultPoint.cpp +20 -0
  97. package/cpp/zxing-core/core/src/ResultPoint.h +35 -0
  98. package/cpp/zxing-core/core/src/StdGenerator.h +121 -0
  99. package/cpp/zxing-core/core/src/StdPrint.h +38 -0
  100. package/cpp/zxing-core/core/src/StdScope.h +55 -0
  101. package/cpp/zxing-core/core/src/StructuredAppend.h +19 -0
  102. package/cpp/zxing-core/core/src/SymbologyIdentifier.h +29 -0
  103. package/cpp/zxing-core/core/src/TextDecoder.cpp +59 -0
  104. package/cpp/zxing-core/core/src/TextDecoder.h +23 -0
  105. package/cpp/zxing-core/core/src/TextEncoder.cpp +75 -0
  106. package/cpp/zxing-core/core/src/TextEncoder.h +31 -0
  107. package/cpp/zxing-core/core/src/ThresholdBinarizer.h +58 -0
  108. package/cpp/zxing-core/core/src/TritMatrix.h +29 -0
  109. package/cpp/zxing-core/core/src/Utf.cpp +276 -0
  110. package/cpp/zxing-core/core/src/Utf.h +26 -0
  111. package/cpp/zxing-core/core/src/WhiteRectDetector.cpp +276 -0
  112. package/cpp/zxing-core/core/src/WhiteRectDetector.h +36 -0
  113. package/cpp/zxing-core/core/src/WriteBarcode.cpp +213 -0
  114. package/cpp/zxing-core/core/src/WriteBarcode.h +72 -0
  115. package/cpp/zxing-core/core/src/ZXAlgorithms.h +353 -0
  116. package/cpp/zxing-core/core/src/ZXConfig.h +17 -0
  117. package/cpp/zxing-core/core/src/ZXTestSupport.h +9 -0
  118. package/cpp/zxing-core/core/src/ZXVersion.h +14 -0
  119. package/cpp/zxing-core/core/src/ZXingC.cpp +460 -0
  120. package/cpp/zxing-core/core/src/ZXingC.h +296 -0
  121. package/cpp/zxing-core/core/src/ZXingCpp.cpp +18 -0
  122. package/cpp/zxing-core/core/src/ZXingCpp.h +76 -0
  123. package/cpp/zxing-core/core/src/ZXingQt.h +606 -0
  124. package/cpp/zxing-core/core/src/aztec/AZDecoder.cpp +376 -0
  125. package/cpp/zxing-core/core/src/aztec/AZDecoder.h +20 -0
  126. package/cpp/zxing-core/core/src/aztec/AZDetector.cpp +508 -0
  127. package/cpp/zxing-core/core/src/aztec/AZDetector.h +25 -0
  128. package/cpp/zxing-core/core/src/aztec/AZDetectorResult.h +51 -0
  129. package/cpp/zxing-core/core/src/aztec/AZEncoder.cpp +318 -0
  130. package/cpp/zxing-core/core/src/aztec/AZEncoder.h +44 -0
  131. package/cpp/zxing-core/core/src/aztec/AZEncodingState.h +40 -0
  132. package/cpp/zxing-core/core/src/aztec/AZHighLevelEncoder.cpp +377 -0
  133. package/cpp/zxing-core/core/src/aztec/AZHighLevelEncoder.h +36 -0
  134. package/cpp/zxing-core/core/src/aztec/AZReader.cpp +45 -0
  135. package/cpp/zxing-core/core/src/aztec/AZReader.h +21 -0
  136. package/cpp/zxing-core/core/src/aztec/AZToken.cpp +44 -0
  137. package/cpp/zxing-core/core/src/aztec/AZToken.h +39 -0
  138. package/cpp/zxing-core/core/src/aztec/AZWriter.cpp +38 -0
  139. package/cpp/zxing-core/core/src/aztec/AZWriter.h +55 -0
  140. package/cpp/zxing-core/core/src/datamatrix/DMBitLayout.cpp +194 -0
  141. package/cpp/zxing-core/core/src/datamatrix/DMBitLayout.h +21 -0
  142. package/cpp/zxing-core/core/src/datamatrix/DMDataBlock.cpp +63 -0
  143. package/cpp/zxing-core/core/src/datamatrix/DMDataBlock.h +41 -0
  144. package/cpp/zxing-core/core/src/datamatrix/DMDecoder.cpp +457 -0
  145. package/cpp/zxing-core/core/src/datamatrix/DMDecoder.h +19 -0
  146. package/cpp/zxing-core/core/src/datamatrix/DMDetector.cpp +1230 -0
  147. package/cpp/zxing-core/core/src/datamatrix/DMDetector.h +23 -0
  148. package/cpp/zxing-core/core/src/datamatrix/DMECEncoder.cpp +137 -0
  149. package/cpp/zxing-core/core/src/datamatrix/DMECEncoder.h +26 -0
  150. package/cpp/zxing-core/core/src/datamatrix/DMEncoderContext.h +128 -0
  151. package/cpp/zxing-core/core/src/datamatrix/DMHighLevelEncoder.cpp +919 -0
  152. package/cpp/zxing-core/core/src/datamatrix/DMHighLevelEncoder.h +29 -0
  153. package/cpp/zxing-core/core/src/datamatrix/DMReader.cpp +40 -0
  154. package/cpp/zxing-core/core/src/datamatrix/DMReader.h +21 -0
  155. package/cpp/zxing-core/core/src/datamatrix/DMSymbolInfo.cpp +141 -0
  156. package/cpp/zxing-core/core/src/datamatrix/DMSymbolInfo.h +78 -0
  157. package/cpp/zxing-core/core/src/datamatrix/DMSymbolShape.h +17 -0
  158. package/cpp/zxing-core/core/src/datamatrix/DMVersion.cpp +82 -0
  159. package/cpp/zxing-core/core/src/datamatrix/DMVersion.h +76 -0
  160. package/cpp/zxing-core/core/src/datamatrix/DMWriter.cpp +114 -0
  161. package/cpp/zxing-core/core/src/datamatrix/DMWriter.h +62 -0
  162. package/cpp/zxing-core/core/src/librscpp/README.md +65 -0
  163. package/cpp/zxing-core/core/src/librscpp/decode.h +258 -0
  164. package/cpp/zxing-core/core/src/librscpp/encode.h +124 -0
  165. package/cpp/zxing-core/core/src/librscpp/field.h +158 -0
  166. package/cpp/zxing-core/core/src/librscpp/poly.h +194 -0
  167. package/cpp/zxing-core/core/src/libzint/2of5inter.c +1 -0
  168. package/cpp/zxing-core/core/src/libzint/2of5inter_based.c +1 -0
  169. package/cpp/zxing-core/core/src/libzint/aztec.c +1 -0
  170. package/cpp/zxing-core/core/src/libzint/aztec.h +1 -0
  171. package/cpp/zxing-core/core/src/libzint/big5.h +1 -0
  172. package/cpp/zxing-core/core/src/libzint/codabar.c +1 -0
  173. package/cpp/zxing-core/core/src/libzint/code.c +1 -0
  174. package/cpp/zxing-core/core/src/libzint/code128.c +1 -0
  175. package/cpp/zxing-core/core/src/libzint/code128.h +1 -0
  176. package/cpp/zxing-core/core/src/libzint/common.c +1 -0
  177. package/cpp/zxing-core/core/src/libzint/common.h +1 -0
  178. package/cpp/zxing-core/core/src/libzint/dmatrix.c +1 -0
  179. package/cpp/zxing-core/core/src/libzint/dmatrix.h +1 -0
  180. package/cpp/zxing-core/core/src/libzint/dxfilmedge.c +1 -0
  181. package/cpp/zxing-core/core/src/libzint/eci.c +1 -0
  182. package/cpp/zxing-core/core/src/libzint/eci.h +1 -0
  183. package/cpp/zxing-core/core/src/libzint/eci_sb.h +1 -0
  184. package/cpp/zxing-core/core/src/libzint/filemem.c +1 -0
  185. package/cpp/zxing-core/core/src/libzint/filemem.h +1 -0
  186. package/cpp/zxing-core/core/src/libzint/fonts/normal_woff2.h +1 -0
  187. package/cpp/zxing-core/core/src/libzint/fonts/upcean_woff2.h +1 -0
  188. package/cpp/zxing-core/core/src/libzint/gb18030.h +1 -0
  189. package/cpp/zxing-core/core/src/libzint/gb2312.h +1 -0
  190. package/cpp/zxing-core/core/src/libzint/gbk.h +1 -0
  191. package/cpp/zxing-core/core/src/libzint/general_field.c +1 -0
  192. package/cpp/zxing-core/core/src/libzint/general_field.h +1 -0
  193. package/cpp/zxing-core/core/src/libzint/gs1.c +1 -0
  194. package/cpp/zxing-core/core/src/libzint/gs1.h +1 -0
  195. package/cpp/zxing-core/core/src/libzint/gs1_lint.h +1 -0
  196. package/cpp/zxing-core/core/src/libzint/iso3166.h +1 -0
  197. package/cpp/zxing-core/core/src/libzint/iso4217.h +1 -0
  198. package/cpp/zxing-core/core/src/libzint/ksx1001.h +1 -0
  199. package/cpp/zxing-core/core/src/libzint/large.c +1 -0
  200. package/cpp/zxing-core/core/src/libzint/large.h +1 -0
  201. package/cpp/zxing-core/core/src/libzint/library.c +1 -0
  202. package/cpp/zxing-core/core/src/libzint/maxicode.c +1 -0
  203. package/cpp/zxing-core/core/src/libzint/maxicode.h +1 -0
  204. package/cpp/zxing-core/core/src/libzint/medical.c +1 -0
  205. package/cpp/zxing-core/core/src/libzint/output.c +1 -0
  206. package/cpp/zxing-core/core/src/libzint/output.h +1 -0
  207. package/cpp/zxing-core/core/src/libzint/pdf417.c +1 -0
  208. package/cpp/zxing-core/core/src/libzint/pdf417.h +1 -0
  209. package/cpp/zxing-core/core/src/libzint/pdf417_tabs.h +1 -0
  210. package/cpp/zxing-core/core/src/libzint/qr.c +1 -0
  211. package/cpp/zxing-core/core/src/libzint/qr.h +1 -0
  212. package/cpp/zxing-core/core/src/libzint/raster.c +1 -0
  213. package/cpp/zxing-core/core/src/libzint/raster_font.h +1 -0
  214. package/cpp/zxing-core/core/src/libzint/reedsol.c +1 -0
  215. package/cpp/zxing-core/core/src/libzint/reedsol.h +1 -0
  216. package/cpp/zxing-core/core/src/libzint/reedsol_logs.h +1 -0
  217. package/cpp/zxing-core/core/src/libzint/rss.c +1 -0
  218. package/cpp/zxing-core/core/src/libzint/rss.h +1 -0
  219. package/cpp/zxing-core/core/src/libzint/sjis.h +1 -0
  220. package/cpp/zxing-core/core/src/libzint/stubs.c +137 -0
  221. package/cpp/zxing-core/core/src/libzint/svg.c +1 -0
  222. package/cpp/zxing-core/core/src/libzint/telepen.c +1 -0
  223. package/cpp/zxing-core/core/src/libzint/upcean.c +1 -0
  224. package/cpp/zxing-core/core/src/libzint/vector.c +1 -0
  225. package/cpp/zxing-core/core/src/libzint/zfiletypes.h +1 -0
  226. package/cpp/zxing-core/core/src/libzint/zint.h +1 -0
  227. package/cpp/zxing-core/core/src/libzint/zintconfig.h +1 -0
  228. package/cpp/zxing-core/core/src/libzueci/README.md +11 -0
  229. package/cpp/zxing-core/core/src/libzueci/zueci.c +1718 -0
  230. package/cpp/zxing-core/core/src/libzueci/zueci.h +179 -0
  231. package/cpp/zxing-core/core/src/libzueci/zueci_big5.h +3884 -0
  232. package/cpp/zxing-core/core/src/libzueci/zueci_common.h +31 -0
  233. package/cpp/zxing-core/core/src/libzueci/zueci_gb18030.h +264 -0
  234. package/cpp/zxing-core/core/src/libzueci/zueci_gb2312.h +2381 -0
  235. package/cpp/zxing-core/core/src/libzueci/zueci_gbk.h +4047 -0
  236. package/cpp/zxing-core/core/src/libzueci/zueci_ksx1001.h +2932 -0
  237. package/cpp/zxing-core/core/src/libzueci/zueci_sb.h +1112 -0
  238. package/cpp/zxing-core/core/src/libzueci/zueci_sjis.h +2286 -0
  239. package/cpp/zxing-core/core/src/maxicode/MCBitMatrixParser.cpp +68 -0
  240. package/cpp/zxing-core/core/src/maxicode/MCBitMatrixParser.h +30 -0
  241. package/cpp/zxing-core/core/src/maxicode/MCDecoder.cpp +329 -0
  242. package/cpp/zxing-core/core/src/maxicode/MCDecoder.h +19 -0
  243. package/cpp/zxing-core/core/src/maxicode/MCReader.cpp +65 -0
  244. package/cpp/zxing-core/core/src/maxicode/MCReader.h +21 -0
  245. package/cpp/zxing-core/core/src/oned/ODCodabarReader.cpp +102 -0
  246. package/cpp/zxing-core/core/src/oned/ODCodabarReader.h +21 -0
  247. package/cpp/zxing-core/core/src/oned/ODCodabarWriter.cpp +136 -0
  248. package/cpp/zxing-core/core/src/oned/ODCodabarWriter.h +34 -0
  249. package/cpp/zxing-core/core/src/oned/ODCode128Patterns.h +130 -0
  250. package/cpp/zxing-core/core/src/oned/ODCode128Reader.cpp +236 -0
  251. package/cpp/zxing-core/core/src/oned/ODCode128Reader.h +21 -0
  252. package/cpp/zxing-core/core/src/oned/ODCode128Writer.cpp +261 -0
  253. package/cpp/zxing-core/core/src/oned/ODCode128Writer.h +34 -0
  254. package/cpp/zxing-core/core/src/oned/ODCode39Reader.cpp +213 -0
  255. package/cpp/zxing-core/core/src/oned/ODCode39Reader.h +26 -0
  256. package/cpp/zxing-core/core/src/oned/ODCode39Writer.cpp +176 -0
  257. package/cpp/zxing-core/core/src/oned/ODCode39Writer.h +34 -0
  258. package/cpp/zxing-core/core/src/oned/ODCode93Patterns.h +80 -0
  259. package/cpp/zxing-core/core/src/oned/ODCode93Reader.cpp +112 -0
  260. package/cpp/zxing-core/core/src/oned/ODCode93Reader.h +21 -0
  261. package/cpp/zxing-core/core/src/oned/ODCode93Writer.cpp +192 -0
  262. package/cpp/zxing-core/core/src/oned/ODCode93Writer.h +32 -0
  263. package/cpp/zxing-core/core/src/oned/ODDXFilmEdgeReader.cpp +246 -0
  264. package/cpp/zxing-core/core/src/oned/ODDXFilmEdgeReader.h +26 -0
  265. package/cpp/zxing-core/core/src/oned/ODDataBarCommon.cpp +172 -0
  266. package/cpp/zxing-core/core/src/oned/ODDataBarCommon.h +204 -0
  267. package/cpp/zxing-core/core/src/oned/ODDataBarExpandedBitDecoder.cpp +253 -0
  268. package/cpp/zxing-core/core/src/oned/ODDataBarExpandedBitDecoder.h +19 -0
  269. package/cpp/zxing-core/core/src/oned/ODDataBarExpandedReader.cpp +383 -0
  270. package/cpp/zxing-core/core/src/oned/ODDataBarExpandedReader.h +25 -0
  271. package/cpp/zxing-core/core/src/oned/ODDataBarLimitedReader.cpp +163 -0
  272. package/cpp/zxing-core/core/src/oned/ODDataBarLimitedReader.h +23 -0
  273. package/cpp/zxing-core/core/src/oned/ODDataBarReader.cpp +240 -0
  274. package/cpp/zxing-core/core/src/oned/ODDataBarReader.h +25 -0
  275. package/cpp/zxing-core/core/src/oned/ODEAN13Writer.cpp +62 -0
  276. package/cpp/zxing-core/core/src/oned/ODEAN13Writer.h +34 -0
  277. package/cpp/zxing-core/core/src/oned/ODEAN8Writer.cpp +51 -0
  278. package/cpp/zxing-core/core/src/oned/ODEAN8Writer.h +34 -0
  279. package/cpp/zxing-core/core/src/oned/ODITFReader.cpp +97 -0
  280. package/cpp/zxing-core/core/src/oned/ODITFReader.h +33 -0
  281. package/cpp/zxing-core/core/src/oned/ODITFWriter.cpp +78 -0
  282. package/cpp/zxing-core/core/src/oned/ODITFWriter.h +34 -0
  283. package/cpp/zxing-core/core/src/oned/ODMultiUPCEANReader.cpp +323 -0
  284. package/cpp/zxing-core/core/src/oned/ODMultiUPCEANReader.h +32 -0
  285. package/cpp/zxing-core/core/src/oned/ODReader.cpp +259 -0
  286. package/cpp/zxing-core/core/src/oned/ODReader.h +35 -0
  287. package/cpp/zxing-core/core/src/oned/ODRowReader.h +222 -0
  288. package/cpp/zxing-core/core/src/oned/ODTelepenReader.cpp +199 -0
  289. package/cpp/zxing-core/core/src/oned/ODTelepenReader.h +25 -0
  290. package/cpp/zxing-core/core/src/oned/ODUPCAWriter.cpp +33 -0
  291. package/cpp/zxing-core/core/src/oned/ODUPCAWriter.h +34 -0
  292. package/cpp/zxing-core/core/src/oned/ODUPCEANCommon.cpp +80 -0
  293. package/cpp/zxing-core/core/src/oned/ODUPCEANCommon.h +129 -0
  294. package/cpp/zxing-core/core/src/oned/ODUPCEWriter.cpp +56 -0
  295. package/cpp/zxing-core/core/src/oned/ODUPCEWriter.h +34 -0
  296. package/cpp/zxing-core/core/src/oned/ODWriterHelper.cpp +39 -0
  297. package/cpp/zxing-core/core/src/oned/ODWriterHelper.h +48 -0
  298. package/cpp/zxing-core/core/src/pdf417/MicroPDFReader.cpp +796 -0
  299. package/cpp/zxing-core/core/src/pdf417/MicroPDFReader.h +23 -0
  300. package/cpp/zxing-core/core/src/pdf417/PDF417.cpp +85 -0
  301. package/cpp/zxing-core/core/src/pdf417/PDF417.h +81 -0
  302. package/cpp/zxing-core/core/src/pdf417/PDFBarcodeMetadata.h +53 -0
  303. package/cpp/zxing-core/core/src/pdf417/PDFBarcodeValue.cpp +48 -0
  304. package/cpp/zxing-core/core/src/pdf417/PDFBarcodeValue.h +38 -0
  305. package/cpp/zxing-core/core/src/pdf417/PDFBoundingBox.cpp +116 -0
  306. package/cpp/zxing-core/core/src/pdf417/PDFBoundingBox.h +75 -0
  307. package/cpp/zxing-core/core/src/pdf417/PDFCodeword.h +71 -0
  308. package/cpp/zxing-core/core/src/pdf417/PDFCodewordDecoder.cpp +588 -0
  309. package/cpp/zxing-core/core/src/pdf417/PDFCodewordDecoder.h +41 -0
  310. package/cpp/zxing-core/core/src/pdf417/PDFCompaction.h +20 -0
  311. package/cpp/zxing-core/core/src/pdf417/PDFCustomData.h +32 -0
  312. package/cpp/zxing-core/core/src/pdf417/PDFDecoder.cpp +725 -0
  313. package/cpp/zxing-core/core/src/pdf417/PDFDecoder.h +20 -0
  314. package/cpp/zxing-core/core/src/pdf417/PDFDetectionResult.cpp +247 -0
  315. package/cpp/zxing-core/core/src/pdf417/PDFDetectionResult.h +74 -0
  316. package/cpp/zxing-core/core/src/pdf417/PDFDetectionResultColumn.cpp +321 -0
  317. package/cpp/zxing-core/core/src/pdf417/PDFDetectionResultColumn.h +83 -0
  318. package/cpp/zxing-core/core/src/pdf417/PDFDetector.cpp +371 -0
  319. package/cpp/zxing-core/core/src/pdf417/PDFDetector.h +45 -0
  320. package/cpp/zxing-core/core/src/pdf417/PDFEncoder.cpp +570 -0
  321. package/cpp/zxing-core/core/src/pdf417/PDFEncoder.h +182 -0
  322. package/cpp/zxing-core/core/src/pdf417/PDFHighLevelEncoder.cpp +570 -0
  323. package/cpp/zxing-core/core/src/pdf417/PDFHighLevelEncoder.h +32 -0
  324. package/cpp/zxing-core/core/src/pdf417/PDFReader.cpp +333 -0
  325. package/cpp/zxing-core/core/src/pdf417/PDFReader.h +28 -0
  326. package/cpp/zxing-core/core/src/pdf417/PDFScanningDecoder.cpp +559 -0
  327. package/cpp/zxing-core/core/src/pdf417/PDFScanningDecoder.h +41 -0
  328. package/cpp/zxing-core/core/src/pdf417/PDFWriter.cpp +170 -0
  329. package/cpp/zxing-core/core/src/pdf417/PDFWriter.h +74 -0
  330. package/cpp/zxing-core/core/src/pdf417/ZXBigInteger.cpp +623 -0
  331. package/cpp/zxing-core/core/src/pdf417/ZXBigInteger.h +81 -0
  332. package/cpp/zxing-core/core/src/pdf417/ZXNullable.h +105 -0
  333. package/cpp/zxing-core/core/src/qrcode/QRBitMatrixParser.cpp +294 -0
  334. package/cpp/zxing-core/core/src/qrcode/QRBitMatrixParser.h +41 -0
  335. package/cpp/zxing-core/core/src/qrcode/QRCodecMode.cpp +95 -0
  336. package/cpp/zxing-core/core/src/qrcode/QRCodecMode.h +59 -0
  337. package/cpp/zxing-core/core/src/qrcode/QRDataBlock.cpp +93 -0
  338. package/cpp/zxing-core/core/src/qrcode/QRDataBlock.h +52 -0
  339. package/cpp/zxing-core/core/src/qrcode/QRDataMask.h +50 -0
  340. package/cpp/zxing-core/core/src/qrcode/QRDecoder.cpp +359 -0
  341. package/cpp/zxing-core/core/src/qrcode/QRDecoder.h +19 -0
  342. package/cpp/zxing-core/core/src/qrcode/QRDetector.cpp +920 -0
  343. package/cpp/zxing-core/core/src/qrcode/QRDetector.h +45 -0
  344. package/cpp/zxing-core/core/src/qrcode/QRECB.h +52 -0
  345. package/cpp/zxing-core/core/src/qrcode/QREncodeResult.h +33 -0
  346. package/cpp/zxing-core/core/src/qrcode/QREncoder.cpp +568 -0
  347. package/cpp/zxing-core/core/src/qrcode/QREncoder.h +21 -0
  348. package/cpp/zxing-core/core/src/qrcode/QRErrorCorrectionLevel.cpp +51 -0
  349. package/cpp/zxing-core/core/src/qrcode/QRErrorCorrectionLevel.h +39 -0
  350. package/cpp/zxing-core/core/src/qrcode/QRFormatInformation.cpp +160 -0
  351. package/cpp/zxing-core/core/src/qrcode/QRFormatInformation.h +61 -0
  352. package/cpp/zxing-core/core/src/qrcode/QRMaskUtil.cpp +156 -0
  353. package/cpp/zxing-core/core/src/qrcode/QRMaskUtil.h +15 -0
  354. package/cpp/zxing-core/core/src/qrcode/QRMatrixUtil.cpp +318 -0
  355. package/cpp/zxing-core/core/src/qrcode/QRMatrixUtil.h +25 -0
  356. package/cpp/zxing-core/core/src/qrcode/QRReader.cpp +149 -0
  357. package/cpp/zxing-core/core/src/qrcode/QRReader.h +21 -0
  358. package/cpp/zxing-core/core/src/qrcode/QRVersion.cpp +754 -0
  359. package/cpp/zxing-core/core/src/qrcode/QRVersion.h +127 -0
  360. package/cpp/zxing-core/core/src/qrcode/QRWriter.cpp +51 -0
  361. package/cpp/zxing-core/core/src/qrcode/QRWriter.h +74 -0
  362. package/cpp/zxing-core/core/version.rc.in +34 -0
  363. package/cpp/zxing-core/core/zxing.pc.in +8 -0
  364. package/cpp/zxing-core/wrappers/ios/README.md +25 -0
  365. package/cpp/zxing-core/wrappers/ios/Sources/Wrapper/Version.h +29 -0
  366. package/cpp/zxing-core/zxing-cpp.podspec +45 -0
  367. package/lib/factory.d.ts +10 -0
  368. package/lib/factory.js +12 -0
  369. package/lib/index.d.ts +9 -0
  370. package/lib/index.js +9 -0
  371. package/lib/specs/Barcode.nitro.d.ts +63 -0
  372. package/lib/specs/Barcode.nitro.js +1 -0
  373. package/lib/specs/BarcodeFormat.d.ts +11 -0
  374. package/lib/specs/BarcodeFormat.js +1 -0
  375. package/lib/specs/BarcodeScanner.nitro.d.ts +89 -0
  376. package/lib/specs/BarcodeScanner.nitro.js +1 -0
  377. package/lib/specs/BarcodeScannerFactory.nitro.d.ts +26 -0
  378. package/lib/specs/BarcodeScannerFactory.nitro.js +1 -0
  379. package/lib/specs/BarcodeValueType.d.ts +9 -0
  380. package/lib/specs/BarcodeValueType.js +1 -0
  381. package/lib/specs/Point.d.ts +14 -0
  382. package/lib/specs/Point.js +1 -0
  383. package/lib/specs/Rect.d.ts +22 -0
  384. package/lib/specs/Rect.js +1 -0
  385. package/lib/useBarcodeScanner.d.ts +23 -0
  386. package/lib/useBarcodeScanner.js +25 -0
  387. package/nitro.json +20 -0
  388. package/nitrogen/generated/.gitattributes +1 -0
  389. package/nitrogen/generated/android/VisionCameraZxing+autolinking.cmake +83 -0
  390. package/nitrogen/generated/android/VisionCameraZxing+autolinking.gradle +27 -0
  391. package/nitrogen/generated/android/VisionCameraZxingOnLoad.cpp +49 -0
  392. package/nitrogen/generated/android/VisionCameraZxingOnLoad.hpp +34 -0
  393. package/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/zxing/VisionCameraZxingOnLoad.kt +35 -0
  394. package/nitrogen/generated/ios/VisionCameraZxing+autolinking.rb +62 -0
  395. package/nitrogen/generated/ios/VisionCameraZxing-Swift-Cxx-Bridge.cpp +17 -0
  396. package/nitrogen/generated/ios/VisionCameraZxing-Swift-Cxx-Bridge.hpp +27 -0
  397. package/nitrogen/generated/ios/VisionCameraZxing-Swift-Cxx-Umbrella.hpp +38 -0
  398. package/nitrogen/generated/ios/VisionCameraZxingAutolinking.mm +35 -0
  399. package/nitrogen/generated/ios/VisionCameraZxingAutolinking.swift +16 -0
  400. package/nitrogen/generated/shared/c++/BarcodeFormat.hpp +124 -0
  401. package/nitrogen/generated/shared/c++/BarcodeScannerOptions.hpp +85 -0
  402. package/nitrogen/generated/shared/c++/BarcodeValueType.hpp +120 -0
  403. package/nitrogen/generated/shared/c++/HybridBarcodeScannerSpec.cpp +23 -0
  404. package/nitrogen/generated/shared/c++/HybridBarcodeScannerSpec.hpp +74 -0
  405. package/nitrogen/generated/shared/c++/HybridBarcodeSpec.cpp +27 -0
  406. package/nitrogen/generated/shared/c++/HybridBarcodeSpec.hpp +82 -0
  407. package/nitrogen/generated/shared/c++/HybridZXingBarcodeScannerFactorySpec.cpp +21 -0
  408. package/nitrogen/generated/shared/c++/HybridZXingBarcodeScannerFactorySpec.hpp +67 -0
  409. package/nitrogen/generated/shared/c++/Point.hpp +87 -0
  410. package/nitrogen/generated/shared/c++/Rect.hpp +95 -0
  411. package/nitrogen/generated/shared/c++/TargetBarcodeFormat.hpp +124 -0
  412. package/package.json +108 -0
  413. package/react-native.config.js +16 -0
  414. package/src/factory.ts +26 -0
  415. package/src/index.ts +9 -0
  416. package/src/specs/Barcode.nitro.ts +70 -0
  417. package/src/specs/BarcodeFormat.ts +31 -0
  418. package/src/specs/BarcodeScanner.nitro.ts +91 -0
  419. package/src/specs/BarcodeScannerFactory.nitro.ts +27 -0
  420. package/src/specs/BarcodeValueType.ts +25 -0
  421. package/src/specs/Point.ts +14 -0
  422. package/src/specs/Rect.ts +22 -0
  423. package/src/useBarcodeScanner.ts +36 -0
@@ -0,0 +1,920 @@
1
+ /*
2
+ * Copyright 2016 Nu-book Inc.
3
+ * Copyright 2016 ZXing authors
4
+ * Copyright 2020 Axel Waggershauser
5
+ * Copyright 2023 gitlost
6
+ */
7
+ // SPDX-License-Identifier: Apache-2.0
8
+
9
+ #include "QRDetector.h"
10
+
11
+ #include "BitArray.h"
12
+ #include "BitMatrix.h"
13
+ #include "BitMatrixCursor.h"
14
+ #include "ConcentricFinder.h"
15
+ #include "GridSampler.h"
16
+ #include "LogMatrix.h"
17
+ #include "Matrix.h"
18
+ #include "Pattern.h"
19
+ #include "QRFormatInformation.h"
20
+ #include "QRVersion.h"
21
+ #include "Quadrilateral.h"
22
+ #include "RegressionLine.h"
23
+
24
+ #include <algorithm>
25
+ #include <cmath>
26
+ #include <cstdlib>
27
+ #include <iterator>
28
+ #include <map>
29
+ #include <numbers>
30
+ #include <utility>
31
+ #include <vector>
32
+
33
+ #ifdef PRINT_DEBUG
34
+ #include "BitMatrixIO.h"
35
+ #else
36
+ #define printf(...){}
37
+ #endif
38
+
39
+ namespace ZXing::QRCode {
40
+
41
+ constexpr auto PATTERN = FixedPattern<5, 7>{1, 1, 3, 1, 1};
42
+ constexpr bool E2E = true;
43
+
44
+ PatternView FindPattern(const PatternView& view)
45
+ {
46
+ return FindLeftGuard<PATTERN.size()>(view, PATTERN.size(), [](const PatternView& view, int spaceInPixel) {
47
+ // perform a fast plausibility test for 1:1:3:1:1 pattern
48
+ if (view[2] < 3 || view[2] < 2 * std::max(view[0], view[4]) || view[2] < std::max(view[1], view[3]))
49
+ return 0.;
50
+ return IsPattern<E2E>(view, PATTERN, spaceInPixel, 0.1); // the requires 4, here we accept almost 0
51
+ });
52
+ }
53
+
54
+ std::vector<ConcentricPattern> FindFinderPatterns(const BitMatrix& image, bool tryHarder)
55
+ {
56
+ constexpr int MIN_SKIP = 3; // 1 pixel/module times 3 modules/center
57
+ constexpr int MAX_MODULES_FAST = 20 * 4 + 17; // support up to version 20 for mobile clients
58
+
59
+ // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the
60
+ // image, and then account for the center being 3 modules in size. This gives the smallest
61
+ // number of pixels the center could be, so skip this often. When trying harder, look for all
62
+ // QR versions regardless of how dense they are.
63
+ int height = image.height();
64
+ int skip = (3 * height) / (4 * MAX_MODULES_FAST);
65
+ if (skip < MIN_SKIP || tryHarder)
66
+ skip = MIN_SKIP;
67
+
68
+ std::vector<ConcentricPattern> res;
69
+ [[maybe_unused]] int N = 0;
70
+ PatternRow row;
71
+
72
+ for (int y = skip - 1; y < height; y += skip) {
73
+ GetPatternRow(image, y, row, false);
74
+ PatternView next = row;
75
+
76
+ while (next = FindPattern(next), next.isValid()) {
77
+ PointF p(next.pixelsInFront() + next[0] + next[1] + next[2] / 2.0, y + 0.5);
78
+
79
+ // make sure p is not 'inside' an already found pattern area
80
+ if (FindIf(res, [p](const auto& old) { return distance(p, old) < old.size / 2; }) == res.end()) {
81
+ log(p);
82
+ N++;
83
+ auto width = 2 * next.sum(); // the factor 2 allows for a maximum aspect ratio of 4:1 due to perspective distortion
84
+ auto pattern = LocateConcentricPattern<E2E>(image, PATTERN, p, width);
85
+ if (pattern) {
86
+ log(*pattern, 3);
87
+ log(*pattern + PointF(.2, 0), 3);
88
+ log(*pattern - PointF(.2, 0), 3);
89
+ log(*pattern + PointF(0, .2), 3);
90
+ log(*pattern - PointF(0, .2), 3);
91
+ assert(image.get(pattern->x, pattern->y));
92
+ res.push_back(*pattern);
93
+ }
94
+ }
95
+
96
+ next.skipPair();
97
+ next.skipPair();
98
+ next.extend();
99
+ }
100
+ }
101
+
102
+ printf("FPs: FindPattern: %d, LocateConcentric: %d\n", N, Size(res));
103
+
104
+ return res;
105
+ }
106
+
107
+ /**
108
+ * @brief GenerateFinderPatternSets
109
+ * @param patterns list of ConcentricPattern objects, i.e. found finder pattern squares
110
+ * @return list of plausible finder pattern sets, sorted by decreasing plausibility
111
+ */
112
+ FinderPatternSets GenerateFinderPatternSets(FinderPatterns& patterns)
113
+ {
114
+ std::sort(patterns.begin(), patterns.end(), [](const auto& a, const auto& b) { return a.size > b.size; });
115
+
116
+ struct {
117
+ int rejSize = 0;
118
+ int nearFPs = 0;
119
+ int candidates = 0;
120
+ int rejLegRatio = 0;
121
+ int rejModCount = 0;
122
+ int rejAngle = 0;
123
+ int accepted = 0;
124
+ } stats;
125
+
126
+ auto sets = std::multimap<double, FinderPatternSet>();
127
+ auto squaredDistance = [](const auto* a, const auto* b) {
128
+ // The scaling of the distance based on the b/a size ratio is a very coarse compensation for the shortening effect of
129
+ // the camera projection on slanted symbols. The fact that the size of the finder pattern is proportional to the
130
+ // distance from the camera is used here. This approximation only works if a < b < 2*a (see below).
131
+ // Test image: fix-finderpattern-order.jpg
132
+ // Originally, I scaled the squaredDistance with the (b/a)^2 ratio but that could skew the cosine calculation
133
+ // below too much, resulting in the acceptance of degenerate triangles (a, b and c on a line).
134
+ return dot((*a - *b), (*a - *b)) * double(b->size) / a->size;
135
+ };
136
+ const double cosUpper = std::cos(60. / 180 * std::numbers::pi);
137
+ const double cosLower = std::cos(120. / 180 * std::numbers::pi);
138
+
139
+ #if 1
140
+ if (Size(patterns) < 3)
141
+ return {};
142
+
143
+ // Bin finder patterns into spatial bins to reduce the number of candidates to compare with geometry heuristics below.
144
+ // For each finder pattern, we only compare it to patterns in bins that are not further away than the largest symbol (177 modules)
145
+ // can occupy. We search from inside out and stop after we found a limited number of candidates which reduces the complexity from
146
+ // O(n^3) to O(n). E.g. a sample with 140 small QRCodes has 420 finder patterns, which results in 12 million candidates to process
147
+ // while with the binning, we only compare 20k candidates -> total runtime goes from 190ms to 9ms.
148
+ auto [mX, MX] = std::ranges::minmax_element(patterns, {}, &PointF::x);
149
+ auto [mY, MY] = std::ranges::minmax_element(patterns, {}, &PointF::y);
150
+ int medianSize = patterns[Size(patterns) / 2].size;
151
+ int binSize = std::max(32, medianSize * 3); // 3 for minimum symbol size of 21 modules
152
+ Matrix<std::vector<int>> bins(std::ceil((MX->x - mX->x + 1) / binSize), std::ceil((MY->y - mY->y + 1) / binSize));
153
+
154
+ printf("medianSize=%d binSize=%d bins=(%dx%d) ", medianSize, binSize, bins.width(), bins.height());
155
+
156
+ auto bin = [&](PointF p) {
157
+ return PointI(std::clamp(int((p.x - mX->x) / binSize), 0, bins.width() - 1),
158
+ std::clamp(int((p.y - mY->y) / binSize), 0, bins.height() - 1));
159
+ };
160
+
161
+ for (int idx = 0; idx < Size(patterns); ++idx)
162
+ bins(bin(patterns[idx])).push_back(idx);
163
+
164
+ constexpr double maxModuleCount = 177 * 1.5;
165
+ // manually tuned to work with e.g. https://github.com/eventualbuddha/zedbar/blob/f0d9d9fa6158c108a21f7cde42c0339fb32dff69/examples/qr-code-140-grid02.jpg
166
+ constexpr size_t maxCandidates = 15;
167
+ auto candidates = std::vector<int>();
168
+ candidates.reserve(maxCandidates * 2);
169
+
170
+ int nbPatterns = Size(patterns);
171
+ bool useFilters = nbPatterns > 5; // for a small number of patterns, we apply no/less filters (like size ratio, leg ratio, angle)
172
+ for (int i = 0; i < nbPatterns - 2; i++) {
173
+ const auto* c0 = &patterns[i];
174
+ double maxDistToC = c0->size / 7.0 * maxModuleCount;
175
+ auto cBin = bin(*c0);
176
+ int binRadius = std::ceil(maxDistToC / binSize);
177
+ candidates.clear();
178
+
179
+ for (auto d : Spiral(binRadius)) {
180
+ auto b = cBin + d;
181
+ if (b.x < 0 || b.x >= bins.width() || b.y < 0 || b.y >= bins.height())
182
+ continue;
183
+
184
+ for (int idx : bins(b)) {
185
+ if (idx <= i)
186
+ continue;
187
+
188
+ const auto* p = &patterns[idx];
189
+ if (useFilters && c0->size > p->size * 2 + 2) {
190
+ stats.rejSize++;
191
+ continue;
192
+ }
193
+
194
+ candidates.push_back(idx);
195
+ stats.nearFPs++;
196
+ }
197
+
198
+ if (candidates.size() >= maxCandidates)
199
+ break;
200
+ }
201
+
202
+ for (int u = 0; u < Size(candidates) - 1; ++u) {
203
+ for (int v = u + 1; v < Size(candidates); ++v) {
204
+ stats.candidates++;
205
+ int j = candidates[u];
206
+ int k = candidates[v];
207
+
208
+ // patterns is sorted descending by size (the larger the pattern, the less likely is it noise),
209
+ // but the geometry/size heuristics below assume a <= b <= c in size. Keep that convention by remapping indices.
210
+ const auto* a = &patterns[std::max(j, k)];
211
+ const auto* b = &patterns[std::min(j, k)];
212
+ const auto* c = c0;
213
+
214
+ #else
215
+
216
+ int nbPatterns = Size(patterns);
217
+ for (int i = 0; i < nbPatterns - 2; i++) {
218
+ for (int j = i + 1; j < nbPatterns - 1; j++) {
219
+ for (int k = j + 1; k < nbPatterns - 0; k++) {
220
+ stats.candidates++;
221
+ // patterns is sorted descending by size (the larger the pattern, the less likely is it noise),
222
+ // but the geometry/size heuristics below assume a <= b <= c in size. Keep that convention by remapping i/j/k.
223
+ const auto* a = &patterns[k];
224
+ const auto* b = &patterns[j];
225
+ const auto* c = &patterns[i];
226
+
227
+ // if the pattern sizes are too different to be part of the same symbol, skip this
228
+ // and the rest of the innermost loop (sorted list)
229
+ if (c->size > a->size * 2)
230
+ break;
231
+ #endif
232
+
233
+ // Orders the three points in an order [A,B,C] such that AB is less than AC
234
+ // and BC is less than AC, and the angle between BC and BA is less than 180 degrees.
235
+
236
+ auto distAB2 = squaredDistance(a, b);
237
+ auto distBC2 = squaredDistance(b, c);
238
+ auto distAC2 = squaredDistance(a, c);
239
+
240
+ if (distBC2 >= distAB2 && distBC2 >= distAC2) {
241
+ std::swap(a, b);
242
+ std::swap(distBC2, distAC2);
243
+ } else if (distAB2 >= distAC2 && distAB2 >= distBC2) {
244
+ std::swap(b, c);
245
+ std::swap(distAB2, distAC2);
246
+ }
247
+
248
+ // Make sure distAB and distBC don't differ more than reasonable:
249
+ // equivalent to distAB > 2 * distBC || distBC > 2 * distAB but avoids sqrt.
250
+ // TODO: make sure the constant 2 is not too conservative for reasonably tilted symbols
251
+ if (useFilters && (distAB2 > 4 * distBC2 || distBC2 > 4 * distAB2)) {
252
+ stats.rejLegRatio++;
253
+ continue;
254
+ }
255
+
256
+ auto distAB = std::sqrt(distAB2);
257
+ auto distBC = std::sqrt(distBC2);
258
+
259
+ // Estimate the module count and ignore this set if it can not result in a valid decoding
260
+ if (auto moduleCount = (distAB + distBC) / (2 * (a->size + b->size + c->size) / (3 * 7.f)) + 7;
261
+ moduleCount < 21 * 0.9 || moduleCount > 177 * 1.5) { // moduleCount may be overestimated, see above
262
+ stats.rejModCount++;
263
+ continue;
264
+ }
265
+
266
+ // Make sure the angle between AB and BC does not deviate from 90° too much
267
+ auto cosAB_BC = (distAB2 + distBC2 - distAC2) / (2 * distAB * distBC);
268
+ if (useFilters && (std::isnan(cosAB_BC) || cosAB_BC > cosUpper || cosAB_BC < cosLower)) {
269
+ stats.rejAngle++;
270
+ continue;
271
+ }
272
+
273
+ // a^2 + b^2 = c^2 (Pythagorean theorem), and a = b (isosceles triangle).
274
+ // Since any right triangle satisfies the formula c^2 - b^2 - a^2 = 0,
275
+ // we need to check both two equal sides separately.
276
+ // The value of |c^2 - 2 * b^2| + |c^2 - 2 * a^2| increases as dissimilarity
277
+ // from isosceles right triangle.
278
+ // double score = (std::abs(distAC2 - 2 * distAB2) + std::abs(distAC2 - 2 * distBC2));
279
+
280
+ // Calculate a score that is used to determine wich sets are most likely to be actual finder pattern sets,
281
+ // the smaller the better. Prefer finder patterns that are close to each with similar distances to each other.
282
+ // Note: experiments incorporating cosAB_BC or the difference of the finder pattern sizes did not yield better results.
283
+ auto score = distAB + distBC + std::abs(distAB - distBC);
284
+
285
+ // arbitrarily limit the number of potential sets
286
+ // (this has performance implications while limiting the maximal number of detected symbols)
287
+ const size_t setSizeLimit = 256;
288
+ if (sets.size() < setSizeLimit || sets.crbegin()->first > score) {
289
+ // Use cross product to figure out whether A and C are correct or flipped.
290
+ // This asks whether BC x BA has a positive z component, which is the arrangement
291
+ // we want for A, B, C. If it's negative then swap A and C.
292
+ if (cross(*c - *b, *a - *b) < 0)
293
+ std::swap(a, c);
294
+
295
+ sets.emplace(score, FinderPatternSet{*a, *b, *c});
296
+ if (sets.size() > setSizeLimit)
297
+ sets.erase(std::prev(sets.end()));
298
+ stats.accepted++;
299
+ }
300
+ }
301
+ }
302
+ }
303
+
304
+ printf("rejectSize=%d nearFPs=%d candidates=%d rejectLeg=%d rejectMod=%d rejectAng=%d accepted=%d\n", stats.rejSize,
305
+ stats.nearFPs, stats.candidates, stats.rejLegRatio, stats.rejModCount, stats.rejAngle, stats.accepted);
306
+
307
+ // convert from multimap to vector
308
+ FinderPatternSets res;
309
+ res.reserve(sets.size());
310
+ for (auto& [d, s] : sets)
311
+ res.push_back(s);
312
+
313
+ printf("FPSets: %d\n", Size(res));
314
+
315
+ return res;
316
+ }
317
+
318
+ static double EstimateModuleSize(const BitMatrix& image, ConcentricPattern a, ConcentricPattern b)
319
+ {
320
+ BitMatrixCursorF cur(image, a, b - a);
321
+ assert(cur.isBlack());
322
+
323
+ auto pattern = ReadSymmetricPattern<5>(cur, a.size * 2);
324
+ if (!pattern || !IsPattern<true>(*pattern, PATTERN))
325
+ return -1;
326
+
327
+ return (2 * Reduce(*pattern) - (*pattern)[0] - (*pattern)[4]) / 12.0 * length(cur.d);
328
+ }
329
+
330
+ struct DimensionEstimate
331
+ {
332
+ int dim = 0;
333
+ double ms = 0;
334
+ int err = 4;
335
+ };
336
+
337
+ static DimensionEstimate EstimateDimension(const BitMatrix& image, ConcentricPattern a, ConcentricPattern b)
338
+ {
339
+ auto ms_a = EstimateModuleSize(image, a, b);
340
+ auto ms_b = EstimateModuleSize(image, b, a);
341
+
342
+ if (ms_a < 0 || ms_b < 0)
343
+ return {};
344
+
345
+ auto moduleSize = (ms_a + ms_b) / 2;
346
+
347
+ int dimension = narrow_cast<int>(std::lround(distance(a, b) / moduleSize) + 7);
348
+ int error = 1 - (dimension % 4);
349
+
350
+ return {dimension + error, moduleSize, std::abs(error)};
351
+ }
352
+
353
+ static RegressionLine TraceLine(const BitMatrix& image, PointF p, PointF d, int edge)
354
+ {
355
+ BitMatrixCursorF cur(image, p, d - p);
356
+ RegressionLine line;
357
+ line.setDirectionInward(cur.back());
358
+
359
+ // collect points inside the black line -> backup on 3rd edge
360
+ cur.stepToEdge(edge, 0, edge == 3);
361
+ if (edge == 3)
362
+ cur.turnBack();
363
+
364
+ auto curI = BitMatrixCursorI(image, PointI(cur.p), PointI(mainDirection(cur.d)));
365
+ // make sure curI positioned such that the white->black edge is directly behind
366
+ // Test image: fix-traceline.jpg
367
+ while (curI.isIn() && !curI.edgeAtBack()) {
368
+ if (curI.edgeAtLeft())
369
+ curI.turnRight();
370
+ else if (curI.edgeAtRight())
371
+ curI.turnLeft();
372
+ else
373
+ curI.step(-1);
374
+ }
375
+
376
+ for (auto dir : {Direction::LEFT, Direction::RIGHT}) {
377
+ auto c = BitMatrixCursorI(image, curI.p, curI.direction(dir));
378
+ auto stepCount = static_cast<int>(maxAbsComponent(cur.p - p));
379
+ do {
380
+ line.add(centered(c.p));
381
+ } while (--stepCount > 0 && c.stepAlongEdge(dir, true));
382
+ }
383
+
384
+ line.evaluate(1.0, true);
385
+
386
+ for (auto p : line.points())
387
+ log(p, 2);
388
+
389
+ return line;
390
+ }
391
+
392
+ // estimate how tilted the symbol is (return value between 1 and 2, see also above)
393
+ static double EstimateTilt(const FinderPatternSet& fp)
394
+ {
395
+ int min = std::min({fp.bl.size, fp.tl.size, fp.tr.size});
396
+ int max = std::max({fp.bl.size, fp.tl.size, fp.tr.size});
397
+ return double(max) / min;
398
+ }
399
+
400
+ static PerspectiveTransform Mod2Pix(int dimension, PointF brOffset, QuadrilateralF pix)
401
+ {
402
+ auto quad = Rectangle(dimension, dimension, 3.5);
403
+ quad[2] = quad[2] - brOffset;
404
+ return {quad, pix};
405
+ }
406
+
407
+ static std::optional<PointF> LocateAlignmentPattern(const BitMatrix& image, int moduleSize, PointF estimate)
408
+ {
409
+ log(estimate, 4);
410
+
411
+ for (auto d : {PointF{0, 0}, {0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1},
412
+ #if 1
413
+ }) {
414
+ #else
415
+ {0, -2}, {0, 2}, {-2, 0}, {2, 0}, {-1, -2}, {1, -2}, {-1, 2}, {1, 2}, {-2, -1}, {-2, 1}, {2, -1}, {2, 1}}) {
416
+ #endif
417
+ auto p = estimate + moduleSize * 2.25 * d;
418
+ if (!image.isIn(p))
419
+ continue;
420
+
421
+ auto cor = CenterOfRing(image, PointI(p), moduleSize * 3, 1, false);
422
+
423
+ // if we did not land on a black pixel the concentric pattern finder will fail
424
+ if (!cor || !image.get(*cor))
425
+ continue;
426
+
427
+ if (auto cor1 = CenterOfRing(image, PointI(*cor), moduleSize * 2, 1))
428
+ if (auto cor2 = CenterOfRing(image, PointI(*cor), moduleSize * 3, 2))
429
+ if (distance(*cor1, *cor2) < moduleSize / 2 && cor2->size > cor1->size) {
430
+ auto res = (*cor1 + *cor2) / 2;
431
+ log(res, 3);
432
+ return res;
433
+ }
434
+ }
435
+
436
+ return {};
437
+ }
438
+
439
+ static const Version* ReadVersion(const BitMatrix& image, int dimension, const PerspectiveTransform& mod2Pix)
440
+ {
441
+ int bits[2] = {};
442
+
443
+ for (bool mirror : {false, true}) {
444
+ // Read top-right/bottom-left version info: 3 wide by 6 tall (depending on mirrored)
445
+ int versionBits = 0;
446
+ for (int y = 5; y >= 0; --y)
447
+ for (int x = dimension - 9; x >= dimension - 11; --x) {
448
+ auto mod = mirror ? PointI{y, x} : PointI{x, y};
449
+ auto pix = mod2Pix(centered(mod));
450
+ if (!image.isIn(pix))
451
+ versionBits = -1;
452
+ else
453
+ AppendBit(versionBits, image.get(pix));
454
+ log(pix, 3);
455
+ }
456
+ bits[static_cast<int>(mirror)] = versionBits;
457
+ }
458
+
459
+ return Version::DecodeVersionInformation(bits[0], bits[1]);
460
+ }
461
+
462
+ DetectorResults SampleQR(const BitMatrix& image, const FinderPatternSet& fp)
463
+ {
464
+ auto top = EstimateDimension(image, fp.tl, fp.tr);
465
+ auto left = EstimateDimension(image, fp.tl, fp.bl);
466
+
467
+ if (!top.dim && !left.dim)
468
+ co_return;
469
+
470
+ auto best = top.err == left.err ? (top.dim > left.dim ? top : left) : (top.err < left.err ? top : left);
471
+ int dimension = best.dim;
472
+ int moduleSize = static_cast<int>(top.dim == left.dim ? std::midpoint(top.ms, left.ms) : best.ms) + 1;
473
+
474
+ auto br = PointF{-1, -1};
475
+ auto brOffset = PointF{3, 3};
476
+ bool brFound = false;
477
+
478
+ // Everything except version 1 (21 modules) has an alignment pattern. Estimate the center of that by intersecting
479
+ // line extensions of the 1 module wide square around the finder patterns. This could also help with detecting
480
+ // slanted symbols of version 1.
481
+
482
+ // generate 4 lines: outer and inner edge of the 1 module wide black line between the two outer and the inner
483
+ // (tl) finder pattern
484
+ auto bl2 = TraceLine(image, fp.bl, fp.tl, 2);
485
+ auto bl3 = TraceLine(image, fp.bl, fp.tl, 3);
486
+ auto tr2 = TraceLine(image, fp.tr, fp.tl, 2);
487
+ auto tr3 = TraceLine(image, fp.tr, fp.tl, 3);
488
+
489
+ if (bl2.isValid() && tr2.isValid() && bl3.isValid() && tr3.isValid()) {
490
+ // intersect both outer and inner line pairs and take the center point between the two intersection points
491
+ auto brInter = (intersect(bl2, tr2) + intersect(bl3, tr3)) / 2;
492
+ log(brInter, 3);
493
+
494
+ if (dimension > 21)
495
+ if (auto brCP = LocateAlignmentPattern(image, moduleSize, brInter))
496
+ br = *brCP;
497
+
498
+ brFound = image.isIn(br);
499
+ if (!brFound)
500
+ br = brInter;
501
+ }
502
+
503
+ // otherwise or if finder patterns are not square, the simple estimation used by upstream is used as a best guess fallback
504
+ if (!image.isIn(br) || !FitSquareToPoints(image, fp.bl, fp.bl.size, 2, false)) {
505
+ br = fp.tr - fp.tl + fp.bl;
506
+ brOffset = PointF(0, 0);
507
+ }
508
+
509
+ log(br, 3);
510
+ auto mod2Pix = Mod2Pix(dimension, brOffset, {fp.tl, fp.tr, br, fp.bl});
511
+
512
+ if( dimension >= Version::SymbolSize(7, Type::Model2).x) {
513
+ auto version = ReadVersion(image, dimension, mod2Pix);
514
+
515
+ // if the version bits are garbage -> discard the detection
516
+ if (!version || std::min(std::abs(version->dimension() - top.dim), std::abs(version->dimension() - left.dim)) > 8)
517
+ co_return;
518
+ if (version->dimension() != dimension) {
519
+ printf("update dimension: %d -> %d\n", dimension, version->dimension());
520
+ dimension = version->dimension();
521
+ mod2Pix = Mod2Pix(dimension, brOffset, {fp.tl, fp.tr, br, fp.bl});
522
+ }
523
+
524
+ #if 1 // finding and evaluating the alignment patterns to enable a tiled sampling of the symbol
525
+
526
+ auto& apM = version->alignmentPatternCenters(); // alignment pattern positions in modules
527
+ auto apP = Matrix<std::optional<PointF>>(Size(apM), Size(apM)); // found/guessed alignment pattern positions in pixels
528
+ const int N = Size(apM) - 1;
529
+
530
+ // project the alignment pattern at module coordinates x/y to pixel coordinate based on current mod2Pix
531
+ auto projectM2P = [&mod2Pix, &apM](int x, int y) { return mod2Pix(centered(PointI(apM[x], apM[y]))); };
532
+
533
+ auto findInnerCornerOfConcentricPattern = [&image, &apP, &projectM2P](int x, int y, const ConcentricPattern& fp) {
534
+ auto pc = *apP.set(x, y, projectM2P(x, y));
535
+ if (auto fpQuad = FindConcentricPatternCorners(image, fp, fp.size, 2))
536
+ for (auto c : *fpQuad)
537
+ if (distance(c, pc) < fp.size / 2)
538
+ apP.set(x, y, c);
539
+ };
540
+
541
+ findInnerCornerOfConcentricPattern(0, 0, fp.tl);
542
+ findInnerCornerOfConcentricPattern(0, N, fp.bl);
543
+ findInnerCornerOfConcentricPattern(N, 0, fp.tr);
544
+
545
+ auto bestGuessAPP = [&](int x, int y){
546
+ if (auto p = apP(x, y))
547
+ return *p;
548
+ return projectM2P(x, y);
549
+ };
550
+
551
+ for (int y = 0; y <= N; ++y)
552
+ for (int x = 0; x <= N; ++x) {
553
+ if (apP(x, y))
554
+ continue;
555
+
556
+ PointF guessed =
557
+ x * y == 0 ? bestGuessAPP(x, y) : bestGuessAPP(x - 1, y) + bestGuessAPP(x, y - 1) - bestGuessAPP(x - 1, y - 1);
558
+ if (auto found = LocateAlignmentPattern(image, moduleSize, guessed))
559
+ apP.set(x, y, found);
560
+ }
561
+
562
+ // go over the whole set of alignment patters again and try to fill any remaining gap by using available neighbors as guides
563
+ for (int y = 0; y <= N; ++y)
564
+ for (int x = 0; x <= N; ++x) {
565
+ if (apP(x, y))
566
+ continue;
567
+
568
+ // find the two closest valid alignment pattern pixel positions both horizontally and vertically
569
+ std::vector<PointF> hori, verti;
570
+ for (int i = 2; i < 2 * N + 2 && Size(hori) < 2; ++i) {
571
+ int xi = x + i / 2 * (i%2 ? 1 : -1);
572
+ if (0 <= xi && xi <= N && apP(xi, y))
573
+ hori.push_back(*apP(xi, y));
574
+ }
575
+ for (int i = 2; i < 2 * N + 2 && Size(verti) < 2; ++i) {
576
+ int yi = y + i / 2 * (i%2 ? 1 : -1);
577
+ if (0 <= yi && yi <= N && apP(x, yi))
578
+ verti.push_back(*apP(x, yi));
579
+ }
580
+
581
+ // if we found 2 each, intersect the two lines that are formed by connecting the point pairs
582
+ if (Size(hori) == 2 && Size(verti) == 2) {
583
+ auto guessed = intersect(RegressionLine(hori[0], hori[1]), RegressionLine(verti[0], verti[1]));
584
+ auto found = LocateAlignmentPattern(image, moduleSize, guessed);
585
+ // search again near that intersection and if the search fails, use the intersection
586
+ if (!found) printf("location guessed at %dx%d\n", x, y);
587
+ apP.set(x, y, found ? *found : guessed);
588
+ }
589
+ }
590
+
591
+ if (auto c = apP.get(N, N))
592
+ mod2Pix = Mod2Pix(dimension, PointF(3, 3), {fp.tl, fp.tr, *c, fp.bl});
593
+
594
+ co_yield SampleGrid(image, dimension, dimension, mod2Pix, std::move(apP), apM, apM);
595
+ #endif
596
+ }
597
+ else
598
+ co_yield SampleGrid(image, dimension, dimension, mod2Pix);
599
+
600
+ // if we have not found the br alignment pattern, we check
601
+ // a) if we have a version 1 symbol and tried and failed with the intersection of the trace lines (#1086), or
602
+ // b) if the symbol is almost level and the resolution of the RegressionLines is not sufficient (#199 and estimate-tilt.jpg)
603
+ // we then try the fallback method of sampling the symbol with the br corner extrapolated from the other three corners.
604
+ if (!brFound
605
+ && ((dimension == 21 && brOffset != PointF(0, 0))
606
+ || (EstimateTilt(fp) < 1.1 && !(bl2.isHighRes() && bl3.isHighRes() && tr2.isHighRes() && tr3.isHighRes()))))
607
+ {
608
+ mod2Pix = Mod2Pix(dimension, PointF(0, 0), {fp.tl, fp.tr, fp.tr - fp.tl + fp.bl, fp.bl});
609
+ co_yield SampleGrid(image, dimension, dimension, mod2Pix);
610
+ }
611
+ }
612
+
613
+ /**
614
+ * This method detects a code in a "pure" image -- that is, pure monochrome image
615
+ * which contains only an unrotated, unskewed, image of a code, with some white border
616
+ * around it. This is a specialized method that works exceptionally fast in this special
617
+ * case.
618
+ */
619
+ DetectorResult DetectPureQR(const BitMatrix& image)
620
+ {
621
+ using Pattern = std::array<PatternView::value_type, PATTERN.size()>;
622
+
623
+ #ifdef PRINT_DEBUG
624
+ SaveAsPBM(image, "weg.pbm");
625
+ #endif
626
+
627
+ constexpr int MIN_MODULES = Version::SymbolSize(1, Type::Model2).x;
628
+
629
+ int left, top, width, height;
630
+ if (!image.findBoundingBox(left, top, width, height, MIN_MODULES) || std::abs(width - height) > 1)
631
+ return {};
632
+ auto pos = Rectangle<PointI>(left, top, width, height);
633
+
634
+ const PointI &tl = pos.topLeft(), &tr = pos.topRight(), &bl = pos.bottomLeft();
635
+ Pattern diagonal;
636
+ // allow corners be moved one pixel inside to accommodate for possible aliasing artifacts
637
+ for (auto [p, d] : {std::pair(tl, PointI{1, 1}), {tr, {-1, 1}}, {bl, {1, -1}}}) {
638
+ diagonal = BitMatrixCursorI(image, p, d).readPatternFromBlack<Pattern>(1, width / 3 + 1);
639
+ if (!IsPattern(diagonal, PATTERN))
640
+ return {};
641
+ }
642
+
643
+ PointF::value_t fpWidth = Reduce(diagonal);
644
+ auto dimension =
645
+ EstimateDimension(image, {tl + fpWidth / 2 * PointF(1, 1), fpWidth}, {tr + fpWidth / 2 * PointF(-1, 1), fpWidth}).dim;
646
+
647
+ float moduleSize = float(width) / dimension;
648
+ if (!Version::IsValidSize({dimension, dimension}, Type::Model2) ||
649
+ !image.isIn(PointF{left + moduleSize / 2 + (dimension - 1) * moduleSize,
650
+ top + moduleSize / 2 + (dimension - 1) * moduleSize}))
651
+ return {};
652
+
653
+ #ifdef PRINT_DEBUG
654
+ LogMatrix log;
655
+ LogMatrixWriter lmw(log, image, 5, "grid2.pnm");
656
+ for (int y = 0; y < dimension; y++)
657
+ for (int x = 0; x < dimension; x++)
658
+ log(PointF(left + (x + .5f) * moduleSize, top + (y + .5f) * moduleSize));
659
+ #endif
660
+
661
+ // Now just read off the bits (this is a crop + subsample)
662
+ return {Deflate(image, dimension, dimension, top + moduleSize / 2, left + moduleSize / 2, moduleSize), std::move(pos)};
663
+ }
664
+
665
+ DetectorResult DetectPureMQR(const BitMatrix& image)
666
+ {
667
+ using Pattern = std::array<PatternView::value_type, PATTERN.size()>;
668
+
669
+ constexpr int MIN_MODULES = Version::SymbolSize(1, Type::Micro).x;
670
+
671
+ int left, top, width, height;
672
+ if (!image.findBoundingBox(left, top, width, height, MIN_MODULES) || std::abs(width - height) > 1)
673
+ return {};
674
+
675
+ // allow corners be moved one pixel inside to accommodate for possible aliasing artifacts
676
+ auto diagonal = BitMatrixCursorI(image, {left, top}, {1, 1}).readPatternFromBlack<Pattern>(1);
677
+ if (!IsPattern(diagonal, PATTERN))
678
+ return {};
679
+
680
+ auto fpWidth = Reduce(diagonal);
681
+ float moduleSize = float(fpWidth) / 7;
682
+ int dimension = narrow_cast<int>(std::lround(width / moduleSize));
683
+
684
+ if (!Version::IsValidSize({dimension, dimension}, Type::Micro) ||
685
+ !image.isIn(PointF{left + moduleSize / 2 + (dimension - 1) * moduleSize,
686
+ top + moduleSize / 2 + (dimension - 1) * moduleSize}))
687
+ return {};
688
+
689
+ #ifdef PRINT_DEBUG
690
+ LogMatrix log;
691
+ LogMatrixWriter lmw(log, image, 5, "grid2.pnm");
692
+ for (int y = 0; y < dimension; y++)
693
+ for (int x = 0; x < dimension; x++)
694
+ log(PointF(left + (x + .5f) * moduleSize, top + (y + .5f) * moduleSize));
695
+ #endif
696
+
697
+ // Now just read off the bits (this is a crop + subsample)
698
+ return {Deflate(image, dimension, dimension, top + moduleSize / 2, left + moduleSize / 2, moduleSize),
699
+ Rectangle<PointI>(left, top, width, height)};
700
+ }
701
+
702
+ DetectorResult DetectPureRMQR(const BitMatrix& image)
703
+ {
704
+ constexpr auto SUBPATTERN = FixedPattern<4, 4>{1, 1, 1, 1};
705
+ constexpr auto TIMINGPATTERN = FixedPattern<10, 10>{1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
706
+
707
+ using Pattern = std::array<PatternView::value_type, PATTERN.size()>;
708
+ using SubPattern = std::array<PatternView::value_type, SUBPATTERN.size()>;
709
+ using TimingPattern = std::array<PatternView::value_type, TIMINGPATTERN.size()>;
710
+
711
+ #ifdef PRINT_DEBUG
712
+ SaveAsPBM(image, "weg.pbm");
713
+ #endif
714
+
715
+ constexpr int MIN_MODULES = Version::SymbolSize(1, Type::rMQR).y;
716
+
717
+ int left, top, width, height;
718
+ if (!image.findBoundingBox(left, top, width, height, MIN_MODULES) || height >= width)
719
+ return {};
720
+ auto pos = Rectangle<PointI>(left, top, width, height);
721
+
722
+ const PointI &tl = pos.topLeft(), &tr = pos.topRight(), &bl = pos.bottomLeft(), &br = pos.bottomRight();
723
+
724
+ // allow corners be moved one pixel inside to accommodate for possible aliasing artifacts
725
+ auto diagonal = BitMatrixCursorI(image, tl, {1, 1}).readPatternFromBlack<Pattern>(1);
726
+ if (!IsPattern(diagonal, PATTERN))
727
+ return {};
728
+
729
+ // Finder sub pattern
730
+ auto subdiagonal = BitMatrixCursorI(image, br, {-1, -1}).readPatternFromBlack<SubPattern>(1);
731
+ if (!IsPattern(subdiagonal, SUBPATTERN))
732
+ return {};
733
+
734
+ float moduleSize = Reduce(diagonal) + Reduce(subdiagonal);
735
+
736
+ // Horizontal timing patterns
737
+ for (auto [p, d] : {std::pair(tr, PointI{-1, 0}), {bl, {1, 0}}, {tl, {1, 0}}, {br, {-1, 0}}}) {
738
+ auto cur = BitMatrixCursorI(image, p, d);
739
+ // skip corner / finder / sub pattern edge
740
+ cur.stepToEdge(2 + cur.isWhite());
741
+ auto timing = cur.readPattern<TimingPattern>();
742
+ if (!IsPattern(timing, TIMINGPATTERN))
743
+ return {};
744
+ moduleSize += Reduce(timing);
745
+ }
746
+
747
+ moduleSize /= 7 + 4 + 4 * 10; // fp + sub + 4 x timing
748
+ int dimW = narrow_cast<int>(std::lround(width / moduleSize));
749
+ int dimH = narrow_cast<int>(std::lround(height / moduleSize));
750
+
751
+ if (!Version::IsValidSize(PointI{dimW, dimH}, Type::rMQR))
752
+ return {};
753
+
754
+ #ifdef PRINT_DEBUG
755
+ LogMatrix log;
756
+ LogMatrixWriter lmw(log, image, 5, "grid2.pnm");
757
+ for (int y = 0; y < dimH; y++)
758
+ for (int x = 0; x < dimW; x++)
759
+ log(pos.topLeft() + moduleSize * PointF(x + .5f, y + .5f));
760
+ #endif
761
+
762
+ // Now just read off the bits (this is a crop + subsample)
763
+ return {Deflate(image, dimW, dimH, top + moduleSize / 2, left + moduleSize / 2, moduleSize), std::move(pos)};
764
+ }
765
+
766
+ DetectorResult SampleMQR(const BitMatrix& image, const ConcentricPattern& fp)
767
+ {
768
+ auto fpQuad = FindConcentricPatternCorners(image, fp, fp.size, 2);
769
+ if (!fpQuad)
770
+ return {};
771
+
772
+ auto srcQuad = Rectangle(7, 7, 0.5);
773
+
774
+ #if defined(_MSVC_LANG) && !(_MSC_VER >= 1940) // VS2022 17.10 and later work
775
+ // see MSVC issue https://developercommunity.visualstudio.com/t/constexpr-object-is-unable-to-be-used-as/10035065
776
+ static
777
+ #else
778
+ constexpr
779
+ #endif
780
+ const PointI FORMAT_INFO_COORDS[] = {{0, 8}, {1, 8}, {2, 8}, {3, 8}, {4, 8}, {5, 8}, {6, 8}, {7, 8}, {8, 8},
781
+ {8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {8, 1}, {8, 0}};
782
+
783
+ FormatInformation bestFI;
784
+ PerspectiveTransform bestPT;
785
+ BitMatrixCursorF cur(image, {}, {});
786
+
787
+ for (int i = 0; i < 4; ++i) {
788
+ auto mod2Pix = PerspectiveTransform(srcQuad, RotatedCorners(*fpQuad, i));
789
+
790
+ auto check = [&](int i, bool checkOne) {
791
+ auto p = mod2Pix(centered(FORMAT_INFO_COORDS[i]));
792
+ return image.isIn(p) && (!checkOne || image.get(p));
793
+ };
794
+
795
+ // check that we see both innermost timing pattern modules
796
+ if (!check(0, true) || !check(8, false) || !check(16, true))
797
+ continue;
798
+
799
+ int formatInfoBits = 0;
800
+ for (int i = 1; i <= 15; ++i)
801
+ AppendBit(formatInfoBits, cur.blackAt(mod2Pix(centered(FORMAT_INFO_COORDS[i]))));
802
+
803
+ auto fi = FormatInformation::DecodeMQR(formatInfoBits);
804
+ if (fi.hammingDistance < bestFI.hammingDistance) {
805
+ bestFI = fi;
806
+ bestPT = mod2Pix;
807
+ }
808
+ }
809
+
810
+ if (!bestFI.isValid())
811
+ return {};
812
+
813
+ const int dim = Version::SymbolSize(bestFI.microVersion, Type::Micro).x;
814
+
815
+ // check that we are in fact not looking at a corner of a non-micro QRCode symbol
816
+ // we accept at most 1/3rd black pixels in the quite zone (in a QRCode symbol we expect about 1/2).
817
+ int blackPixels = 0;
818
+ for (int i = 0; i < dim; ++i) {
819
+ auto px = bestPT(centered(PointI{i, dim}));
820
+ auto py = bestPT(centered(PointI{dim, i}));
821
+ blackPixels += cur.blackAt(px) && cur.blackAt(py);
822
+ }
823
+ if (blackPixels > 2 * dim / 3)
824
+ return {};
825
+
826
+ return SampleGrid(image, dim, dim, bestPT);
827
+ }
828
+
829
+ DetectorResult SampleRMQR(const BitMatrix& image, const ConcentricPattern& fp)
830
+ {
831
+ auto fpQuad = FindConcentricPatternCorners(image, fp, fp.size, 2);
832
+ if (!fpQuad)
833
+ return {};
834
+
835
+ auto srcQuad = Rectangle(7, 7, 0.5);
836
+
837
+ static const PointI FORMAT_INFO_EDGE_COORDS[] = {{8, 0}, {9, 0}, {10, 0}, {11, 0}};
838
+ static const PointI FORMAT_INFO_COORDS[] = {
839
+ {11, 3}, {11, 2}, {11, 1},
840
+ {10, 5}, {10, 4}, {10, 3}, {10, 2}, {10, 1},
841
+ { 9, 5}, { 9, 4}, { 9, 3}, { 9, 2}, { 9, 1},
842
+ { 8, 5}, { 8, 4}, { 8, 3}, { 8, 2}, { 8, 1},
843
+ };
844
+
845
+ FormatInformation bestFI;
846
+ PerspectiveTransform bestPT;
847
+ BitMatrixCursorF cur(image, {}, {});
848
+
849
+ for (int i = 0; i < 4; ++i) {
850
+ auto mod2Pix = PerspectiveTransform(srcQuad, RotatedCorners(*fpQuad, i));
851
+
852
+ auto check = [&](int i, bool on) {
853
+ return cur.testAt(mod2Pix(centered(FORMAT_INFO_EDGE_COORDS[i]))) == BitMatrixCursorF::Value(on);
854
+ };
855
+
856
+ // check that we see top edge timing pattern modules
857
+ if (!check(0, true) || !check(1, false) || !check(2, true) || !check(3, false))
858
+ continue;
859
+
860
+ uint32_t formatInfoBits = 0;
861
+ for (auto c : FORMAT_INFO_COORDS)
862
+ AppendBit(formatInfoBits, cur.blackAt(mod2Pix(centered(c))));
863
+
864
+ auto fi = FormatInformation::DecodeRMQR(formatInfoBits, 0 /*formatInfoBits2*/);
865
+ if (fi.hammingDistance < bestFI.hammingDistance) {
866
+ bestFI = fi;
867
+ bestPT = mod2Pix;
868
+ }
869
+ }
870
+
871
+ if (!bestFI.isValid())
872
+ return {};
873
+
874
+ const PointI dim = Version::SymbolSize(bestFI.microVersion, Type::rMQR);
875
+
876
+ // TODO: this is a WIP
877
+ auto intersectQuads = [](QuadrilateralF& a, QuadrilateralF& b) {
878
+ auto tl = Center(a);
879
+ auto br = Center(b);
880
+ // rotate points such that topLeft of a is furthest away from b and topLeft of b is closest to a
881
+ auto dist2B = [c = br](auto a, auto b) { return distance(a, c) < distance(b, c); };
882
+ auto offsetA = narrow_cast<int>(std::max_element(a.begin(), a.end(), dist2B) - a.begin());
883
+ auto dist2A = [c = tl](auto a, auto b) { return distance(a, c) < distance(b, c); };
884
+ auto offsetB = narrow_cast<int>(std::min_element(b.begin(), b.end(), dist2A) - b.begin());
885
+
886
+ a = RotatedCorners(a, offsetA);
887
+ b = RotatedCorners(b, offsetB);
888
+
889
+ auto tr = (intersect(RegressionLine(a[0], a[1]), RegressionLine(b[1], b[2]))
890
+ + intersect(RegressionLine(a[3], a[2]), RegressionLine(b[0], b[3])))
891
+ / 2;
892
+ auto bl = (intersect(RegressionLine(a[0], a[3]), RegressionLine(b[2], b[3]))
893
+ + intersect(RegressionLine(a[1], a[2]), RegressionLine(b[0], b[1])))
894
+ / 2;
895
+
896
+ log(tr, 2);
897
+ log(bl, 2);
898
+
899
+ return QuadrilateralF{tl, tr, br, bl};
900
+ };
901
+
902
+ if (auto found = LocateAlignmentPattern(image, fp.size / 7, bestPT(dim - PointF(3, 3)))) {
903
+ log(*found, 2);
904
+ if (auto spQuad = FindConcentricPatternCorners(image, *found, fp.size / 2, 1)) {
905
+ auto dest = intersectQuads(*fpQuad, *spQuad);
906
+ if (dim.y <= 9) {
907
+ bestPT = PerspectiveTransform({{6.5, 0.5}, {dim.x - 1.5, dim.y - 3.5}, {dim.x - 1.5, dim.y - 1.5}, {6.5, 6.5}},
908
+ {fpQuad->topRight(), spQuad->topRight(), spQuad->bottomRight(), fpQuad->bottomRight()});
909
+ } else {
910
+ dest[0] = fp;
911
+ dest[2] = *found;
912
+ bestPT = PerspectiveTransform({{3.5, 3.5}, {dim.x - 2.5, 3.5}, {dim.x - 2.5, dim.y - 2.5}, {3.5, dim.y - 2.5}}, dest);
913
+ }
914
+ }
915
+ }
916
+
917
+ return SampleGrid(image, dim.x, dim.y, bestPT);
918
+ }
919
+
920
+ } // namespace ZXing::QRCode