docvortex 0.2.1__py3-none-any.whl

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 (364) hide show
  1. docvortex/__init__.py +21 -0
  2. docvortex/analyzers/__init__.py +3 -0
  3. docvortex/analyzers/native/__init__.py +37 -0
  4. docvortex/analyzers/native/_shared/__init__.py +3 -0
  5. docvortex/analyzers/native/_shared/hyperlink.py +16 -0
  6. docvortex/analyzers/native/_shared/image.py +8 -0
  7. docvortex/analyzers/native/_shared/markup/__init__.py +47 -0
  8. docvortex/analyzers/native/_shared/markup/anchors.py +30 -0
  9. docvortex/analyzers/native/_shared/markup/formula.py +37 -0
  10. docvortex/analyzers/native/_shared/markup/projector.py +57 -0
  11. docvortex/analyzers/native/_shared/markup/styles.py +19 -0
  12. docvortex/analyzers/native/_shared/mathml.py +17 -0
  13. docvortex/analyzers/native/_shared/names.py +7 -0
  14. docvortex/analyzers/native/_shared/xycut.py +414 -0
  15. docvortex/analyzers/native/contracts.py +44 -0
  16. docvortex/analyzers/native/csv.py +351 -0
  17. docvortex/analyzers/native/epub/__init__.py +18 -0
  18. docvortex/analyzers/native/epub/constants.py +45 -0
  19. docvortex/analyzers/native/epub/converter.py +80 -0
  20. docvortex/analyzers/native/epub/errors.py +20 -0
  21. docvortex/analyzers/native/epub/metadata.py +31 -0
  22. docvortex/analyzers/native/epub/package.py +649 -0
  23. docvortex/analyzers/native/epub/xhtml.py +306 -0
  24. docvortex/analyzers/native/html/__init__.py +6 -0
  25. docvortex/analyzers/native/html/anchors.py +271 -0
  26. docvortex/analyzers/native/html/constants.py +25 -0
  27. docvortex/analyzers/native/html/contracts.py +7 -0
  28. docvortex/analyzers/native/html/converter.py +117 -0
  29. docvortex/analyzers/native/html/document.py +389 -0
  30. docvortex/analyzers/native/html/errors.py +12 -0
  31. docvortex/analyzers/native/html/resources.py +365 -0
  32. docvortex/analyzers/native/html/selector.py +421 -0
  33. docvortex/analyzers/native/models.py +209 -0
  34. docvortex/analyzers/native/ofd/__init__.py +14 -0
  35. docvortex/analyzers/native/ofd/constants.py +59 -0
  36. docvortex/analyzers/native/ofd/converter.py +31 -0
  37. docvortex/analyzers/native/ofd/errors.py +16 -0
  38. docvortex/analyzers/native/ofd/geometry.py +215 -0
  39. docvortex/analyzers/native/ofd/images.py +124 -0
  40. docvortex/analyzers/native/ofd/metadata.py +53 -0
  41. docvortex/analyzers/native/ofd/models.py +170 -0
  42. docvortex/analyzers/native/ofd/package.py +346 -0
  43. docvortex/analyzers/native/ofd/path.py +201 -0
  44. docvortex/analyzers/native/ofd/reading_order.py +293 -0
  45. docvortex/analyzers/native/ofd/resources.py +122 -0
  46. docvortex/analyzers/native/ofd/scene.py +347 -0
  47. docvortex/analyzers/native/ofd/table.py +240 -0
  48. docvortex/analyzers/native/ofd/text.py +521 -0
  49. docvortex/analyzers/native/office/__init__.py +3 -0
  50. docvortex/analyzers/native/office/doc/__init__.py +3 -0
  51. docvortex/analyzers/native/office/doc/bookmarks.py +81 -0
  52. docvortex/analyzers/native/office/doc/doc_converter.py +573 -0
  53. docvortex/analyzers/native/office/doc/fib.py +261 -0
  54. docvortex/analyzers/native/office/doc/fields.py +101 -0
  55. docvortex/analyzers/native/office/doc/formatting.py +171 -0
  56. docvortex/analyzers/native/office/doc/images.py +162 -0
  57. docvortex/analyzers/native/office/doc/lists.py +356 -0
  58. docvortex/analyzers/native/office/doc/models.py +164 -0
  59. docvortex/analyzers/native/office/doc/parser.py +851 -0
  60. docvortex/analyzers/native/office/doc/pieces.py +256 -0
  61. docvortex/analyzers/native/office/doc/records.py +40 -0
  62. docvortex/analyzers/native/office/doc/sprm.py +269 -0
  63. docvortex/analyzers/native/office/doc/styles.py +215 -0
  64. docvortex/analyzers/native/office/docx/__init__.py +3 -0
  65. docvortex/analyzers/native/office/docx/context.py +71 -0
  66. docvortex/analyzers/native/office/docx/docx_converter.py +614 -0
  67. docvortex/analyzers/native/office/docx/equationxml.py +119 -0
  68. docvortex/analyzers/native/office/docx/fields.py +816 -0
  69. docvortex/analyzers/native/office/docx/formatting_types.py +23 -0
  70. docvortex/analyzers/native/office/docx/main.py +50 -0
  71. docvortex/analyzers/native/office/docx/numbering.py +491 -0
  72. docvortex/analyzers/native/office/docx/office_xml.py +57 -0
  73. docvortex/analyzers/native/office/docx/package_normalizer.py +248 -0
  74. docvortex/analyzers/native/office/docx/resources.py +526 -0
  75. docvortex/analyzers/native/office/docx/styles.py +693 -0
  76. docvortex/analyzers/native/office/docx/tables.py +515 -0
  77. docvortex/analyzers/native/office/equation/__init__.py +3 -0
  78. docvortex/analyzers/native/office/equation/image.py +470 -0
  79. docvortex/analyzers/native/office/equation/latex_dict.py +324 -0
  80. docvortex/analyzers/native/office/equation/mtef.py +885 -0
  81. docvortex/analyzers/native/office/equation/mtef_v5.py +941 -0
  82. docvortex/analyzers/native/office/equation/omml.py +561 -0
  83. docvortex/analyzers/native/office/equation/ooxml.py +62 -0
  84. docvortex/analyzers/native/office/errors.py +33 -0
  85. docvortex/analyzers/native/office/image.py +307 -0
  86. docvortex/analyzers/native/office/legacy/__init__.py +3 -0
  87. docvortex/analyzers/native/office/legacy/binary.py +43 -0
  88. docvortex/analyzers/native/office/legacy/officeart.py +362 -0
  89. docvortex/analyzers/native/office/legacy/ole.py +110 -0
  90. docvortex/analyzers/native/office/limits.py +12 -0
  91. docvortex/analyzers/native/office/odf/__init__.py +3 -0
  92. docvortex/analyzers/native/office/odf/chart.py +76 -0
  93. docvortex/analyzers/native/office/odf/constants.py +70 -0
  94. docvortex/analyzers/native/office/odf/converters.py +403 -0
  95. docvortex/analyzers/native/office/odf/errors.py +18 -0
  96. docvortex/analyzers/native/office/odf/metadata.py +91 -0
  97. docvortex/analyzers/native/office/odf/models.py +176 -0
  98. docvortex/analyzers/native/office/odf/package.py +270 -0
  99. docvortex/analyzers/native/office/odf/styles.py +329 -0
  100. docvortex/analyzers/native/office/odf/table.py +469 -0
  101. docvortex/analyzers/native/office/odf/text.py +1002 -0
  102. docvortex/analyzers/native/office/ooxml_chart.py +1016 -0
  103. docvortex/analyzers/native/office/opc.py +38 -0
  104. docvortex/analyzers/native/office/ppt/__init__.py +3 -0
  105. docvortex/analyzers/native/office/ppt/models.py +118 -0
  106. docvortex/analyzers/native/office/ppt/parser.py +1895 -0
  107. docvortex/analyzers/native/office/ppt/ppt_converter.py +292 -0
  108. docvortex/analyzers/native/office/ppt/records.py +131 -0
  109. docvortex/analyzers/native/office/ppt/style_text.py +247 -0
  110. docvortex/analyzers/native/office/pptx/__init__.py +3 -0
  111. docvortex/analyzers/native/office/pptx/context.py +113 -0
  112. docvortex/analyzers/native/office/pptx/lists.py +558 -0
  113. docvortex/analyzers/native/office/pptx/main.py +20 -0
  114. docvortex/analyzers/native/office/pptx/package_normalizer.py +321 -0
  115. docvortex/analyzers/native/office/pptx/pptx_converter.py +323 -0
  116. docvortex/analyzers/native/office/pptx/resources.py +329 -0
  117. docvortex/analyzers/native/office/pptx/shapes.py +393 -0
  118. docvortex/analyzers/native/office/pptx/text_styles.py +625 -0
  119. docvortex/analyzers/native/office/pptx/titles.py +178 -0
  120. docvortex/analyzers/native/office/rich_text.py +420 -0
  121. docvortex/analyzers/native/office/rtf/__init__.py +3 -0
  122. docvortex/analyzers/native/office/rtf/converter.py +708 -0
  123. docvortex/analyzers/native/office/rtf/lexer.py +213 -0
  124. docvortex/analyzers/native/office/rtf/math.py +339 -0
  125. docvortex/analyzers/native/office/rtf/models.py +185 -0
  126. docvortex/analyzers/native/office/rtf/parser.py +1553 -0
  127. docvortex/analyzers/native/office/spreadsheet/__init__.py +3 -0
  128. docvortex/analyzers/native/office/spreadsheet/html.py +81 -0
  129. docvortex/analyzers/native/office/spreadsheet/models.py +79 -0
  130. docvortex/analyzers/native/office/spreadsheet/projector.py +928 -0
  131. docvortex/analyzers/native/office/streams.py +18 -0
  132. docvortex/analyzers/native/office/xls/__init__.py +3 -0
  133. docvortex/analyzers/native/office/xls/chart.py +132 -0
  134. docvortex/analyzers/native/office/xls/embedded_chart.py +299 -0
  135. docvortex/analyzers/native/office/xls/models.py +109 -0
  136. docvortex/analyzers/native/office/xls/number_format.py +521 -0
  137. docvortex/analyzers/native/office/xls/parser.py +1145 -0
  138. docvortex/analyzers/native/office/xls/records.py +201 -0
  139. docvortex/analyzers/native/office/xls/strings.py +205 -0
  140. docvortex/analyzers/native/office/xls/xls_converter.py +354 -0
  141. docvortex/analyzers/native/office/xlsx/__init__.py +3 -0
  142. docvortex/analyzers/native/office/xlsx/main.py +20 -0
  143. docvortex/analyzers/native/office/xlsx/ooxml_ole.py +522 -0
  144. docvortex/analyzers/native/office/xlsx/package_normalizer.py +310 -0
  145. docvortex/analyzers/native/office/xlsx/xlsx_converter.py +716 -0
  146. docvortex/analyzers/native/pdf/__init__.py +3 -0
  147. docvortex/analyzers/native/pdf/auxiliary_text.py +1671 -0
  148. docvortex/analyzers/native/pdf/char_geometry.py +1662 -0
  149. docvortex/analyzers/native/pdf/code_blocks.py +535 -0
  150. docvortex/analyzers/native/pdf/formulas.py +1985 -0
  151. docvortex/analyzers/native/pdf/geometry.py +281 -0
  152. docvortex/analyzers/native/pdf/graphics.py +1501 -0
  153. docvortex/analyzers/native/pdf/index_blocks.py +268 -0
  154. docvortex/analyzers/native/pdf/inline/__init__.py +3 -0
  155. docvortex/analyzers/native/pdf/inline/common.py +112 -0
  156. docvortex/analyzers/native/pdf/inline/detection.py +590 -0
  157. docvortex/analyzers/native/pdf/inline/matching.py +1185 -0
  158. docvortex/analyzers/native/pdf/inline/materialize.py +457 -0
  159. docvortex/analyzers/native/pdf/inline/scripts.py +975 -0
  160. docvortex/analyzers/native/pdf/inline/types.py +385 -0
  161. docvortex/analyzers/native/pdf/line_layout.py +1106 -0
  162. docvortex/analyzers/native/pdf/line_merging.py +1223 -0
  163. docvortex/analyzers/native/pdf/models.py +246 -0
  164. docvortex/analyzers/native/pdf/native_text.py +1004 -0
  165. docvortex/analyzers/native/pdf/pipeline.py +1390 -0
  166. docvortex/analyzers/native/pdf/script_geometry.py +636 -0
  167. docvortex/analyzers/native/pdf/shared.py +30 -0
  168. docvortex/analyzers/native/pdf/spatial_text.py +383 -0
  169. docvortex/analyzers/native/pdf/table_annotations.py +446 -0
  170. docvortex/analyzers/native/pdf/table_constants.py +48 -0
  171. docvortex/analyzers/native/pdf/table_detection.py +227 -0
  172. docvortex/analyzers/native/pdf/table_filled_grid.py +218 -0
  173. docvortex/analyzers/native/pdf/table_geometry.py +40 -0
  174. docvortex/analyzers/native/pdf/table_materialization.py +444 -0
  175. docvortex/analyzers/native/pdf/table_recovery/__init__.py +15 -0
  176. docvortex/analyzers/native/pdf/table_recovery/candidate.py +356 -0
  177. docvortex/analyzers/native/pdf/table_recovery/contracts.py +154 -0
  178. docvortex/analyzers/native/pdf/table_recovery/engine.py +609 -0
  179. docvortex/analyzers/native/pdf/table_recovery/geometry.py +164 -0
  180. docvortex/analyzers/native/pdf/table_recovery/sparse_common.py +85 -0
  181. docvortex/analyzers/native/pdf/table_recovery/sparse_hybrid.py +804 -0
  182. docvortex/analyzers/native/pdf/table_recovery/sparse_multiline.py +1122 -0
  183. docvortex/analyzers/native/pdf/table_recovery/text.py +414 -0
  184. docvortex/analyzers/native/pdf/table_recovery/text_grid.py +618 -0
  185. docvortex/analyzers/native/pdf/table_recovery/vector.py +1931 -0
  186. docvortex/analyzers/native/pdf/table_rows.py +34 -0
  187. docvortex/analyzers/native/pdf/table_rules.py +1129 -0
  188. docvortex/analyzers/native/pdf/table_text_styles.py +283 -0
  189. docvortex/analyzers/native/pdf/tables.py +147 -0
  190. docvortex/analyzers/native/pdf/text_assembly/__init__.py +3 -0
  191. docvortex/analyzers/native/pdf/text_assembly/annotations.py +581 -0
  192. docvortex/analyzers/native/pdf/text_assembly/assembly.py +292 -0
  193. docvortex/analyzers/native/pdf/text_assembly/common.py +477 -0
  194. docvortex/analyzers/native/pdf/text_assembly/footnotes.py +394 -0
  195. docvortex/analyzers/native/pdf/text_assembly/merging.py +1274 -0
  196. docvortex/analyzers/native/pdf/text_assembly/rows.py +692 -0
  197. docvortex/analyzers/native/pdf/text_blocks.py +82 -0
  198. docvortex/analyzers/native/pdf/text_styles.py +55 -0
  199. docvortex/analyzers/native/pdf/title_analysis/__init__.py +3 -0
  200. docvortex/analyzers/native/pdf/title_analysis/body_profile.py +215 -0
  201. docvortex/analyzers/native/pdf/title_analysis/common.py +117 -0
  202. docvortex/analyzers/native/pdf/title_analysis/document_profile.py +164 -0
  203. docvortex/analyzers/native/pdf/title_analysis/lane_titles.py +758 -0
  204. docvortex/analyzers/native/pdf/title_analysis/page_titles.py +1024 -0
  205. docvortex/analyzers/native/pdf/title_analysis/prototype.py +194 -0
  206. docvortex/analyzers/native/pdf/title_analysis/structural.py +1081 -0
  207. docvortex/analyzers/native/pdf/titles.py +75 -0
  208. docvortex/analyzers/native/pdf/typography.py +19 -0
  209. docvortex/analyzers/native/pdf/visual_annotations.py +1262 -0
  210. docvortex/api.py +180 -0
  211. docvortex/assets/__init__.py +5 -0
  212. docvortex/assets/store.py +51 -0
  213. docvortex/cli.py +54 -0
  214. docvortex/codecs/__init__.py +3 -0
  215. docvortex/codecs/html/__init__.py +22 -0
  216. docvortex/codecs/html/contracts.py +236 -0
  217. docvortex/codecs/html/materializer.py +331 -0
  218. docvortex/codecs/html/parser.py +763 -0
  219. docvortex/codecs/html/resources.py +34 -0
  220. docvortex/codecs/json.py +17 -0
  221. docvortex/content/__init__.py +5 -0
  222. docvortex/content/inline.py +248 -0
  223. docvortex/content/markup/__init__.py +44 -0
  224. docvortex/content/markup/anchors.py +188 -0
  225. docvortex/content/markup/formula.py +280 -0
  226. docvortex/content/markup/projector.py +1237 -0
  227. docvortex/content/markup/styles.py +327 -0
  228. docvortex/content/mathml.py +167 -0
  229. docvortex/content/normalization.py +188 -0
  230. docvortex/content/spans.py +183 -0
  231. docvortex/content/table/__init__.py +18 -0
  232. docvortex/content/table/blocks.py +152 -0
  233. docvortex/content/table/content.py +425 -0
  234. docvortex/content/table/document.py +104 -0
  235. docvortex/content/table/html.py +399 -0
  236. docvortex/content/table/models.py +76 -0
  237. docvortex/content/table/rules.py +42 -0
  238. docvortex/content/table/structure.py +221 -0
  239. docvortex/content/tree.py +5 -0
  240. docvortex/document/__init__.py +3 -0
  241. docvortex/document/contracts.py +22 -0
  242. docvortex/document/detection.py +389 -0
  243. docvortex/document/filetypes.py +175 -0
  244. docvortex/document/page_range.py +167 -0
  245. docvortex/document/pdf/__init__.py +19 -0
  246. docvortex/document/pdf/classify.py +1138 -0
  247. docvortex/document/pdf/constants.py +132 -0
  248. docvortex/document/pdf/diagnostics.py +350 -0
  249. docvortex/document/pdf/document.py +582 -0
  250. docvortex/document/pdf/font_runtime.py +335 -0
  251. docvortex/document/pdf/geometry.py +31 -0
  252. docvortex/document/pdf/images.py +654 -0
  253. docvortex/document/pdf/native_annotations.py +367 -0
  254. docvortex/document/pdf/native_contracts.py +169 -0
  255. docvortex/document/pdf/native_coordinates.py +216 -0
  256. docvortex/document/pdf/native_lifecycle.py +16 -0
  257. docvortex/document/pdf/native_objects.py +902 -0
  258. docvortex/document/pdf/native_text_geometry.py +315 -0
  259. docvortex/document/pdf/pdfium.py +325 -0
  260. docvortex/document/pdf/raster.py +46 -0
  261. docvortex/document/pdf/text/__init__.py +62 -0
  262. docvortex/document/pdf/text/contracts.py +211 -0
  263. docvortex/document/pdf/text/extract.py +165 -0
  264. docvortex/document/pdf/text/geometry.py +16 -0
  265. docvortex/document/pdf/text/groups.py +162 -0
  266. docvortex/document/pdf/visual_geometry.py +201 -0
  267. docvortex/document/pdf/visuals.py +343 -0
  268. docvortex/document/source.py +92 -0
  269. docvortex/errors.py +21 -0
  270. docvortex/export/__init__.py +3 -0
  271. docvortex/export/bundle.py +98 -0
  272. docvortex/export/files.py +66 -0
  273. docvortex/export/middle.py +208 -0
  274. docvortex/foundation/__init__.py +3 -0
  275. docvortex/foundation/geometry.py +125 -0
  276. docvortex/foundation/hyperlink.py +65 -0
  277. docvortex/foundation/image.py +48 -0
  278. docvortex/foundation/image_encoding.py +30 -0
  279. docvortex/foundation/image_payload.py +280 -0
  280. docvortex/foundation/language.py +92 -0
  281. docvortex/foundation/platform.py +38 -0
  282. docvortex/foundation/text.py +153 -0
  283. docvortex/foundation/type_identity.py +20 -0
  284. docvortex/foundation/xml_names.py +20 -0
  285. docvortex/options.py +30 -0
  286. docvortex/postprocess/__init__.py +3 -0
  287. docvortex/postprocess/content.py +53 -0
  288. docvortex/postprocess/document.py +19 -0
  289. docvortex/postprocess/lists.py +236 -0
  290. docvortex/postprocess/page_blocks.py +214 -0
  291. docvortex/postprocess/pages.py +95 -0
  292. docvortex/postprocess/paragraphs.py +580 -0
  293. docvortex/postprocess/visual.py +715 -0
  294. docvortex/render/__init__.py +48 -0
  295. docvortex/render/_internal/__init__.py +3 -0
  296. docvortex/render/_internal/common/__init__.py +3 -0
  297. docvortex/render/_internal/common/context.py +43 -0
  298. docvortex/render/_internal/common/html_table.py +178 -0
  299. docvortex/render/_internal/common/index.py +33 -0
  300. docvortex/render/_internal/common/list_items.py +158 -0
  301. docvortex/render/_internal/common/planner.py +140 -0
  302. docvortex/render/_internal/docx/__init__.py +3 -0
  303. docvortex/render/_internal/docx/assets.py +202 -0
  304. docvortex/render/_internal/docx/inline.py +434 -0
  305. docvortex/render/_internal/docx/math.py +220 -0
  306. docvortex/render/_internal/docx/renderer.py +905 -0
  307. docvortex/render/_internal/docx/styles.py +195 -0
  308. docvortex/render/_internal/docx/table.py +442 -0
  309. docvortex/render/_internal/epub/__init__.py +5 -0
  310. docvortex/render/_internal/epub/assets.py +173 -0
  311. docvortex/render/_internal/epub/package.py +249 -0
  312. docvortex/render/_internal/epub/renderer.py +1156 -0
  313. docvortex/render/_internal/html/__init__.py +3 -0
  314. docvortex/render/_internal/html/inline.py +346 -0
  315. docvortex/render/_internal/html/renderer.py +1041 -0
  316. docvortex/render/_internal/html/sanitizer.py +478 -0
  317. docvortex/render/_internal/html/table.py +121 -0
  318. docvortex/render/_internal/latex/__init__.py +1 -0
  319. docvortex/render/_internal/latex/assets.py +85 -0
  320. docvortex/render/_internal/latex/inline.py +145 -0
  321. docvortex/render/_internal/latex/renderer.py +506 -0
  322. docvortex/render/_internal/latex/table.py +347 -0
  323. docvortex/render/_internal/markdown/__init__.py +3 -0
  324. docvortex/render/_internal/markdown/assets.py +78 -0
  325. docvortex/render/_internal/markdown/blocks.py +635 -0
  326. docvortex/render/_internal/markdown/escaping.py +51 -0
  327. docvortex/render/_internal/markdown/inline.py +260 -0
  328. docvortex/render/_internal/markdown/renderer.py +93 -0
  329. docvortex/render/_internal/markdown/table.py +281 -0
  330. docvortex/render/_internal/pdf/__init__.py +3 -0
  331. docvortex/render/_internal/pdf/assets.py +197 -0
  332. docvortex/render/_internal/pdf/formula.py +417 -0
  333. docvortex/render/_internal/pdf/inline.py +343 -0
  334. docvortex/render/_internal/pdf/renderer.py +734 -0
  335. docvortex/render/_internal/pdf/styles.py +206 -0
  336. docvortex/render/_internal/pdf/table.py +272 -0
  337. docvortex/render/_internal/structured_content/__init__.py +3 -0
  338. docvortex/render/_internal/structured_content/renderer.py +193 -0
  339. docvortex/render/api.py +199 -0
  340. docvortex/render/contracts.py +205 -0
  341. docvortex/render/docx.py +38 -0
  342. docvortex/render/epub.py +35 -0
  343. docvortex/render/fragments.py +70 -0
  344. docvortex/render/html.py +29 -0
  345. docvortex/render/latex.py +24 -0
  346. docvortex/render/markdown.py +50 -0
  347. docvortex/render/pdf.py +25 -0
  348. docvortex/render/structured_content.py +23 -0
  349. docvortex/resources/epub/docvortex.css +91 -0
  350. docvortex/resources/fasttext-langdetect/lid.176.ftz +0 -0
  351. docvortex/resources/fonts/DroidSansFallbackFull.ttf +0 -0
  352. docvortex/resources/fonts/NOTICE +190 -0
  353. docvortex/resources/fonts/manifest.json +9 -0
  354. docvortex/resources/html/docvortex.css +601 -0
  355. docvortex/resources/html/docvortex.min.css +1 -0
  356. docvortex/result.py +91 -0
  357. docvortex/schema.py +1141 -0
  358. docvortex/version.py +3 -0
  359. docvortex-0.2.1.dist-info/METADATA +193 -0
  360. docvortex-0.2.1.dist-info/RECORD +364 -0
  361. docvortex-0.2.1.dist-info/WHEEL +5 -0
  362. docvortex-0.2.1.dist-info/entry_points.txt +2 -0
  363. docvortex-0.2.1.dist-info/licenses/LICENSE.md +21 -0
  364. docvortex-0.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,414 @@
1
+ """基于几何信息实现不依赖语义模型的 XYCut++ 阅读顺序排序。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ from dataclasses import dataclass
7
+ from statistics import median
8
+ from typing import Any, Final, Sequence
9
+
10
+
11
+ DEFAULT_BETA: Final = 1.3
12
+ DEFAULT_DENSITY_THRESHOLD: Final = 0.9
13
+ OVERLAP_THRESHOLD: Final = 0.1
14
+ MIN_OVERLAP_COUNT: Final = 2
15
+ MIN_GAP_THRESHOLD: Final = 5.0
16
+ NARROW_ELEMENT_WIDTH_RATIO: Final = 0.1
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class _CutInfo:
21
+ """记录投影切分位置及对应的空白间距。"""
22
+
23
+ position: float
24
+ gap: float
25
+
26
+
27
+ @dataclass(frozen=True)
28
+ class _SortableEntry:
29
+ """保存待排序对象、原始序号及标准化后的绝对坐标。"""
30
+
31
+ index: int
32
+ payload: dict[str, Any]
33
+ bbox: tuple[float, float, float, float]
34
+
35
+ @property
36
+ def left(self) -> float:
37
+ """返回左边界。"""
38
+ return self.bbox[0]
39
+
40
+ @property
41
+ def top(self) -> float:
42
+ """返回上边界。"""
43
+ return self.bbox[1]
44
+
45
+ @property
46
+ def right(self) -> float:
47
+ """返回右边界。"""
48
+ return self.bbox[2]
49
+
50
+ @property
51
+ def bottom(self) -> float:
52
+ """返回下边界。"""
53
+ return self.bbox[3]
54
+
55
+ @property
56
+ def width(self) -> float:
57
+ """返回元素宽度。"""
58
+ return self.right - self.left
59
+
60
+ @property
61
+ def height(self) -> float:
62
+ """返回元素高度。"""
63
+ return self.bottom - self.top
64
+
65
+ @property
66
+ def area(self) -> float:
67
+ """返回元素包围盒面积。"""
68
+ return self.width * self.height
69
+
70
+ @property
71
+ def center_x(self) -> float:
72
+ """返回元素横向中心。"""
73
+ return (self.left + self.right) / 2.0
74
+
75
+ @property
76
+ def center_y(self) -> float:
77
+ """返回元素纵向中心。"""
78
+ return (self.top + self.bottom) / 2.0
79
+
80
+
81
+ def sort_entries(
82
+ entries: Sequence[dict[str, Any]],
83
+ *,
84
+ beta: float = DEFAULT_BETA,
85
+ density_threshold: float = DEFAULT_DENSITY_THRESHOLD,
86
+ ) -> list[dict[str, Any]]:
87
+ """按绝对坐标 bbox 对字典对象执行确定性的 XYCut++ 排序。
88
+
89
+ bbox 无效的对象不会参与几何排序,并按输入相对顺序稳定保留在结果末尾。
90
+ ``MIN_GAP_THRESHOLD`` 使用 PDF point 等绝对坐标单位,调用方不得提前归一化。
91
+ """
92
+ sortable_entries, invalid_entries = _build_sortable_entries(entries)
93
+ sorted_entries = _recursive_segment(
94
+ sortable_entries,
95
+ beta=beta,
96
+ density_threshold=density_threshold,
97
+ )
98
+ return [entry.payload for entry in sorted_entries] + invalid_entries
99
+
100
+
101
+ def _build_sortable_entries(
102
+ entries: Sequence[dict[str, Any]],
103
+ ) -> tuple[list[_SortableEntry], list[dict[str, Any]]]:
104
+ """拆分 bbox 有效的排序对象和需要稳定置尾的无效对象。"""
105
+ sortable_entries: list[_SortableEntry] = []
106
+ invalid_entries: list[dict[str, Any]] = []
107
+ for index, entry in enumerate(entries):
108
+ bbox = _normalize_bbox(entry.get("bbox"))
109
+ if bbox is None:
110
+ invalid_entries.append(entry)
111
+ continue
112
+ sortable_entries.append(_SortableEntry(index=index, payload=entry, bbox=bbox))
113
+ return sortable_entries, invalid_entries
114
+
115
+
116
+ def _normalize_bbox(
117
+ bbox: Any,
118
+ ) -> tuple[float, float, float, float] | None:
119
+ """将合法四元 bbox 转成有限浮点数绝对坐标。"""
120
+ if not isinstance(bbox, (list, tuple)) or len(bbox) != 4:
121
+ return None
122
+
123
+ try:
124
+ normalized = tuple(float(value) for value in bbox)
125
+ except (TypeError, ValueError):
126
+ return None
127
+
128
+ if not all(math.isfinite(value) for value in normalized):
129
+ return None
130
+
131
+ x0, y0, x1, y1 = normalized
132
+ if x1 <= x0 or y1 <= y0:
133
+ return None
134
+ return (x0, y0, x1, y1)
135
+
136
+
137
+ def _recursive_segment(
138
+ entries: Sequence[_SortableEntry],
139
+ *,
140
+ beta: float,
141
+ density_threshold: float,
142
+ ) -> list[_SortableEntry]:
143
+ """在当前局部区域重新识别跨栏块、计算密度并递归切分。"""
144
+ if len(entries) <= 1:
145
+ return list(entries)
146
+
147
+ cross_layout_entries = _identify_cross_layout_elements(entries, beta)
148
+ cross_layout_ids = {entry.index for entry in cross_layout_entries}
149
+ main_entries = [entry for entry in entries if entry.index not in cross_layout_ids]
150
+
151
+ if not main_entries:
152
+ return _sort_by_y_then_x(cross_layout_entries)
153
+
154
+ sorted_main = _segment_main_entries(
155
+ main_entries,
156
+ beta=beta,
157
+ density_threshold=density_threshold,
158
+ )
159
+ return _merge_cross_layout_elements(sorted_main, cross_layout_entries)
160
+
161
+
162
+ def _segment_main_entries(
163
+ entries: Sequence[_SortableEntry],
164
+ *,
165
+ beta: float,
166
+ density_threshold: float,
167
+ ) -> list[_SortableEntry]:
168
+ """依据当前区域密度选择首选轴,并在切分后递归处理子区域。"""
169
+ if len(entries) <= 1:
170
+ return list(entries)
171
+
172
+ density_ratio = _compute_density_ratio(entries)
173
+ prefer_horizontal_first = density_ratio > density_threshold
174
+ horizontal_cut = _find_best_horizontal_cut_with_projection(entries)
175
+ vertical_cut = _find_best_vertical_cut_with_projection(entries)
176
+
177
+ preferred_cut = horizontal_cut if prefer_horizontal_first else vertical_cut
178
+ fallback_cut = vertical_cut if prefer_horizontal_first else horizontal_cut
179
+ use_horizontal_cut = prefer_horizontal_first
180
+
181
+ if preferred_cut.gap < MIN_GAP_THRESHOLD:
182
+ if fallback_cut.gap < MIN_GAP_THRESHOLD:
183
+ return _sort_by_y_then_x(entries)
184
+ preferred_cut = fallback_cut
185
+ use_horizontal_cut = not use_horizontal_cut
186
+
187
+ if use_horizontal_cut:
188
+ groups = _split_by_horizontal_cut(entries, preferred_cut.position)
189
+ else:
190
+ groups = _split_by_vertical_cut(entries, preferred_cut.position)
191
+
192
+ if len(groups) <= 1:
193
+ return _sort_by_y_then_x(entries)
194
+
195
+ result: list[_SortableEntry] = []
196
+ for group in groups:
197
+ result.extend(
198
+ _recursive_segment(
199
+ group,
200
+ beta=beta,
201
+ density_threshold=density_threshold,
202
+ )
203
+ )
204
+ return result
205
+
206
+
207
+ def _identify_cross_layout_elements(entries: Sequence[_SortableEntry], beta: float) -> list[_SortableEntry]:
208
+ """以当前区域中位宽度识别横跨多个栏区的宽元素。"""
209
+ if len(entries) < 3:
210
+ return []
211
+
212
+ median_width = median(entry.width for entry in entries)
213
+ threshold = beta * median_width
214
+ return [entry for entry in entries if entry.width >= threshold and _has_minimum_overlaps(entry, entries, MIN_OVERLAP_COUNT)]
215
+
216
+
217
+ def _has_minimum_overlaps(
218
+ entry: _SortableEntry,
219
+ entries: Sequence[_SortableEntry],
220
+ min_count: int,
221
+ ) -> bool:
222
+ """判断元素是否在水平方向覆盖至少指定数量的其他元素。"""
223
+ overlap_count = 0
224
+ for other in entries:
225
+ if other.index == entry.index:
226
+ continue
227
+ if _calculate_horizontal_overlap_ratio(entry, other) < OVERLAP_THRESHOLD:
228
+ continue
229
+ overlap_count += 1
230
+ if overlap_count >= min_count:
231
+ return True
232
+ return False
233
+
234
+
235
+ def _calculate_horizontal_overlap_ratio(
236
+ entry1: _SortableEntry,
237
+ entry2: _SortableEntry,
238
+ ) -> float:
239
+ """计算两个元素相对较窄元素的横向覆盖比例。"""
240
+ overlap_width = max(
241
+ 0.0,
242
+ min(entry1.right, entry2.right) - max(entry1.left, entry2.left),
243
+ )
244
+ smaller_width = min(entry1.width, entry2.width)
245
+ if overlap_width <= 0 or smaller_width <= 0:
246
+ return 0.0
247
+ return overlap_width / smaller_width
248
+
249
+
250
+ def _compute_density_ratio(entries: Sequence[_SortableEntry]) -> float:
251
+ """计算当前区域中元素面积之和与区域面积的比值。"""
252
+ region = _calculate_bounding_region(entries)
253
+ if region is None:
254
+ return 1.0
255
+
256
+ region_area = (region[2] - region[0]) * (region[3] - region[1])
257
+ if region_area <= 0:
258
+ return 1.0
259
+
260
+ content_area = sum(entry.area for entry in entries)
261
+ return min(1.0, content_area / region_area)
262
+
263
+
264
+ def _calculate_bounding_region(
265
+ entries: Sequence[_SortableEntry],
266
+ ) -> tuple[float, float, float, float] | None:
267
+ """计算当前元素集合的最小外接矩形。"""
268
+ if not entries:
269
+ return None
270
+
271
+ left = min(entry.left for entry in entries)
272
+ top = min(entry.top for entry in entries)
273
+ right = max(entry.right for entry in entries)
274
+ bottom = max(entry.bottom for entry in entries)
275
+ if right <= left or bottom <= top:
276
+ return None
277
+ return (left, top, right, bottom)
278
+
279
+
280
+ def _find_best_vertical_cut_with_projection(
281
+ entries: Sequence[_SortableEntry],
282
+ ) -> _CutInfo:
283
+ """寻找纵向最大投影空白,并在必要时忽略窄元素重试。"""
284
+ if len(entries) < 2:
285
+ return _CutInfo(0.0, 0.0)
286
+
287
+ edge_cut = _find_vertical_cut_by_edges(entries)
288
+ if edge_cut.gap >= MIN_GAP_THRESHOLD or len(entries) < 3:
289
+ return edge_cut
290
+
291
+ region = _calculate_bounding_region(entries)
292
+ if region is None:
293
+ return edge_cut
294
+
295
+ narrow_threshold = (region[2] - region[0]) * NARROW_ELEMENT_WIDTH_RATIO
296
+ filtered_entries = [entry for entry in entries if entry.width >= narrow_threshold]
297
+ if len(filtered_entries) < 2 or len(filtered_entries) == len(entries):
298
+ return edge_cut
299
+
300
+ filtered_cut = _find_vertical_cut_by_edges(filtered_entries)
301
+ if filtered_cut.gap > edge_cut.gap and filtered_cut.gap >= MIN_GAP_THRESHOLD:
302
+ return filtered_cut
303
+ return edge_cut
304
+
305
+
306
+ def _find_vertical_cut_by_edges(
307
+ entries: Sequence[_SortableEntry],
308
+ ) -> _CutInfo:
309
+ """根据横向区间投影寻找最大的纵向切分空白。"""
310
+ sorted_entries = sorted(
311
+ entries,
312
+ key=lambda entry: (entry.left, entry.right, entry.index),
313
+ )
314
+ largest_gap = 0.0
315
+ cut_position = 0.0
316
+ previous_right: float | None = None
317
+
318
+ for entry in sorted_entries:
319
+ if previous_right is not None and entry.left > previous_right:
320
+ gap = entry.left - previous_right
321
+ if gap > largest_gap:
322
+ largest_gap = gap
323
+ cut_position = (previous_right + entry.left) / 2.0
324
+ previous_right = entry.right if previous_right is None else max(previous_right, entry.right)
325
+ return _CutInfo(cut_position, largest_gap)
326
+
327
+
328
+ def _find_best_horizontal_cut_with_projection(
329
+ entries: Sequence[_SortableEntry],
330
+ ) -> _CutInfo:
331
+ """根据纵向区间投影寻找最大的横向切分空白。"""
332
+ if len(entries) < 2:
333
+ return _CutInfo(0.0, 0.0)
334
+
335
+ sorted_entries = sorted(
336
+ entries,
337
+ key=lambda entry: (entry.top, entry.bottom, entry.index),
338
+ )
339
+ largest_gap = 0.0
340
+ cut_position = 0.0
341
+ previous_bottom: float | None = None
342
+
343
+ for entry in sorted_entries:
344
+ if previous_bottom is not None and entry.top > previous_bottom:
345
+ gap = entry.top - previous_bottom
346
+ if gap > largest_gap:
347
+ largest_gap = gap
348
+ cut_position = (previous_bottom + entry.top) / 2.0
349
+ previous_bottom = entry.bottom if previous_bottom is None else max(previous_bottom, entry.bottom)
350
+ return _CutInfo(cut_position, largest_gap)
351
+
352
+
353
+ def _split_by_horizontal_cut(
354
+ entries: Sequence[_SortableEntry],
355
+ cut_y: float,
356
+ ) -> list[list[_SortableEntry]]:
357
+ """按横向切线将元素分成上、下两个区域。"""
358
+ above = [entry for entry in entries if entry.center_y < cut_y]
359
+ below = [entry for entry in entries if entry.center_y >= cut_y]
360
+ return [group for group in (above, below) if group]
361
+
362
+
363
+ def _split_by_vertical_cut(
364
+ entries: Sequence[_SortableEntry],
365
+ cut_x: float,
366
+ ) -> list[list[_SortableEntry]]:
367
+ """按纵向切线将元素分成左、右两个区域。"""
368
+ left = [entry for entry in entries if entry.center_x < cut_x]
369
+ right = [entry for entry in entries if entry.center_x >= cut_x]
370
+ return [group for group in (left, right) if group]
371
+
372
+
373
+ def _merge_cross_layout_elements(
374
+ sorted_main: Sequence[_SortableEntry],
375
+ cross_layout_entries: Sequence[_SortableEntry],
376
+ ) -> list[_SortableEntry]:
377
+ """按几何纵向分带回插跨栏元素,避免栏内 y 坐标重置。"""
378
+ if not cross_layout_entries:
379
+ return list(sorted_main)
380
+ if not sorted_main:
381
+ return _sort_by_y_then_x(cross_layout_entries)
382
+
383
+ result: list[_SortableEntry] = []
384
+ remaining_main = list(sorted_main)
385
+ for cross_entry in _sort_by_y_then_x(cross_layout_entries):
386
+ geometrically_above = [entry for entry in remaining_main if entry.bottom <= cross_entry.top]
387
+ result.extend(geometrically_above)
388
+ above_ids = {entry.index for entry in geometrically_above}
389
+ remaining_main = [entry for entry in remaining_main if entry.index not in above_ids]
390
+ result.append(cross_entry)
391
+
392
+ result.extend(remaining_main)
393
+ return result
394
+
395
+
396
+ def _sort_by_y_then_x(
397
+ entries: Sequence[_SortableEntry],
398
+ ) -> list[_SortableEntry]:
399
+ """在无法继续投影切分时按上到下、从左到右稳定排序。"""
400
+ return sorted(
401
+ entries,
402
+ key=lambda entry: (entry.top, entry.left, entry.index),
403
+ )
404
+
405
+
406
+ __all__ = [
407
+ "DEFAULT_BETA",
408
+ "DEFAULT_DENSITY_THRESHOLD",
409
+ "MIN_GAP_THRESHOLD",
410
+ "MIN_OVERLAP_COUNT",
411
+ "NARROW_ELEMENT_WIDTH_RATIO",
412
+ "OVERLAP_THRESHOLD",
413
+ "sort_entries",
414
+ ]
@@ -0,0 +1,44 @@
1
+ """原生分析的内部结构契约;公开 ModelJson 的 wire shape 保持不变。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any, BinaryIO, Protocol, TypedDict
6
+
7
+ from ...schema import BBox
8
+
9
+ if TYPE_CHECKING:
10
+ from ...document.pdf.document import _PDFPageSnapshot
11
+
12
+
13
+ class RawBlock(TypedDict, total=False):
14
+ """描述 raw 阶段共有字段,格式特有证据仍可附加在普通字典中。"""
15
+
16
+ type: str
17
+ bbox: BBox | list[float] | None
18
+ index: int
19
+ content: str | list[dict[str, Any]]
20
+ angle: int
21
+ image_base64: str
22
+ lines: list[dict[str, list[float]]]
23
+ _inline_math_regions: list[BBox]
24
+
25
+
26
+ class NativeBinaryAnalyzer(Protocol):
27
+ """限定 API 分派需要的二进制流预测能力,不创建统一继承框架。"""
28
+
29
+ def predict(self, file_binary: BinaryIO) -> list[list[dict[str, Any]]]:
30
+ """读取调用者持有的流并返回原生页面,不关闭该流。"""
31
+
32
+
33
+ class NativePdfSource(Protocol):
34
+ """限定原生 PDF 编排所需的页面数量与一次性证据快照。"""
35
+
36
+ @property
37
+ def page_count(self) -> int:
38
+ """返回当前所选 PDF 的物理页数。"""
39
+
40
+ def _extract_native_page(self, page_idx: int) -> _PDFPageSnapshot:
41
+ """在单个页面生命周期内收集原生证据。"""
42
+
43
+
44
+ __all__ = ["RawBlock", "NativeBinaryAnalyzer", "NativePdfSource"]