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,1230 @@
1
+ /*
2
+ * Copyright 2016 Nu-book Inc.
3
+ * Copyright 2016 ZXing authors
4
+ * Copyright 2017 Axel Waggershauser
5
+ */
6
+ // SPDX-License-Identifier: Apache-2.0
7
+
8
+ #include "DMDetector.h"
9
+
10
+ #include "BitMatrix.h"
11
+ #include "BitMatrixCursor.h"
12
+ #include "Matrix.h"
13
+ #include "DetectorResult.h"
14
+ #include "DMVersion.h"
15
+ #include "GridSampler.h"
16
+ #include "LogMatrix.h"
17
+ #include "LocalGrid.h"
18
+ #include "Point.h"
19
+ #include "RegressionLine.h"
20
+ #include "ResultPoint.h"
21
+ #include "StdScope.h"
22
+ #include "WhiteRectDetector.h"
23
+
24
+ #include <algorithm>
25
+ #include <array>
26
+ #include <cassert>
27
+ #include <cmath>
28
+ #include <cstdlib>
29
+ #include <functional>
30
+ #include <map>
31
+ #include <utility>
32
+ #include <vector>
33
+
34
+ #ifndef PRINT_DEBUG
35
+ #define printf(...){}
36
+ #define printv(...){}
37
+ #else
38
+ #define printv(fmt, vec) \
39
+ for (auto v : vec) \
40
+ printf(fmt, v); \
41
+ printf("\n");
42
+ #endif
43
+
44
+ namespace ZXing::DataMatrix {
45
+
46
+ /**
47
+ * The following code is the 'old' code by Sean Owen based on the Java upstream project.
48
+ * It looks for a white rectangle, then cuts the corners until it hits a black pixel, which
49
+ * results in 4 corner points. Then it determines the dimension by counting transitions
50
+ * between the upper and right corners and samples the grid.
51
+ * This code has several limitations compared to the new code below but has one advantage:
52
+ * it works on high resolution scans with noisy/rippled black/white-edges and potentially
53
+ * on partly occluded locator patterns (the surrounding border of modules/pixels). It is
54
+ * therefore kept as a fall-back.
55
+ */
56
+
57
+ /**
58
+ * Simply encapsulates two points and a number of transitions between them.
59
+ */
60
+ struct ResultPointsAndTransitions
61
+ {
62
+ const ResultPoint* from;
63
+ const ResultPoint* to;
64
+ int transitions;
65
+ };
66
+
67
+ /**
68
+ * Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.
69
+ */
70
+ static ResultPointsAndTransitions TransitionsBetween(const BitMatrix& image, const ResultPoint& from,
71
+ const ResultPoint& to)
72
+ {
73
+ // See QR Code Detector, sizeOfBlackWhiteBlackRun()
74
+ int fromX = static_cast<int>(from.x());
75
+ int fromY = static_cast<int>(from.y());
76
+ int toX = static_cast<int>(to.x());
77
+ int toY = static_cast<int>(to.y());
78
+ bool steep = std::abs(toY - fromY) > std::abs(toX - fromX);
79
+ if (steep) {
80
+ std::swap(fromX, fromY);
81
+ std::swap(toX, toY);
82
+ }
83
+
84
+ int dx = std::abs(toX - fromX);
85
+ int dy = std::abs(toY - fromY);
86
+ int error = -dx / 2;
87
+ int ystep = fromY < toY ? 1 : -1;
88
+ int xstep = fromX < toX ? 1 : -1;
89
+ int transitions = 0;
90
+ bool inBlack = image.get(steep ? fromY : fromX, steep ? fromX : fromY);
91
+ for (int x = fromX, y = fromY; x != toX; x += xstep) {
92
+ bool isBlack = image.get(steep ? y : x, steep ? x : y);
93
+ if (isBlack != inBlack) {
94
+ transitions++;
95
+ inBlack = isBlack;
96
+ }
97
+ error += dy;
98
+ if (error > 0) {
99
+ if (y == toY) {
100
+ break;
101
+ }
102
+ y += ystep;
103
+ error -= dx;
104
+ }
105
+ }
106
+ return ResultPointsAndTransitions{ &from, &to, transitions };
107
+ }
108
+
109
+ static bool IsValidPoint(const ResultPoint& p, int imgWidth, int imgHeight)
110
+ {
111
+ return p.x() >= 0 && p.x() < imgWidth && p.y() > 0 && p.y() < imgHeight;
112
+ }
113
+
114
+ template <typename T>
115
+ static float RoundToNearestF(T x)
116
+ {
117
+ return static_cast<float>(std::round(x));
118
+ }
119
+
120
+ /**
121
+ * Calculates the position of the white top right module using the output of the rectangle detector
122
+ * for a rectangular matrix
123
+ */
124
+ static bool CorrectTopRightRectangular(const BitMatrix& image, const ResultPoint& bottomLeft,
125
+ const ResultPoint& bottomRight, const ResultPoint& topLeft,
126
+ const ResultPoint& topRight, int dimensionTop, int dimensionRight,
127
+ ResultPoint& result)
128
+ {
129
+ float corr = RoundToNearestF(distance(bottomLeft, bottomRight)) / static_cast<float>(dimensionTop);
130
+ float norm = RoundToNearestF(distance(topLeft, topRight));
131
+ float cos = (topRight.x() - topLeft.x()) / norm;
132
+ float sin = (topRight.y() - topLeft.y()) / norm;
133
+
134
+ ResultPoint c1(topRight.x() + corr*cos, topRight.y() + corr*sin);
135
+
136
+ corr = RoundToNearestF(distance(bottomLeft, topLeft)) / (float)dimensionRight;
137
+ norm = RoundToNearestF(distance(bottomRight, topRight));
138
+ cos = (topRight.x() - bottomRight.x()) / norm;
139
+ sin = (topRight.y() - bottomRight.y()) / norm;
140
+
141
+ ResultPoint c2(topRight.x() + corr*cos, topRight.y() + corr*sin);
142
+
143
+ if (!IsValidPoint(c1, image.width(), image.height())) {
144
+ if (IsValidPoint(c2, image.width(), image.height())) {
145
+ result = c2;
146
+ return true;
147
+ }
148
+ return false;
149
+ }
150
+ if (!IsValidPoint(c2, image.width(), image.height())) {
151
+ result = c1;
152
+ return true;
153
+ }
154
+
155
+ int l1 = std::abs(dimensionTop - TransitionsBetween(image, topLeft, c1).transitions) +
156
+ std::abs(dimensionRight - TransitionsBetween(image, bottomRight, c1).transitions);
157
+ int l2 = std::abs(dimensionTop - TransitionsBetween(image, topLeft, c2).transitions) +
158
+ std::abs(dimensionRight - TransitionsBetween(image, bottomRight, c2).transitions);
159
+
160
+ result = l1 <= l2 ? c1 : c2;
161
+ return true;
162
+ }
163
+
164
+ /**
165
+ * Calculates the position of the white top right module using the output of the rectangle detector
166
+ * for a square matrix
167
+ */
168
+ static ResultPoint CorrectTopRight(const BitMatrix& image, const ResultPoint& bottomLeft, const ResultPoint& bottomRight,
169
+ const ResultPoint& topLeft, const ResultPoint& topRight, int dimension)
170
+ {
171
+ float corr = RoundToNearestF(distance(bottomLeft, bottomRight)) / (float)dimension;
172
+ float norm = RoundToNearestF(distance(topLeft, topRight));
173
+ float cos = (topRight.x() - topLeft.x()) / norm;
174
+ float sin = (topRight.y() - topLeft.y()) / norm;
175
+
176
+ ResultPoint c1(topRight.x() + corr * cos, topRight.y() + corr * sin);
177
+
178
+ corr = RoundToNearestF(distance(bottomLeft, topLeft)) / (float)dimension;
179
+ norm = RoundToNearestF(distance(bottomRight, topRight));
180
+ cos = (topRight.x() - bottomRight.x()) / norm;
181
+ sin = (topRight.y() - bottomRight.y()) / norm;
182
+
183
+ ResultPoint c2(topRight.x() + corr * cos, topRight.y() + corr * sin);
184
+
185
+ if (!IsValidPoint(c1, image.width(), image.height())) {
186
+ if (!IsValidPoint(c2, image.width(), image.height()))
187
+ return topRight;
188
+ return c2;
189
+ }
190
+ if (!IsValidPoint(c2, image.width(), image.height()))
191
+ return c1;
192
+
193
+ int l1 = std::abs(TransitionsBetween(image, topLeft, c1).transitions -
194
+ TransitionsBetween(image, bottomRight, c1).transitions);
195
+ int l2 = std::abs(TransitionsBetween(image, topLeft, c2).transitions -
196
+ TransitionsBetween(image, bottomRight, c2).transitions);
197
+ return l1 <= l2 ? c1 : c2;
198
+ }
199
+
200
+ static DetectorResult SampleGrid(const BitMatrix& image, const ResultPoint& topLeft, const ResultPoint& bottomLeft,
201
+ const ResultPoint& bottomRight, const ResultPoint& topRight, int width, int height)
202
+ {
203
+ return SampleGrid(image, width, height,
204
+ {Rectangle(width, height, 0), {topLeft, topRight, bottomRight, bottomLeft}});
205
+ }
206
+
207
+ /**
208
+ * Returns the z component of the cross product between vectors BC and BA.
209
+ */
210
+ static float CrossProductZ(const ResultPoint& a, const ResultPoint& b, const ResultPoint& c)
211
+ {
212
+ return (c.x() - b.x())*(a.y() - b.y()) - (c.y() - b.y())*(a.x() - b.x());
213
+ }
214
+
215
+ /**
216
+ * Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC
217
+ * and BC is less than AC, and the angle between BC and BA is less than 180 degrees.
218
+ */
219
+ static void OrderByBestPatterns(const ResultPoint*& p0, const ResultPoint*& p1, const ResultPoint*& p2)
220
+ {
221
+ // Find distances between pattern centers
222
+ auto zeroOneDistance = distance(*p0, *p1);
223
+ auto oneTwoDistance = distance(*p1, *p2);
224
+ auto zeroTwoDistance = distance(*p0, *p2);
225
+
226
+ const ResultPoint* pointA;
227
+ const ResultPoint* pointB;
228
+ const ResultPoint* pointC;
229
+ // Assume one closest to other two is B; A and C will just be guesses at first
230
+ if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
231
+ pointB = p0;
232
+ pointA = p1;
233
+ pointC = p2;
234
+ }
235
+ else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
236
+ pointB = p1;
237
+ pointA = p0;
238
+ pointC = p2;
239
+ }
240
+ else {
241
+ pointB = p2;
242
+ pointA = p0;
243
+ pointC = p1;
244
+ }
245
+
246
+ // Use cross product to figure out whether A and C are correct or flipped.
247
+ // This asks whether BC x BA has a positive z component, which is the arrangement
248
+ // we want for A, B, C. If it's negative, then we've got it flipped around and
249
+ // should swap A and C.
250
+ if (CrossProductZ(*pointA, *pointB, *pointC) < 0.0f) {
251
+ std::swap(pointA, pointC);
252
+ }
253
+
254
+ p0 = pointA;
255
+ p1 = pointB;
256
+ p2 = pointC;
257
+ }
258
+
259
+ static DetectorResult DetectOld(const BitMatrix& image)
260
+ {
261
+ ResultPoint pointA, pointB, pointC, pointD;
262
+ if (!DetectWhiteRect(image, pointA, pointB, pointC, pointD))
263
+ return {};
264
+
265
+ // Point A and D are across the diagonal from one another,
266
+ // as are B and C. Figure out which are the solid black lines
267
+ // by counting transitions
268
+ std::array transitions = {
269
+ TransitionsBetween(image, pointA, pointB),
270
+ TransitionsBetween(image, pointA, pointC),
271
+ TransitionsBetween(image, pointB, pointD),
272
+ TransitionsBetween(image, pointC, pointD),
273
+ };
274
+ std::sort(transitions.begin(), transitions.end(),
275
+ [](const auto& a, const auto& b) { return a.transitions < b.transitions; });
276
+
277
+ // Sort by number of transitions. First two will be the two solid sides; last two
278
+ // will be the two alternating black/white sides
279
+ const auto& lSideOne = transitions[0];
280
+ const auto& lSideTwo = transitions[1];
281
+
282
+ // We accept at most 4 transitions inside the L pattern (i.e. 2 corruptions) to reduce false positive FormatErrors
283
+ if (lSideTwo.transitions > 2)
284
+ return {};
285
+
286
+ // Figure out which point is their intersection by tallying up the number of times we see the
287
+ // endpoints in the four endpoints. One will show up twice.
288
+ std::map<const ResultPoint*, int> pointCount;
289
+ pointCount[lSideOne.from] += 1;
290
+ pointCount[lSideOne.to] += 1;
291
+ pointCount[lSideTwo.from] += 1;
292
+ pointCount[lSideTwo.to] += 1;
293
+
294
+ const ResultPoint* bottomRight = nullptr;
295
+ const ResultPoint* bottomLeft = nullptr;
296
+ const ResultPoint* topLeft = nullptr;
297
+ for (const auto& [point, count] : pointCount) {
298
+ if (count == 2) {
299
+ bottomLeft = point; // this is definitely the bottom left, then -- end of two L sides
300
+ }
301
+ else {
302
+ // Otherwise it's either top left or bottom right -- just assign the two arbitrarily now
303
+ if (bottomRight == nullptr) {
304
+ bottomRight = point;
305
+ }
306
+ else {
307
+ topLeft = point;
308
+ }
309
+ }
310
+ }
311
+
312
+ if (bottomRight == nullptr || bottomLeft == nullptr || topLeft == nullptr)
313
+ return {};
314
+
315
+ // Bottom left is correct but top left and bottom right might be switched
316
+ // Use the dot product trick to sort them out
317
+ OrderByBestPatterns(bottomRight, bottomLeft, topLeft);
318
+
319
+ // Which point didn't we find in relation to the "L" sides? that's the top right corner
320
+ const ResultPoint* topRight;
321
+ if (pointCount.find(&pointA) == pointCount.end()) {
322
+ topRight = &pointA;
323
+ }
324
+ else if (pointCount.find(&pointB) == pointCount.end()) {
325
+ topRight = &pointB;
326
+ }
327
+ else if (pointCount.find(&pointC) == pointCount.end()) {
328
+ topRight = &pointC;
329
+ }
330
+ else {
331
+ topRight = &pointD;
332
+ }
333
+
334
+ // Next determine the dimension by tracing along the top or right side and counting black/white
335
+ // transitions. Since we start inside a black module, we should see a number of transitions
336
+ // equal to 1 less than the code dimension. Well, actually 2 less, because we are going to
337
+ // end on a black module:
338
+
339
+ // The top right point is actually the corner of a module, which is one of the two black modules
340
+ // adjacent to the white module at the top right. Tracing to that corner from either the top left
341
+ // or bottom right should work here.
342
+
343
+ int dimensionTop = TransitionsBetween(image, *topLeft, *topRight).transitions;
344
+ int dimensionRight = TransitionsBetween(image, *bottomRight, *topRight).transitions;
345
+
346
+ if ((dimensionTop & 0x01) == 1) {
347
+ // it can't be odd, so, round... up?
348
+ dimensionTop++;
349
+ }
350
+ dimensionTop += 2;
351
+
352
+ if ((dimensionRight & 0x01) == 1) {
353
+ // it can't be odd, so, round... up?
354
+ dimensionRight++;
355
+ }
356
+ dimensionRight += 2;
357
+
358
+ if (dimensionTop < 10 || dimensionTop > 144 || dimensionRight < 8 || dimensionRight > 144 )
359
+ return {};
360
+
361
+ ResultPoint correctedTopRight;
362
+
363
+ // Rectangular symbols are 6x16, 6x28, 10x24, 10x32, 14x32, or 14x44. If one dimension is more
364
+ // than twice the other, it's certainly rectangular, but to cut a bit more slack we accept it as
365
+ // rectangular if the bigger side is at least 7/4 times the other:
366
+ if (4 * dimensionTop >= 7 * dimensionRight || 4 * dimensionRight >= 7 * dimensionTop) {
367
+ // The matrix is rectangular
368
+
369
+ if (!CorrectTopRightRectangular(image, *bottomLeft, *bottomRight, *topLeft, *topRight, dimensionTop,
370
+ dimensionRight, correctedTopRight)) {
371
+ correctedTopRight = *topRight;
372
+ }
373
+
374
+ dimensionTop = TransitionsBetween(image, *topLeft, correctedTopRight).transitions;
375
+ dimensionRight = TransitionsBetween(image, *bottomRight, correctedTopRight).transitions;
376
+
377
+ if ((dimensionTop & 0x01) == 1) {
378
+ // it can't be odd, so, round... up?
379
+ dimensionTop++;
380
+ }
381
+
382
+ if ((dimensionRight & 0x01) == 1) {
383
+ // it can't be odd, so, round... up?
384
+ dimensionRight++;
385
+ }
386
+ }
387
+ else {
388
+ // The matrix is square
389
+
390
+ int dimension = std::min(dimensionRight, dimensionTop);
391
+ // correct top right point to match the white module
392
+ correctedTopRight = CorrectTopRight(image, *bottomLeft, *bottomRight, *topLeft, *topRight, dimension);
393
+
394
+ // Redetermine the dimension using the corrected top right point
395
+ int dimensionCorrected = std::max(TransitionsBetween(image, *topLeft, correctedTopRight).transitions,
396
+ TransitionsBetween(image, *bottomRight, correctedTopRight).transitions);
397
+ dimensionCorrected++;
398
+ if ((dimensionCorrected & 0x01) == 1) {
399
+ dimensionCorrected++;
400
+ }
401
+
402
+ dimensionTop = dimensionRight = dimensionCorrected;
403
+ }
404
+
405
+ return SampleGrid(image, *topLeft, *bottomLeft, *bottomRight, correctedTopRight, dimensionTop, dimensionRight);
406
+ }
407
+
408
+ /**
409
+ * The following code is the 'new' one implemented by Axel Waggershauser and is working completely different.
410
+ * It is performing something like a (back) trace search along edges through the bit matrix, first looking for
411
+ * the 'L'-pattern, then tracing the black/white borders at the top/right. Advantages over the old code are:
412
+ * * works with lower resolution scans (around 2 pixel per module), due to sub-pixel precision grid placement
413
+ * * works with real-world codes that have just one module wide quiet-zone (which is perfectly in spec)
414
+ */
415
+
416
+ class DMRegressionLine : public RegressionLine
417
+ {
418
+ template <typename Container, typename Filter>
419
+ static double average(const Container& c, Filter f)
420
+ {
421
+ double sum = 0;
422
+ int num = 0;
423
+ for (const auto& v : c)
424
+ if (f(v)) {
425
+ sum += v;
426
+ ++num;
427
+ }
428
+ return sum / num;
429
+ }
430
+
431
+ public:
432
+ void reverse() { std::reverse(_points.begin(), _points.end()); }
433
+
434
+ double modules(PointF beg, PointF end)
435
+ {
436
+ assert(_points.size() > 3);
437
+
438
+ // re-evaluate and filter out all points too far away. required for the gapSizes calculation.
439
+ evaluate(1.2, true);
440
+
441
+ std::vector<double> gapSizes, modSizes;
442
+ gapSizes.reserve(_points.size());
443
+
444
+ // calculate the distance between the points projected onto the regression line
445
+ for (size_t i = 1; i < _points.size(); ++i)
446
+ gapSizes.push_back(distance(project(_points[i]), project(_points[i - 1])));
447
+
448
+ // calculate the (expected average) distance of two adjacent pixels
449
+ auto unitPixelDist = ZXing::length(bresenhamDirection(_points.back() - _points.front()));
450
+
451
+ // calculate the width of 2 modules (first black pixel to first black pixel)
452
+ double sumFront = distance(beg, project(_points.front())) - unitPixelDist;
453
+ double sumBack = 0; // (last black pixel to last black pixel)
454
+ for (auto dist : gapSizes) {
455
+ if (dist > 1.9 * unitPixelDist)
456
+ modSizes.push_back(std::exchange(sumBack, 0.0));
457
+ sumFront += dist;
458
+ sumBack += dist;
459
+ if (dist > 1.9 * unitPixelDist)
460
+ modSizes.push_back(std::exchange(sumFront, 0.0));
461
+ }
462
+ if (modSizes.empty())
463
+ return 0;
464
+ modSizes.push_back(sumFront + distance(end, project(_points.back())));
465
+ modSizes.front() = 0; // the first element is an invalid sumBack value, would be pop_front() if vector supported this
466
+ auto lineLength = distance(beg, end) - unitPixelDist;
467
+ auto [iMin, iMax] = std::minmax_element(modSizes.begin() + 1, modSizes.end());
468
+ auto meanModSize = average(modSizes, [](double dist){ return dist > 0; });
469
+
470
+ printf("unit pixel dist: %.1f\n", unitPixelDist);
471
+ printf("lineLength: %.1f, meanModSize: %.1f (min: %.1f, max: %.1f), gaps: %lu\n", lineLength, meanModSize, *iMin, *iMax,
472
+ modSizes.size());
473
+ printf("modSizes: ");
474
+ printv("%.1f ", modSizes);
475
+
476
+ if (*iMax > 2 * *iMin) {
477
+ for (int i = 1; i < Size(modSizes) - 2; ++i) {
478
+ if (modSizes[i] > 0 && modSizes[i] + modSizes[i + 2] < meanModSize * 1.4)
479
+ modSizes[i] += std::exchange(modSizes[i + 2], 0);
480
+ else if (modSizes[i] > meanModSize * 1.6)
481
+ modSizes[i] = 0;
482
+ }
483
+ printf("filtered: ");
484
+ printv("%.1f ", modSizes);
485
+
486
+ meanModSize = average(modSizes, [](double dist) { return dist > 0; });
487
+ }
488
+ printf("post filter meanModSize: %.1f\n", meanModSize);
489
+
490
+ return lineLength / meanModSize;
491
+ }
492
+
493
+ bool truncateIfLShape()
494
+ {
495
+ auto lenThis = Size(_points);
496
+ auto lineAB = RegressionLine(_points.front(), _points.back());
497
+ if (lenThis < 16 || lineAB.distance(_points[lenThis / 2]) < 5)
498
+ return false;
499
+
500
+ auto maxP = _points.begin();
501
+ double maxD = 0.0;
502
+ for (auto p = _points.begin(); p != _points.end(); ++p) {
503
+ auto d = lineAB.distance(*p);
504
+ if (d > maxD) {
505
+ maxP = p;
506
+ maxD = d;
507
+ }
508
+ }
509
+
510
+ auto lenL = distance(_points.front(), *maxP) - 1;
511
+ auto lenB = distance(*maxP, _points.back()) - 1;
512
+ if (maxD < std::min(lenL, lenB) / 2)
513
+ return false;
514
+
515
+ setDirectionInward(_points.back() - *maxP);
516
+
517
+ _points.resize(std::distance(_points.begin(), maxP) - 1);
518
+
519
+ return true;
520
+ }
521
+ };
522
+
523
+ class EdgeTracer : public BitMatrixCursorF
524
+ {
525
+ enum class StepResult { FOUND, OPEN_END, CLOSED_END };
526
+
527
+ // force this function inline to allow the compiler optimize for the maxStepSize==1 case in traceLine()
528
+ // this can result in a 10% speedup of the falsepositive use case when build with c++20
529
+ #if defined(__clang__) || defined(__GNUC__)
530
+ inline __attribute__((always_inline))
531
+ #elif defined(_MSC_VER)
532
+ __forceinline
533
+ #endif
534
+ StepResult traceStep(PointF dEdge, int maxStepSize, bool goodDirection)
535
+ {
536
+ dEdge = mainDirection(dEdge);
537
+ for (int breadth = 1; breadth <= (maxStepSize == 1 ? 2 : (goodDirection ? 1 : 3)); ++breadth)
538
+ for (int step = 1; step <= maxStepSize; ++step)
539
+ for (int i = 0; i <= 2*(step/4+1) * breadth; ++i) {
540
+ auto pEdge = p + step * d + (i&1 ? (i+1)/2 : -i/2) * dEdge;
541
+ log(pEdge);
542
+
543
+ if (!blackAt(pEdge + dEdge))
544
+ continue;
545
+
546
+ // found black pixel -> go 'outward' until we hit the b/w border
547
+ for (int j = 0; j < std::max(maxStepSize, 3) && isIn(pEdge); ++j) {
548
+ if (whiteAt(pEdge)) {
549
+ // if we are not making any progress, we still have another endless loop bug
550
+ assert(p != centered(pEdge));
551
+ p = centered(pEdge);
552
+
553
+ if (history && maxStepSize == 1) {
554
+ if (history->get(PointI(p)) == state)
555
+ return StepResult::CLOSED_END;
556
+ history->set(PointI(p), state);
557
+ }
558
+
559
+ return StepResult::FOUND;
560
+ }
561
+ pEdge = pEdge - dEdge;
562
+ if (blackAt(pEdge - d))
563
+ pEdge = pEdge - d;
564
+ log(pEdge);
565
+ }
566
+ // no valid b/w border found within reasonable range
567
+ return StepResult::CLOSED_END;
568
+ }
569
+ return StepResult::OPEN_END;
570
+ }
571
+
572
+ public:
573
+ using StateMatrix = Matrix<int8_t>;
574
+ StateMatrix* history = nullptr;
575
+ int state = 0;
576
+
577
+ using BitMatrixCursorF::BitMatrixCursor;
578
+
579
+ bool updateDirectionFromOrigin(PointF origin)
580
+ {
581
+ auto old_d = d;
582
+ setDirection(p - origin);
583
+ // if the new direction is pointing "backward", i.e. angle(new, old) > 90 deg -> break
584
+ if (dot(d, old_d) < 0)
585
+ return false;
586
+ // make sure d stays in the same quadrant to prevent an infinite loop
587
+ if (std::abs(d.x) == std::abs(d.y))
588
+ d = mainDirection(old_d) + 0.99f * (d - mainDirection(old_d));
589
+ else if (mainDirection(d) != mainDirection(old_d))
590
+ d = mainDirection(old_d) + 0.99f * mainDirection(d);
591
+ return true;
592
+ }
593
+
594
+ bool updateDirectionFromLine(RegressionLine& line)
595
+ {
596
+ return line.evaluate(1.5) && updateDirectionFromOrigin(p - line.project(p) + line.points().front());
597
+ }
598
+
599
+ bool updateDirectionFromLineCentroid(RegressionLine& line)
600
+ {
601
+ // Basically a faster, less accurate version of the above without the line evaluation
602
+ return updateDirectionFromOrigin(line.centroid());
603
+ }
604
+
605
+ bool traceLine(PointF dEdge, RegressionLine& line)
606
+ {
607
+ line.setDirectionInward(dEdge);
608
+ do {
609
+ log(p);
610
+ line.add(p);
611
+ if (line.points().size() % 50 == 10 && !updateDirectionFromLineCentroid(line))
612
+ return false;
613
+ auto stepResult = traceStep(dEdge, 1, line.isValid());
614
+ if (stepResult != StepResult::FOUND)
615
+ return stepResult == StepResult::OPEN_END && line.points().size() > 1 && updateDirectionFromLineCentroid(line);
616
+ } while (true);
617
+ }
618
+
619
+ bool traceGaps(PointF dEdge, RegressionLine& line, int maxStepSize, const RegressionLine& finishLine = {}, double minDist = 0)
620
+ {
621
+ line.setDirectionInward(dEdge);
622
+ int gaps = 0, steps = 0, maxStepsPerGap = maxStepSize;
623
+ PointF lastP;
624
+ do {
625
+ // detect an endless loop (lack of progress). if encountered, please report.
626
+ // this fixes a deadlock in falsepositives-1/#570.png and the regression in #574
627
+ if (p == std::exchange(lastP, p) || steps++ > (gaps == 0 ? 2 : gaps + 1) * maxStepsPerGap)
628
+ return false;
629
+ log(p);
630
+
631
+ // if we drifted too far outside of the code, break
632
+ if (line.isValid() && line.signedDistance(p) < -5 && (!line.evaluate() || line.signedDistance(p) < -5))
633
+ return false;
634
+
635
+ // if we are drifting towards the inside of the code, pull the current position back out onto the line
636
+ if (line.isValid() && line.signedDistance(p) > 3) {
637
+ // The current direction d and the line we are tracing are supposed to be roughly parallel.
638
+ // In case the 'go outward' step in traceStep lead us astray, we might end up with a line
639
+ // that is almost perpendicular to d. Then the back-projection below can result in an
640
+ // endless loop. Break if the angle between d and line is greater than 45 deg.
641
+ if (std::abs(dot(normalized(d), line.normal())) > 0.7) // thresh is approx. sin(45 deg)
642
+ return false;
643
+
644
+ // re-evaluate line with all the points up to here before projecting
645
+ if (!line.evaluate(1.5))
646
+ return false;
647
+
648
+ auto np = line.project(p);
649
+ // make sure we are making progress even when back-projecting:
650
+ // consider a 90deg corner, rotated 45deg. we step away perpendicular from the line and get
651
+ // back projected where we left off the line.
652
+ // The 'while' instead of 'if' was introduced to fix the issue with #245. It turns out that
653
+ // np can actually be behind the projection of the last line point and we need 2 steps in d
654
+ // to prevent a dead lock. see #245.png
655
+ while (distance(np, line.project(line.points().back())) < 1)
656
+ np = np + d;
657
+ p = centered(np);
658
+ }
659
+ else {
660
+ auto curStep = line.points().empty() ? PointF() : p - line.points().back();
661
+ auto stepLengthInMainDir = line.points().empty() ? 0.0 : dot(mainDirection(d), curStep);
662
+ line.add(p);
663
+
664
+ if (stepLengthInMainDir > 1 || maxAbsComponent(curStep) >= 2) {
665
+ ++gaps;
666
+ if (gaps >= 2 || line.points().size() > 5) {
667
+ if (!updateDirectionFromLine(line))
668
+ return false;
669
+ // check if the first half of the top-line trace is complete.
670
+ // the minimum code size is 10x10 -> every code has at least 4 gaps
671
+ if (minDist && gaps >= 4 && distance(p, line.points().front()) > minDist) {
672
+ // undo the last insert, it will be inserted again after the restart
673
+ line.pop_back();
674
+ --gaps;
675
+ return true;
676
+ }
677
+ }
678
+ } else if (gaps == 0 && Size(line.points()) >= 2 * maxStepSize) {
679
+ return false; // no point in following a line that has no gaps
680
+ }
681
+ }
682
+
683
+ if (finishLine.isValid())
684
+ UpdateMin(maxStepSize, static_cast<int>(finishLine.signedDistance(p)));
685
+
686
+ auto stepResult = traceStep(dEdge, maxStepSize, line.isValid());
687
+
688
+ if (stepResult != StepResult::FOUND)
689
+ // we are successful iff we found an open end across a valid finishLine
690
+ return stepResult == StepResult::OPEN_END && finishLine.isValid() &&
691
+ static_cast<int>(finishLine.signedDistance(p)) <= maxStepSize + 1;
692
+ } while (true);
693
+ }
694
+
695
+ bool traceCorner(PointF dir, PointF& corner)
696
+ {
697
+ step();
698
+ log(p);
699
+ corner = p;
700
+ std::swap(d, dir);
701
+ traceStep(-1 * dir, 2, false);
702
+ printf("turn: %.0f x %.0f -> %.2f, %.2f\n", p.x, p.y, d.x, d.y);
703
+
704
+ return isIn(corner) && isIn(p);
705
+ }
706
+
707
+ bool moveToNextWhiteAfterBlack()
708
+ {
709
+ assert(std::abs(d.x + d.y) == 1);
710
+
711
+ FastEdgeToEdgeCounter e2e(BitMatrixCursorI(*img, PointI(p), PointI(d)));
712
+ int steps = e2e.stepToNextEdge(INT_MAX);
713
+ if (!steps)
714
+ return false;
715
+ step(steps);
716
+ if(isWhite())
717
+ return true;
718
+
719
+ steps = e2e.stepToNextEdge(INT_MAX);
720
+ if (!steps)
721
+ return false;
722
+ return step(steps);
723
+ }
724
+ };
725
+
726
+ // Store a LUT mapping module indices to their actual center positions along the edge.
727
+ struct ModuleCenterLUT : std::vector<double>
728
+ {
729
+ using std::vector<double>::vector;
730
+
731
+ double operator()(int i) const { return empty() ? i + 0.5 : (*this)[i]; }
732
+ };
733
+
734
+ // Build a module-center LUT from uniform module coordinates to actual (non-uniform) ones
735
+ // by analyzing the gap structure in timing-pattern traced points. See #794, #1063, #1072.
736
+ static ModuleCenterLUT BuildModuleCenterLUT(const std::vector<PointF>& points, PointF start, PointF end, int numModules,
737
+ const std::function<double(double)>& edgeFracToModule)
738
+ {
739
+ if (Size(points) < 5)
740
+ return {};
741
+
742
+ auto edgeDir = end - start;
743
+ auto edgeLen = length(edgeDir);
744
+ auto unitDir = normalized(edgeDir);
745
+ auto modSize = edgeLen / numModules;
746
+
747
+ // project traced points onto edge direction
748
+ std::vector<double> proj;
749
+ proj.reserve(points.size());
750
+ for (const auto& p : points)
751
+ proj.push_back(dot(p - start, unitDir));
752
+
753
+ bool startsWithGap = false;
754
+ if (proj.front() > proj.back()) {
755
+ std::reverse(proj.begin(), proj.end());
756
+ startsWithGap = true;
757
+ }
758
+
759
+ // detect gaps (white modules) — use a lower threshold than modules() (1.9×) to catch
760
+ // compressed gaps near edges caused by barrel distortion on curved surfaces
761
+ auto unitPixelDist = length(bresenhamDirection(edgeDir));
762
+ double gapThreshold = 1.4 * unitPixelDist;
763
+
764
+ std::vector<double> gapMids;
765
+ for (int i = 1; i < Size(proj); ++i)
766
+ if (proj[i] - proj[i - 1] > gapThreshold) {
767
+ auto gapMid = (proj[i] + proj[i - 1]) / 2;
768
+ if (gapMids.empty() || gapMid - gapMids.back() > 0.75 * 2 * modSize)
769
+ gapMids.push_back(gapMid);
770
+ }
771
+
772
+ if (gapMids.empty()) {
773
+ return {};
774
+ }
775
+
776
+ // assign each gap a module index, accounting for missing gaps via spacing ratio
777
+ std::vector<int> modIdx(gapMids.size());
778
+ modIdx[0] = static_cast<int>(std::round((gapMids.front() / modSize - (1.5 + startsWithGap)) / 2)) * 2 + 1 + startsWithGap;
779
+ for (int i = 1; i < Size(gapMids); ++i)
780
+ modIdx[i] = modIdx[i - 1] + std::max(1, static_cast<int>(std::round((gapMids[i] - gapMids[i - 1]) / (2 * modSize)))) * 2;
781
+
782
+ printf("mIdx: ");
783
+ printv("%d ", modIdx);
784
+
785
+ struct Knot
786
+ {
787
+ double mc, corrMc;
788
+ };
789
+ std::vector<Knot> knots;
790
+ knots.reserve(Size(gapMids) + 2);
791
+ knots.push_back({0.0, 0.0});
792
+ for (int k = 0; k < Size(gapMids); ++k)
793
+ knots.push_back({modIdx[k] + 0.5, edgeFracToModule(gapMids[k] / edgeLen)});
794
+ knots.push_back({double(numModules), double(numModules)});
795
+
796
+ // less than 1/2 module deviation: correction not worthwhile
797
+ if (Reduce(knots, 0.0, [](double m, const Knot& k) { return std::max(m, std::abs(k.mc - k.corrMc)); }) < 0.5)
798
+ return {};
799
+
800
+ ModuleCenterLUT centerLUT(numModules);
801
+
802
+ // #define ZXING_USE_POLY_TIMING_REMAP
803
+ // #define ZXING_USE_POLY_TIMING_REMAP_CONSTRAINED
804
+
805
+ #ifdef ZXING_USE_POLY_TIMING_REMAP
806
+ {
807
+ // Fit degree-2 polynomial corrMc = poly[0] + poly[1]*mc + poly[2]*mc^2
808
+ // using least-squares on all knots (including endpoint sentinels at 0 and numModules).
809
+ double s0 = Size(knots), s1 = 0, s2 = 0, s3 = 0, s4 = 0;
810
+ double b0 = 0, b1 = 0, b2 = 0;
811
+ for (const auto& k : knots) {
812
+ double m = k.mc, c = k.corrMc, m2 = m * m;
813
+ s1 += m;
814
+ s2 += m2;
815
+ s3 += m2 * m;
816
+ s4 += m2 * m2;
817
+ b0 += c;
818
+ b1 += m * c;
819
+ b2 += m2 * c;
820
+ }
821
+ // Gaussian elimination on the 3x3 normal equations [A^T A | A^T b]
822
+ double mat[3][4] = {{s0, s1, s2, b0}, {s1, s2, s3, b1}, {s2, s3, s4, b2}};
823
+ for (int col = 0; col < 3; ++col)
824
+ for (int row = col + 1; row < 3; ++row) {
825
+ double f = mat[row][col] / mat[col][col];
826
+ for (int j = col; j <= 3; ++j)
827
+ mat[row][j] -= f * mat[col][j];
828
+ }
829
+ double p2 = mat[2][3] / mat[2][2];
830
+ double p1 = (mat[1][3] - mat[1][2] * p2) / mat[1][1];
831
+ double p0 = (mat[0][3] - mat[0][2] * p2 - mat[0][1] * p1) / mat[0][0];
832
+ for (int i = 0; i < numModules; ++i) {
833
+ double mc = i + 0.5;
834
+ centerLUT[i] = p0 + p1 * mc + p2 * mc * mc;
835
+ }
836
+ }
837
+ #elif defined(ZXING_USE_POLY_TIMING_REMAP_CONSTRAINED)
838
+ {
839
+ // Fit a quadratic that reproduces both sentinel endpoints (0 and N) exactly:
840
+ // corrMc = mc + a * mc * (mc - N).
841
+ // This keeps corrMc(0) == 0 and corrMc(N) == N by construction,
842
+ // while fitting the interior gap knots in the least-squares sense.
843
+ double gg = 0, gb = 0;
844
+ for (const auto& k : knots) {
845
+ double g = k.mc * (k.mc - numModules);
846
+ gg += g * g;
847
+ gb += g * (k.corrMc - k.mc);
848
+ }
849
+ double a = gb / gg;
850
+ double p0 = 0;
851
+ double p1 = 1 - a * numModules;
852
+ double p2 = a;
853
+ for (int i = 0; i < numModules; ++i) {
854
+ double mc = i + 0.5;
855
+ centerLUT[i] = p0 + p1 * mc + p2 * mc * mc;
856
+ }
857
+ }
858
+ #else
859
+ // Fill dense lookup table at module centers via piecewise-linear interpolation.
860
+ int ki = 0;
861
+ for (int i = 0; i < numModules; ++i) {
862
+ double mc = i + 0.5;
863
+ while (ki + 1 < Size(knots) - 1 && knots[ki + 1].mc < mc)
864
+ ++ki;
865
+ double denom = knots[ki + 1].mc - knots[ki].mc;
866
+ assert(denom >= 0.1);
867
+ double t = (mc - knots[ki].mc) / denom;
868
+ centerLUT[i] = knots[ki].corrMc + t * (knots[ki + 1].corrMc - knots[ki].corrMc);
869
+ }
870
+ #endif
871
+
872
+ printf("corr: ");
873
+ for (int i = 0; i < numModules; ++i)
874
+ printf("%.2f ", centerLUT[i] - (i + 0.5));
875
+ printf("\n");
876
+
877
+ return centerLUT;
878
+ }
879
+
880
+ //TODO: merge this into a generic SampleGrid function
881
+ static DetectorResult SampleGridCorrected(const BitMatrix& image, int width, int height, const PerspectiveTransform& mod2Pix,
882
+ const ModuleCenterLUT& topCenterLUT, const ModuleCenterLUT& rightCenterLUT)
883
+ {
884
+ #ifdef PRINT_DEBUG
885
+ LogMatrix log;
886
+ static int i = 0;
887
+ LogMatrixWriter lmw(log, image, 5, "grid_c" + std::to_string(i++) + ".pnm");
888
+ #endif
889
+
890
+ BitMatrix res(width, height);
891
+ for (int y = 0; y < height; ++y) {
892
+ double my = rightCenterLUT(y);
893
+ for (int x = 0; x < width; ++x) {
894
+ auto p = mod2Pix(PointF{topCenterLUT(x), my});
895
+ if (!image.isIn(p))
896
+ return {};
897
+ #ifdef PRINT_DEBUG
898
+ log(p, 3);
899
+ #endif
900
+ if (image.get(p))
901
+ res.set(x, y);
902
+ }
903
+ }
904
+
905
+ auto projectCorner = [&](PointI p) { return PointI(mod2Pix(PointF(p)) + PointF(0.5, 0.5)); };
906
+ return {std::move(res),
907
+ {projectCorner({0, 0}), projectCorner({width, 0}), projectCorner({width, height}), projectCorner({0, height})}};
908
+ }
909
+
910
+ static DetectorResults Scan(EdgeTracer& startTracer, std::array<DMRegressionLine, 4>& lines)
911
+ {
912
+ while (startTracer.moveToNextWhiteAfterBlack()) {
913
+ log(startTracer.p);
914
+
915
+ PointF tl, bl, br, tr;
916
+ auto& [lineL, lineB, lineR, lineT] = lines;
917
+
918
+ for (auto& l : lines)
919
+ l.reset();
920
+
921
+ #ifdef PRINT_DEBUG
922
+ SCOPE_EXIT([&] {
923
+ for (auto& l : lines)
924
+ log(l.points());
925
+ });
926
+ # define CHECK(A) if (!(A)) { printf("broke at %d\n", __LINE__); continue; }
927
+ #else
928
+ # define CHECK(A) if(!(A)) continue
929
+ #endif
930
+
931
+ auto t = startTracer;
932
+ PointF up, right;
933
+
934
+ // follow left leg upwards
935
+ t.turnRight();
936
+ t.state = 1;
937
+ CHECK(t.traceLine(t.right(), lineL));
938
+ CHECK(t.traceCorner(t.right(), tl));
939
+ lineL.reverse();
940
+ auto tlTracer = t;
941
+
942
+ // follow left leg downwards
943
+ t = startTracer;
944
+ t.state = 1;
945
+ t.setDirection(tlTracer.right());
946
+ CHECK(t.traceLine(t.left(), lineL));
947
+
948
+ // check if lineL is L-shaped -> truncate the lower leg and set t to just before the corner
949
+ if (lineL.truncateIfLShape())
950
+ t.p = lineL.points().back();
951
+ t.updateDirectionFromOrigin(tl);
952
+ up = t.back();
953
+ CHECK(t.traceCorner(t.left(), bl));
954
+
955
+ // follow bottom leg right
956
+ t.state = 2;
957
+ CHECK(t.traceLine(t.left(), lineB));
958
+ t.updateDirectionFromOrigin(bl);
959
+ right = t.front();
960
+ CHECK(t.traceCorner(t.left(), br));
961
+
962
+ auto lenL = distance(tl, bl) - 1;
963
+ auto lenB = distance(bl, br) - 1;
964
+ CHECK(lenL >= 8 && lenB >= 10 && lenB >= lenL / 4 && lenB <= lenL * 18);
965
+
966
+ auto maxStepSize = static_cast<int>(lenB / 5 + 1); // datamatrix bottom dim is at least 10
967
+
968
+ // at this point we found a plausible L-shape and are now looking for the b/w pattern at the top and right:
969
+ // follow top row right 'half way' (at least 4 gaps), see traceGaps
970
+ tlTracer.setDirection(right);
971
+ CHECK(tlTracer.traceGaps(tlTracer.right(), lineT, maxStepSize, {}, lenB / 2));
972
+
973
+ maxStepSize = std::min(lineT.length() / 3, static_cast<int>(lenL / 5)) * 2;
974
+
975
+ // follow up until we reach the top line
976
+ t.setDirection(up);
977
+ t.state = 3;
978
+ CHECK(t.traceGaps(t.left(), lineR, maxStepSize, lineT));
979
+ CHECK(t.traceCorner(t.left(), tr));
980
+
981
+ auto lenT = distance(tl, tr) - 1;
982
+ auto lenR = distance(tr, br) - 1;
983
+
984
+ CHECK(std::abs(lenT - lenB) / lenB < 0.5 && std::abs(lenR - lenL) / lenL < 0.5 &&
985
+ lineT.points().size() >= 5 && lineR.points().size() >= 5);
986
+
987
+ // continue top row right until we cross the right line
988
+ CHECK(tlTracer.traceGaps(tlTracer.right(), lineT, maxStepSize, lineR));
989
+
990
+ printf("L: %.1f, %.1f ^ %.1f, %.1f > %.1f, %.1f (%d : %d : %d : %d)\n", bl.x, bl.y,
991
+ tl.x - bl.x, tl.y - bl.y, br.x - bl.x, br.y - bl.y, (int)lenL, (int)lenB, (int)lenT, (int)lenR);
992
+
993
+ for (auto* l : {&lineL, &lineB, &lineT, &lineR})
994
+ l->evaluate(1.0);
995
+
996
+ // find the bounding box corners of the code with sub-pixel precision by intersecting the 4 border lines
997
+ bl = intersect(lineB, lineL);
998
+ tl = intersect(lineT, lineL);
999
+ tr = intersect(lineT, lineR);
1000
+ br = intersect(lineB, lineR);
1001
+
1002
+ int dimT, dimR;
1003
+ double fracT, fracR;
1004
+ auto splitDouble = [](double d, int* i, double* f) {
1005
+ *i = std::isnormal(d) ? narrow_cast<int>(std::lround(d)) : 0;
1006
+ *f = std::isnormal(d) ? std::abs(d - *i) : INFINITY;
1007
+ };
1008
+ splitDouble(lineT.modules(tl, tr), &dimT, &fracT);
1009
+ splitDouble(lineR.modules(br, tr), &dimR, &fracR);
1010
+
1011
+ // the dimension is 2x the number of black/white transitions
1012
+ dimT *= 2;
1013
+ dimR *= 2;
1014
+
1015
+ printf("L: %.1f, %.1f ^ %.1f, %.1f > %.1f, %.1f ^> %.1f, %.1f\n", bl.x, bl.y,
1016
+ tl.x - bl.x, tl.y - bl.y, br.x - bl.x, br.y - bl.y, tr.x, tr.y);
1017
+ printf("dim: %d x %d (%.2f, %.2f)\n", dimT, dimR, fracT, fracR);
1018
+
1019
+ auto* version = VersionForDimensions(dimR, dimT);
1020
+
1021
+ // if we have an invalid dimension but it is almost square (all valid rectangular symbols differ in their dimension by at least 10),
1022
+ // we try to parse it by assuming a square. If only one leads to a valid version, we use that, otherwise we use the dimension
1023
+ // that is closer to an integral value.
1024
+ if (!version && std::abs(dimT - dimR) < 10) {
1025
+ auto* versionT = VersionForDimensions(dimT, dimT);
1026
+ auto* versionR = VersionForDimensions(dimR, dimR);
1027
+ if (bool(versionT) ^ bool(versionR))
1028
+ dimT = dimR = versionT ? dimT : dimR;
1029
+ else
1030
+ dimT = dimR = fracR < fracT ? dimR : dimT;
1031
+ version = VersionForDimensions(dimR, dimT);
1032
+ }
1033
+ CHECK(version);
1034
+
1035
+ auto movedTowardsBy = [](PointF a, PointF b1, PointF b2, auto d) {
1036
+ return a + d * normalized(normalized(b1 - a) + normalized(b2 - a));
1037
+ };
1038
+
1039
+ // shrink shape by half a pixel to go from center of white pixel outside of code to the edge between white and black
1040
+ QuadrilateralF sourcePoints = {
1041
+ movedTowardsBy(tl, tr, bl, 0.5f),
1042
+ // move the tr point a little less because the jagged top and right line tend to be statistically slightly
1043
+ // inclined toward the center anyway.
1044
+ movedTowardsBy(tr, br, tl, 0.3f),
1045
+ movedTowardsBy(br, bl, tr, 0.5f),
1046
+ movedTowardsBy(bl, tl, br, 0.5f),
1047
+ };
1048
+
1049
+ auto mod2Pix = PerspectiveTransform(Rectangle(dimT, dimR, 0), sourcePoints);
1050
+ auto pix2Mod = PerspectiveTransform(sourcePoints, Rectangle(dimT, dimR, 0));
1051
+
1052
+ #if 1
1053
+ std::vector<int> apX(version->dataBlocksX() + 1), apY(version->dataBlocksY() + 1);
1054
+ std::generate(apX.begin(), apX.end(), [i = 0, version]() mutable { return i++ * (version->dataBlockWidth + 2); });
1055
+ std::generate(apY.begin(), apY.end(), [i = 0, version]() mutable { return i++ * (version->dataBlockHeight + 2); });
1056
+ apX.back() = dimT - 1;
1057
+ apY.back() = dimR - 1;
1058
+ auto apP = Matrix<std::optional<PointF>>(Size(apX), Size(apY));
1059
+
1060
+ constexpr PointI l(-1, 0), r(1, 0), u(0, -1), d(0, 1);
1061
+
1062
+ // Find the position of the alignment pattern center by looking for the given b/w patterns around the initial estimate
1063
+ // based on the mod2Pix projection.
1064
+ auto findAP = [&](PointI p, PointI offset, int radius, PointI timingStart, LocalGrid::Directions timingDirs, PointI blackStart,
1065
+ LocalGrid::Directions blackDirs, PointI whiteStart,
1066
+ LocalGrid::Directions whiteDirs) -> std::optional<PointF> {
1067
+ auto lg = LocalGrid(*startTracer.img, mod2Pix, p, {dimT, dimR}, offset);
1068
+ if (lg.findPattern(radius, timingStart, timingDirs, blackStart, blackDirs, whiteStart, whiteDirs))
1069
+ return lg.getPos();
1070
+ return {};
1071
+ };
1072
+
1073
+ for (int y = 0; y < Size(apY); ++y)
1074
+ for (int x = 0; x < Size(apX); ++x) {
1075
+ std::optional<PointF> ap;
1076
+ PointI api{apX[x], apY[y]};
1077
+ int Nx = Size(apX) - 1, Ny = Size(apY) - 1;
1078
+
1079
+ if (x == 0 && y == 0) // top-left
1080
+ ap = findAP(api, {2, 0}, 4, {1, 0}, std::array{r}, {0, 0}, std::array{d}, {-1, -1}, std::array{d, r});
1081
+ else if (x == Nx && y == 0) // top-right
1082
+ ap = findAP(api, {-1, 1}, 4, {0, 0}, std::array{l, d}, {}, {}, {1, -1}, std::array{d, l});
1083
+ else if (x == Nx && y == Ny) // bottom-right
1084
+ ap = findAP(api, {-0, -2}, 4, {0, -1}, std::array{u}, {0, 0}, std::array{l}, {1, 1}, std::array{u, l});
1085
+ else if (x == 0 && y == Ny) // bottom-left
1086
+ ap = findAP(api, {1, -1}, 4, {}, {}, {0, 0}, std::array{u, r}, {-1, 1}, std::array{u, r});
1087
+ else if (x == 0) // left
1088
+ ap = findAP(api, {2, 0}, 3, {1, 0}, std::array{r}, {0, -1}, std::array{u, d, r}, {}, {});
1089
+ else if (x == Nx) // right
1090
+ ap = findAP(api, {-1, 0}, 3, {0, 0}, std::array{l, u, d}, {0, -1}, std::array{l}, {}, {});
1091
+ else if (y == 0) // top
1092
+ ap = findAP(api, {-1, 0}, 3, {-1, 0}, std::array{l, r, d}, {0, 0}, std::array{d}, {}, {});
1093
+ else if (y == Ny) // bottom
1094
+ ap = findAP(api, {-1, -1}, 3, {-1, -1}, std::array{u}, {0, 0}, std::array{l, r, u}, {}, {});
1095
+ else // center
1096
+ ap = findAP(api, {-1, 0}, 3, {-1, 0}, std::array{l, r, u, d}, {0, -1}, std::array{l, r, u, d}, {}, {});
1097
+
1098
+ if (ap)
1099
+ apP.set(x, y, *ap);
1100
+ }
1101
+
1102
+ if (auto res = SampleGrid(*startTracer.img, dimT, dimR, mod2Pix, std::move(apP), apX, apY); res.isValid())
1103
+ co_yield std::move(res);
1104
+ #else
1105
+ if (auto res = SampleGrid(*startTracer.img, dimT, dimR, mod2Pix); res.isValid())
1106
+ co_yield std::move(res);
1107
+ #endif
1108
+ // if (auto res = SampleGrid(*startTracer.img, dimT, dimR, mod2Pix); res.isValid())
1109
+ // co_yield std::move(res);
1110
+
1111
+ if (dimT > 42 && dimR > 42) // symbols that are this large are unlikely to be fixable by a 'global' timing pattern correction
1112
+ continue;
1113
+
1114
+ // TODO: we currently only yield the corrected grid if at least one dimention is significantly deformed (has a LUT), but it
1115
+ // would be even better if we stopped right after having a sucessful decoding result from the uncorrected grid. The current
1116
+ // co-routine setup does not allow this. The runtime impact is very small though.
1117
+
1118
+ // produce timing-pattern-corrected alternatives for deformed symbols
1119
+ tl = sourcePoints[0], tr = sourcePoints[1], br = sourcePoints[2];
1120
+
1121
+ auto tLUT = BuildModuleCenterLUT(lineT.points(), tl, tr, dimT, [&](double t) { return pix2Mod((1 - t) * tl + t * tr).x; });
1122
+ auto rLUT = BuildModuleCenterLUT(lineR.points(), tr, br, dimR, [&](double t) { return pix2Mod((1 - t) * tr + t * br).y; });
1123
+
1124
+ if (!tLUT.empty() || !rLUT.empty())
1125
+ if (auto res = SampleGridCorrected(*startTracer.img, dimT, dimR, mod2Pix, tLUT, rLUT); res.isValid())
1126
+ co_yield std::move(res);
1127
+ }
1128
+ }
1129
+
1130
+ static DetectorResults DetectNew(const BitMatrix& image, bool tryHarder, bool tryRotate)
1131
+ {
1132
+ #ifdef PRINT_DEBUG
1133
+ LogMatrixWriter lmw(log, image, 3, "dm-log.pnm");
1134
+ // tryRotate = tryHarder = false;
1135
+ #endif
1136
+
1137
+ // a history log to remember where the tracing already passed by to prevent a later trace from doing the same work twice
1138
+ EdgeTracer::StateMatrix history;
1139
+ if (tryHarder)
1140
+ history = EdgeTracer::StateMatrix(image.width(), image.height());
1141
+
1142
+ // instantiate RegressionLine objects outside of Scan function to prevent repetitive std::vector allocations
1143
+ std::array<DMRegressionLine, 4> lines;
1144
+
1145
+ constexpr int minSymbolSize = 8 * 2; // minimum realistic size in pixel: 8 modules x 2 pixels per module
1146
+
1147
+ for (auto dir : {PointF{-1, 0}, {1, 0}, {0, -1}, {0, 1}}) {
1148
+ auto center = PointI(image.width() / 2, image.height() / 2);
1149
+ auto startPos = centered(center - center * dir + minSymbolSize / 2 * dir);
1150
+
1151
+ history.clear();
1152
+
1153
+ for (int i = 1;; ++i) {
1154
+ EdgeTracer tracer(image, startPos, dir);
1155
+ tracer.p += i / 2 * minSymbolSize * (i & 1 ? -1 : 1) * tracer.right();
1156
+ if (tryHarder)
1157
+ tracer.history = &history;
1158
+
1159
+ if (!tracer.isIn())
1160
+ break;
1161
+
1162
+ for (auto&& res : Scan(tracer, lines))
1163
+ co_yield std::move(res);
1164
+
1165
+ if (!tryHarder)
1166
+ break; // only test center lines
1167
+ }
1168
+
1169
+ if (!tryRotate)
1170
+ break; // only test left direction
1171
+ }
1172
+ }
1173
+
1174
+ /**
1175
+ * This method detects a code in a "pure" image -- that is, pure monochrome image
1176
+ * which contains only an unrotated, unskewed, image of a code, with some optional white border
1177
+ * around it. This is a specialized method that works exceptionally fast in this special
1178
+ * case.
1179
+ */
1180
+ static DetectorResult DetectPure(const BitMatrix& image)
1181
+ {
1182
+ int left, top, width, height;
1183
+ if (!image.findBoundingBox(left, top, width, height, 8))
1184
+ return {};
1185
+
1186
+ BitMatrixCursorI cur(image, {left, top}, {0, 1});
1187
+ if (cur.countEdges(height - 1) != 0)
1188
+ return {};
1189
+ cur.turnLeft();
1190
+ if (cur.countEdges(width - 1) != 0)
1191
+ return {};
1192
+ cur.turnLeft();
1193
+ int dimR = cur.countEdges(height - 1) + 1;
1194
+ cur.turnLeft();
1195
+ int dimT = cur.countEdges(width - 1) + 1;
1196
+
1197
+ auto modSizeX = float(width) / dimT;
1198
+ auto modSizeY = float(height) / dimR;
1199
+ auto modSize = (modSizeX + modSizeY) / 2;
1200
+
1201
+ if (dimT % 2 != 0 || dimR % 2 != 0 || dimT < 10 || dimT > 144 || dimR < 8 || dimR > 144
1202
+ || std::abs(modSizeX - modSizeY) > 1
1203
+ || !image.isIn(PointF{left + modSizeX / 2 + (dimT - 1) * modSize, top + modSizeY / 2 + (dimR - 1) * modSize}))
1204
+ return {};
1205
+
1206
+ // Now just read off the bits (this is a crop + subsample)
1207
+ return {Deflate(image, dimT, dimR, top + modSizeY / 2, left + modSizeX / 2, modSize),
1208
+ Rectangle<PointI>(left, top, width, height)};
1209
+ }
1210
+
1211
+ DetectorResults Detect(const BitMatrix& image, bool tryHarder, bool tryRotate, bool isPure)
1212
+ {
1213
+ // First try the very fast DetectPure() path. Also because DetectNew() generally fails with pure module size 1 symbols
1214
+ // TODO: implement a tryRotate version of DetectPure, see #590.
1215
+ if (auto r = DetectPure(image); r.isValid())
1216
+ co_yield std::move(r);
1217
+ else if (!isPure) { // If r.isValid() then there is no point in looking for more (no-pure) symbols
1218
+ bool found = false;
1219
+ for (auto&& r : DetectNew(image, tryHarder, tryRotate)) {
1220
+ found = true;
1221
+ co_yield std::move(r);
1222
+ }
1223
+ if (!found && tryHarder) {
1224
+ if (auto r = DetectOld(image); r.isValid())
1225
+ co_yield std::move(r);
1226
+ }
1227
+ }
1228
+ }
1229
+
1230
+ } // namespace ZXing::DataMatrix