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,477 @@
1
+ """共享正文块连接的几何、内容拼接和来源规则。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from typing import Any, Sequence
7
+
8
+ from .....foundation.language import detect_lang
9
+ from .....foundation.text import merge_text_line_contents
10
+ from ..geometry import _bbox_axis_overlap_ratio, _bbox_center_y, _bbox_union_many
11
+ from ..native_text import _normalize_native_run_text
12
+
13
+ _REFERENCE_ENTRY_RE = re.compile(r"^[[\[]\s*\d+\s*[]\]]")
14
+
15
+
16
+ _FIGURE_CAPTION_MARKER_RE = re.compile(
17
+ r"^(?:图\s*[0-90-9一二三四五六七八九十]|fig(?:ure)?\.?\s*[0-9])",
18
+ re.IGNORECASE,
19
+ )
20
+
21
+
22
+ _INLINE_MATH_RECOVERY_MARKER = "_recovered_inline_math_fragments"
23
+
24
+
25
+ _PARAGRAPH_FORMULA_CONTEXT_MARKER = "_paragraph_formula_context"
26
+
27
+
28
+ _FRONT_MATTER_FIELD_RE = re.compile(
29
+ r"^\s*(?:keywords?|key\s+words?|关键词|中图分类号|文献标识码|文章编号)\s*[::]",
30
+ re.IGNORECASE,
31
+ )
32
+
33
+
34
+ _LIST_ITEM_RE = re.compile(
35
+ r"^\s*(?:[((]\s*(?:\d+|[ivxlcdm]+)\s*[))]|[①-⑳]|[•●▪])",
36
+ re.IGNORECASE,
37
+ )
38
+
39
+
40
+ _BULLET_ITEM_RE = re.compile(
41
+ r"^\s*[•●▪]",
42
+ )
43
+
44
+
45
+ _EMAIL_METADATA_RE = re.compile(
46
+ r"^\s*e[\s-]*mail\s*[::]",
47
+ re.IGNORECASE,
48
+ )
49
+
50
+
51
+ _ABSTRACT_METADATA_RE = re.compile(
52
+ r"^\s*(?:abstract|摘\s*要)\s*[::]",
53
+ re.IGNORECASE,
54
+ )
55
+
56
+
57
+ _LABELLED_METADATA_RE = re.compile(
58
+ r"^\s*(?P<label>[A-Za-z\u3400-\u9fff]{1,12})\s*[::]",
59
+ )
60
+
61
+
62
+ _URL_LINE_RE = re.compile(
63
+ r"^\s*(?:https?://|www\.)",
64
+ re.IGNORECASE,
65
+ )
66
+
67
+
68
+ _SHORT_SAME_BASELINE_PREFIX_RE = re.compile(
69
+ r"^(?:[((]\s*\d{1,3}|\d{1,2}\s*[::]\s*\d{2})$",
70
+ )
71
+
72
+
73
+ def _merge_internal_text_block_group(
74
+ blocks: list[dict[str, Any]],
75
+ indices: list[int],
76
+ *,
77
+ preserve_visual_spaces: bool = False,
78
+ ) -> dict[str, Any]:
79
+ """合并内部文本块及其版面元数据,最终输出阶段仍会统一移除这些字段。"""
80
+
81
+ ordered_indices = sorted(
82
+ indices,
83
+ key=(
84
+ (lambda index: blocks[index]["bbox"][0])
85
+ if preserve_visual_spaces
86
+ else (lambda index: _text_component_sort_key(blocks[index]))
87
+ ),
88
+ )
89
+ merged = dict(blocks[ordered_indices[0]])
90
+ merged["bbox"] = _bbox_union_many([blocks[index]["bbox"] for index in ordered_indices])
91
+ contents = [str(blocks[index].get("content", "")) for index in ordered_indices]
92
+ merged["content"] = (
93
+ " ".join(content.strip() for content in contents if content.strip())
94
+ if preserve_visual_spaces
95
+ else _merge_text_line_content(contents)
96
+ )
97
+ merged["_visual_row_ids"] = set().union(
98
+ *[row_ids for index in ordered_indices if isinstance((row_ids := blocks[index].get("_visual_row_ids")), set)]
99
+ )
100
+ merged["_single_run_row_id"] = None
101
+ merged["_local_line_bboxes"] = [bbox for index in ordered_indices for bbox in blocks[index].get("_local_line_bboxes", [])]
102
+ merged["_local_output_line_bboxes"] = [
103
+ bbox for index in ordered_indices for bbox in blocks[index].get("_local_output_line_bboxes", [])
104
+ ]
105
+ merged["_output_bbox_repaired"] = any(blocks[index].get("_output_bbox_repaired") is True for index in ordered_indices)
106
+ merged["_line_heights"] = [height for index in ordered_indices for height in blocks[index].get("_line_heights", [])]
107
+ merged["_font_signatures"] = set().union(
108
+ *[
109
+ signatures
110
+ for index in ordered_indices
111
+ if isinstance(
112
+ (signatures := blocks[index].get("_font_signatures")),
113
+ set,
114
+ )
115
+ ]
116
+ )
117
+ merged["_inline_math_regions"] = [
118
+ region for index in ordered_indices for region in blocks[index].get("_inline_math_regions", [])
119
+ ]
120
+ merged[_PARAGRAPH_FORMULA_CONTEXT_MARKER] = any(
121
+ blocks[index].get(_PARAGRAPH_FORMULA_CONTEXT_MARKER) is True for index in ordered_indices
122
+ )
123
+ return merged
124
+
125
+
126
+ def _component_declared_lane_interval(
127
+ block: dict[str, Any],
128
+ ) -> tuple[float, float] | None:
129
+ """读取组件声明的有效栏带区间,不区分普通栏或跨栏。"""
130
+
131
+ interval = block.get("_lane_interval")
132
+ if (
133
+ not isinstance(interval, (list, tuple))
134
+ or len(interval) != 2
135
+ or not all(isinstance(value, (int, float)) for value in interval)
136
+ ):
137
+ return None
138
+ left, right = float(interval[0]), float(interval[1])
139
+ return (left, right) if right > left else None
140
+
141
+
142
+ def _component_lane_interval(
143
+ block: dict[str, Any],
144
+ ) -> tuple[float, float] | None:
145
+ """读取普通文本组件所属的有效非跨栏栏带区间。"""
146
+
147
+ if block.get("_lane_is_span") is not False:
148
+ return None
149
+ return _component_declared_lane_interval(block)
150
+
151
+
152
+ def _component_reference_width(
153
+ block: dict[str, Any],
154
+ local_page_width: float,
155
+ ) -> float:
156
+ """优先返回组件的局部栏宽,缺少可靠栏带时回退页面宽度。"""
157
+
158
+ interval = _component_lane_interval(block)
159
+ return interval[1] - interval[0] if interval is not None else local_page_width
160
+
161
+
162
+ def _compatible_component_lane_width(
163
+ first_block: dict[str, Any],
164
+ second_block: dict[str, Any],
165
+ local_page_width: float,
166
+ median_height: float,
167
+ ) -> float:
168
+ """同一局部栏带的两个组件使用栏宽,否则继续使用页面宽度。"""
169
+
170
+ first_interval = _component_lane_interval(first_block)
171
+ second_interval = _component_lane_interval(second_block)
172
+ if first_interval is None or second_interval is None:
173
+ return local_page_width
174
+ tolerance = 0.75 * median_height
175
+ if abs(first_interval[0] - second_interval[0]) > tolerance or abs(first_interval[1] - second_interval[1]) > tolerance:
176
+ return local_page_width
177
+ return min(
178
+ first_interval[1] - first_interval[0],
179
+ second_interval[1] - second_interval[0],
180
+ )
181
+
182
+
183
+ def _components_share_lane_role(
184
+ first_block: dict[str, Any],
185
+ second_block: dict[str, Any],
186
+ median_height: float,
187
+ ) -> bool:
188
+ """要求二次合并组件同为跨栏或属于同一普通栏带。"""
189
+
190
+ first_role = first_block.get("_lane_is_span")
191
+ second_role = second_block.get("_lane_is_span")
192
+ if isinstance(first_role, bool) and isinstance(second_role, bool):
193
+ if first_role != second_role:
194
+ return False
195
+ if first_role:
196
+ return True
197
+ first_interval = _component_lane_interval(first_block)
198
+ second_interval = _component_lane_interval(second_block)
199
+ if first_interval is None or second_interval is None:
200
+ return False
201
+ tolerance = 0.75 * median_height
202
+ return (
203
+ abs(first_interval[0] - second_interval[0]) <= tolerance
204
+ and abs(first_interval[1] - second_interval[1]) <= tolerance
205
+ )
206
+ # 兼容缺少内部栏元数据的旧调用;生产路径始终会携带该字段。
207
+ return not isinstance(first_role, bool) and not isinstance(second_role, bool)
208
+
209
+
210
+ def _block_starts_with_short_wide_rows(
211
+ block: dict[str, Any],
212
+ local_page_width: float,
213
+ ) -> bool:
214
+ """判断组件内部是否以短首行和紧邻宽正文形成明确分组起点。"""
215
+
216
+ line_bboxes = block.get("_local_line_bboxes")
217
+ if not isinstance(line_bboxes, list) or len(line_bboxes) < 2:
218
+ return False
219
+ first_bbox, second_bbox = line_bboxes[:2]
220
+ first_width = first_bbox[2] - first_bbox[0]
221
+ second_width = second_bbox[2] - second_bbox[0]
222
+ reference_width = _component_reference_width(block, local_page_width)
223
+ return first_width <= 0.35 * reference_width and second_width >= max(0.25 * reference_width, 1.8 * first_width)
224
+
225
+
226
+ def _find_short_opener_pairs(
227
+ blocks: list[dict[str, Any]],
228
+ candidate_indices: list[int],
229
+ local_page_width: float,
230
+ median_height: float,
231
+ ) -> list[tuple[int, int]]:
232
+ """查找跨栏拆开的短首行与紧邻满宽正文组件。"""
233
+
234
+ output: list[tuple[int, int]] = []
235
+ for opener_index in candidate_indices:
236
+ opener_bboxes = blocks[opener_index]["_local_line_bboxes"]
237
+ if len(opener_bboxes) != 1:
238
+ continue
239
+ opener_bbox = opener_bboxes[0]
240
+ opener_width = opener_bbox[2] - opener_bbox[0]
241
+ matches: list[tuple[float, int]] = []
242
+ for body_index in candidate_indices:
243
+ if body_index == opener_index:
244
+ continue
245
+ if blocks[body_index].get("_hard_break_before") is True:
246
+ continue
247
+ if not _components_share_lane_role(
248
+ blocks[opener_index],
249
+ blocks[body_index],
250
+ median_height,
251
+ ):
252
+ continue
253
+ body_bbox = blocks[body_index]["_local_line_bboxes"][0]
254
+ gap = body_bbox[1] - opener_bbox[3]
255
+ body_width = body_bbox[2] - body_bbox[0]
256
+ reference_width = _compatible_component_lane_width(
257
+ blocks[opener_index],
258
+ blocks[body_index],
259
+ local_page_width,
260
+ median_height,
261
+ )
262
+ if (
263
+ not 0.0 <= gap <= 0.75 * median_height
264
+ or abs(body_bbox[0] - opener_bbox[0]) > 0.75 * median_height
265
+ or opener_width > 0.35 * reference_width
266
+ or body_width < 0.6 * reference_width
267
+ or _component_connection_skips_block(
268
+ blocks,
269
+ opener_index,
270
+ body_index,
271
+ median_height,
272
+ )
273
+ ):
274
+ continue
275
+ matches.append((gap, body_index))
276
+ if matches:
277
+ output.append((opener_index, min(matches)[1]))
278
+ return output
279
+
280
+
281
+ def _nearest_following_text_component(
282
+ blocks: list[dict[str, Any]],
283
+ current_index: int,
284
+ candidate_indices: list[int],
285
+ *,
286
+ maximum_gap: float,
287
+ section_starts: set[int],
288
+ ) -> int | None:
289
+ """返回同一水平流中紧邻且不是新分组起点的下一正文组件。"""
290
+
291
+ current_bbox = blocks[current_index]["_local_line_bboxes"][-1]
292
+ matches: list[tuple[float, float, int]] = []
293
+ for candidate_index in candidate_indices:
294
+ if candidate_index == current_index or candidate_index in section_starts:
295
+ continue
296
+ if blocks[candidate_index].get("_hard_break_before") is True:
297
+ continue
298
+ if not _components_share_lane_role(
299
+ blocks[current_index],
300
+ blocks[candidate_index],
301
+ maximum_gap / 0.75,
302
+ ):
303
+ continue
304
+ candidate_bbox = blocks[candidate_index]["_local_line_bboxes"][0]
305
+ gap = candidate_bbox[1] - current_bbox[3]
306
+ if not -0.25 * maximum_gap <= gap <= maximum_gap:
307
+ continue
308
+ overlap = _bbox_axis_overlap_ratio(current_bbox, candidate_bbox, axis="x")
309
+ left_gap = abs(candidate_bbox[0] - current_bbox[0])
310
+ if overlap < 0.5 and left_gap > 3.0 * maximum_gap:
311
+ continue
312
+ if _component_connection_skips_block(
313
+ blocks,
314
+ current_index,
315
+ candidate_index,
316
+ maximum_gap / 0.75,
317
+ ):
318
+ continue
319
+ matches.append((max(0.0, gap), left_gap, candidate_index))
320
+ return min(matches)[2] if matches else None
321
+
322
+
323
+ def _has_parallel_text_component(
324
+ blocks: list[dict[str, Any]],
325
+ current_index: int,
326
+ candidate_indices: list[int],
327
+ ) -> bool:
328
+ """检查当前组件同一纵向带内是否存在水平分离的并栏组件。"""
329
+
330
+ current_bbox = blocks[current_index]["bbox"]
331
+ for candidate_index in candidate_indices:
332
+ if candidate_index == current_index:
333
+ continue
334
+ candidate_bbox = blocks[candidate_index]["bbox"]
335
+ vertical_overlap = max(
336
+ 0.0,
337
+ min(current_bbox[3], candidate_bbox[3]) - max(current_bbox[1], candidate_bbox[1]),
338
+ )
339
+ horizontally_separate = candidate_bbox[0] >= current_bbox[2] or current_bbox[0] >= candidate_bbox[2]
340
+ if vertical_overlap > 0 and horizontally_separate:
341
+ return True
342
+ return False
343
+
344
+
345
+ def _nearest_tapered_tail_component(
346
+ blocks: list[dict[str, Any]],
347
+ current_index: int,
348
+ candidate_indices: list[int],
349
+ median_height: float,
350
+ section_starts: set[int],
351
+ ) -> int | None:
352
+ """查找左对齐、行宽递减且行距略大的信息组尾行组件。"""
353
+
354
+ previous_bbox = blocks[current_index]["_local_line_bboxes"][-1]
355
+ previous_width = previous_bbox[2] - previous_bbox[0]
356
+ matches: list[tuple[float, int]] = []
357
+ for candidate_index in candidate_indices:
358
+ if candidate_index == current_index or candidate_index in section_starts:
359
+ continue
360
+ if blocks[candidate_index].get("_hard_break_before") is True:
361
+ continue
362
+ if not _components_share_lane_role(
363
+ blocks[current_index],
364
+ blocks[candidate_index],
365
+ median_height,
366
+ ):
367
+ continue
368
+ candidate_bboxes = blocks[candidate_index]["_local_line_bboxes"]
369
+ first_bbox = candidate_bboxes[0]
370
+ last_bbox = candidate_bboxes[-1]
371
+ gap = first_bbox[1] - previous_bbox[3]
372
+ first_width = first_bbox[2] - first_bbox[0]
373
+ last_width = last_bbox[2] - last_bbox[0]
374
+ if (
375
+ not 0.75 * median_height < gap <= 1.5 * median_height
376
+ or len(candidate_bboxes) > 2
377
+ or abs(first_bbox[0] - previous_bbox[0]) > 0.75 * median_height
378
+ or first_width > 0.85 * previous_width
379
+ or last_width > first_width + 0.5 * median_height
380
+ or _component_connection_skips_block(
381
+ blocks,
382
+ current_index,
383
+ candidate_index,
384
+ median_height,
385
+ )
386
+ ):
387
+ continue
388
+ matches.append((gap, candidate_index))
389
+ return min(matches)[1] if matches else None
390
+
391
+
392
+ def _component_connection_skips_block(
393
+ blocks: list[dict[str, Any]],
394
+ first_index: int,
395
+ second_index: int,
396
+ median_height: float,
397
+ ) -> bool:
398
+ """检查两个正文组件之间是否已有同水平流的中间块,禁止二次合并跨越它。"""
399
+
400
+ first_bbox = blocks[first_index]["_local_line_bboxes"][-1]
401
+ second_bbox = blocks[second_index]["_local_line_bboxes"][0]
402
+ first_center = _bbox_center_y(first_bbox)
403
+ second_center = _bbox_center_y(second_bbox)
404
+ corridor_top, corridor_bottom = sorted((first_center, second_center))
405
+ corridor_bbox = (
406
+ min(first_bbox[0], second_bbox[0]),
407
+ corridor_top,
408
+ max(first_bbox[2], second_bbox[2]),
409
+ corridor_bottom,
410
+ )
411
+ for index, block in enumerate(blocks):
412
+ if index in {first_index, second_index}:
413
+ continue
414
+ local_bboxes = block.get("_local_line_bboxes")
415
+ if not isinstance(local_bboxes, list) or not local_bboxes:
416
+ continue
417
+ other_bbox = local_bboxes[0]
418
+ other_center = _bbox_center_y(other_bbox)
419
+ if not (corridor_top + 0.1 * median_height < other_center < corridor_bottom - 0.1 * median_height):
420
+ continue
421
+ if _bbox_axis_overlap_ratio(corridor_bbox, other_bbox, axis="x") >= 0.2:
422
+ return True
423
+ return False
424
+
425
+
426
+ def _text_component_sort_key(block: dict[str, Any]) -> tuple[float, float]:
427
+ """返回正文组件按局部首行位置排序的稳定键。"""
428
+
429
+ first_bbox = block["_local_line_bboxes"][0]
430
+ return first_bbox[1], first_bbox[0]
431
+
432
+
433
+ def _merge_text_line_content(line_texts: Sequence[str]) -> str:
434
+ """按 Hybrid 语言与行末连字规则折叠普通文本行。"""
435
+
436
+ normalized_lines = [_normalize_native_run_text(str(text or "")) for text in line_texts]
437
+ normalized_lines = [text for text in normalized_lines if text]
438
+ if not normalized_lines:
439
+ return ""
440
+ try:
441
+ block_language = detect_lang("".join(normalized_lines))
442
+ except Exception:
443
+ block_language = ""
444
+ return merge_text_line_contents(
445
+ normalized_lines,
446
+ block_language=block_language,
447
+ )
448
+
449
+
450
+ __all__ = [
451
+ "_REFERENCE_ENTRY_RE",
452
+ "_FIGURE_CAPTION_MARKER_RE",
453
+ "_INLINE_MATH_RECOVERY_MARKER",
454
+ "_PARAGRAPH_FORMULA_CONTEXT_MARKER",
455
+ "_FRONT_MATTER_FIELD_RE",
456
+ "_LIST_ITEM_RE",
457
+ "_BULLET_ITEM_RE",
458
+ "_EMAIL_METADATA_RE",
459
+ "_ABSTRACT_METADATA_RE",
460
+ "_LABELLED_METADATA_RE",
461
+ "_URL_LINE_RE",
462
+ "_SHORT_SAME_BASELINE_PREFIX_RE",
463
+ "_merge_internal_text_block_group",
464
+ "_component_declared_lane_interval",
465
+ "_component_lane_interval",
466
+ "_component_reference_width",
467
+ "_compatible_component_lane_width",
468
+ "_components_share_lane_role",
469
+ "_block_starts_with_short_wide_rows",
470
+ "_find_short_opener_pairs",
471
+ "_nearest_following_text_component",
472
+ "_has_parallel_text_component",
473
+ "_nearest_tapered_tail_component",
474
+ "_component_connection_skips_block",
475
+ "_text_component_sort_key",
476
+ "_merge_text_line_content",
477
+ ]