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,383 @@
1
+ """将 PDF 字符或 OCR 结果投影为空间文本的共享算法。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import statistics
6
+ from dataclasses import dataclass
7
+ from typing import Any
8
+
9
+ import numpy as np
10
+ from ....document.pdf.text.contracts import Char
11
+
12
+ from ....schema import BBox
13
+ from .table_geometry import normalize_bbox as _coerce_bbox, rotate_local_bbox as _rotate_local_bbox
14
+
15
+
16
+ # 空间投影思路参考 LiteParse v2.6.0 的字符分段和网格投影;
17
+ # 本模块只针对已有 table bbox 重新实现,不引入 LiteParse 运行时依赖。
18
+ _MAX_INLINE_GAP = 15.0
19
+ _Y_TOLERANCE = 2.0
20
+ _PENDING_SPACE_SPLIT_RATIO = 2.2
21
+ _MISSING_SPACE_HEIGHT_RATIO = 0.35
22
+ _LINE_HEIGHT_RATIO = 1.8
23
+
24
+ _PUNCTUATION_TRANSLATION = str.maketrans(
25
+ {
26
+ "\u2018": "'",
27
+ "\u2019": "'",
28
+ "\u201a": "'",
29
+ "\u2032": "'",
30
+ "\u201c": '"',
31
+ "\u201d": '"',
32
+ "\u201e": '"',
33
+ "\u2033": '"',
34
+ "\u2010": "-",
35
+ "\u2011": "-",
36
+ "\u2012": "-",
37
+ "\u2013": "-",
38
+ "\u2014": "-",
39
+ "\u2015": "-",
40
+ "\u2212": "-",
41
+ "\u00a0": " ",
42
+ "\u0002": "-",
43
+ "\ufb00": "ff",
44
+ "\ufb01": "fi",
45
+ "\ufb02": "fl",
46
+ "\ufb03": "ffi",
47
+ "\ufb04": "ffl",
48
+ "\ufb05": "ft",
49
+ "\ufb06": "st",
50
+ }
51
+ )
52
+
53
+
54
+ @dataclass(slots=True)
55
+ class _SpatialTextItem:
56
+ """保存表格局部坐标中的文本、外接框和识别置信度。"""
57
+
58
+ text: str
59
+ bbox: BBox
60
+ confidence: float = 1.0
61
+
62
+
63
+ def _normalize_table_text(value: Any) -> str:
64
+ """统一表格文本中的连字、控制横线和排版标点。"""
65
+ if not isinstance(value, str):
66
+ return ""
67
+ return value.translate(_PUNCTUATION_TRANSLATION)
68
+
69
+
70
+ def _bbox_union(bbox1: BBox, bbox2: BBox) -> BBox:
71
+ """合并两个字符框,得到当前文本片段的外接框。"""
72
+ return (
73
+ min(bbox1[0], bbox2[0]),
74
+ min(bbox1[1], bbox2[1]),
75
+ max(bbox1[2], bbox2[2]),
76
+ max(bbox1[3], bbox2[3]),
77
+ )
78
+
79
+
80
+ def _normalize_angle(angle: Any) -> int:
81
+ """把已有表格角度限制到四个标准方向,非法值按零度处理。"""
82
+ try:
83
+ normalized_angle = int(float(angle or 0)) % 360
84
+ except (TypeError, ValueError):
85
+ return 0
86
+ return normalized_angle if normalized_angle in {0, 90, 180, 270} else 0
87
+
88
+
89
+ def _select_table_chars(chars: list[Char], table_bbox: BBox) -> list[Char]:
90
+ """按字符框中心点选择表格内字符,并保持原始字符流顺序。"""
91
+ x0, y0, x1, y1 = table_bbox
92
+ selected_chars: list[tuple[int, int, Char]] = []
93
+ for fallback_idx, char in enumerate(chars):
94
+ try:
95
+ char_bbox = [float(value) for value in char.get("bbox", [])]
96
+ except (TypeError, ValueError):
97
+ continue
98
+ if len(char_bbox) != 4:
99
+ continue
100
+ center_x = (char_bbox[0] + char_bbox[2]) / 2.0
101
+ center_y = (char_bbox[1] + char_bbox[3]) / 2.0
102
+ if not (x0 <= center_x <= x1 and y0 <= center_y <= y1):
103
+ continue
104
+ try:
105
+ char_idx = int(char.get("char_idx", fallback_idx))
106
+ except (TypeError, ValueError):
107
+ char_idx = fallback_idx
108
+ selected_chars.append((char_idx, fallback_idx, char))
109
+
110
+ selected_chars.sort(key=lambda item: (item[0], item[1]))
111
+ return [item[2] for item in selected_chars]
112
+
113
+
114
+ def _build_pdf_spatial_items(chars: list[Char], table_bbox: BBox, angle: int) -> list[_SpatialTextItem]:
115
+ """按换行、字符间距和几何连续性把 PDF 字符流拆成空间文本项。"""
116
+ table_x0, table_y0, table_x1, table_y1 = table_bbox
117
+ table_width = table_x1 - table_x0
118
+ table_height = table_y1 - table_y0
119
+ normalized_angle = _normalize_angle(angle)
120
+ spatial_items: list[_SpatialTextItem] = []
121
+
122
+ segment_parts: list[str] = []
123
+ segment_bbox: BBox | None = None
124
+ last_char_bbox: BBox | None = None
125
+ char_widths: list[float] = []
126
+ pending_space = False
127
+
128
+ def flush_segment() -> None:
129
+ """提交当前 PDF 文本片段,并重置片段累计状态。"""
130
+ nonlocal segment_parts, segment_bbox, last_char_bbox, char_widths, pending_space
131
+ text = _normalize_table_text("".join(segment_parts)).strip()
132
+ if text and segment_bbox is not None:
133
+ rotated_bbox = _rotate_local_bbox(
134
+ segment_bbox,
135
+ table_width,
136
+ table_height,
137
+ normalized_angle,
138
+ )
139
+ spatial_items.append(_SpatialTextItem(text=text, bbox=rotated_bbox))
140
+ segment_parts = []
141
+ segment_bbox = None
142
+ last_char_bbox = None
143
+ char_widths = []
144
+ pending_space = False
145
+
146
+ for char in _select_table_chars(chars, table_bbox):
147
+ raw_char = str(char.get("char") or "")
148
+ if raw_char in {"\r", "\n"}:
149
+ flush_segment()
150
+ continue
151
+ if raw_char.isspace():
152
+ if segment_parts:
153
+ pending_space = True
154
+ continue
155
+
156
+ absolute_bbox = _coerce_bbox(char.get("bbox"))
157
+ if absolute_bbox is None:
158
+ continue
159
+ local_bbox = (
160
+ absolute_bbox[0] - table_x0,
161
+ absolute_bbox[1] - table_y0,
162
+ absolute_bbox[2] - table_x0,
163
+ absolute_bbox[3] - table_y0,
164
+ )
165
+ char_height = local_bbox[3] - local_bbox[1]
166
+ if char_height < 0.5:
167
+ continue
168
+
169
+ normalized_char = _normalize_table_text(raw_char)
170
+ if not normalized_char:
171
+ continue
172
+
173
+ if segment_parts and segment_bbox is not None and last_char_bbox is not None:
174
+ gap = local_bbox[0] - last_char_bbox[2]
175
+ y_overlap = local_bbox[1] < segment_bbox[3] + _Y_TOLERANCE and local_bbox[3] > segment_bbox[1] - _Y_TOLERANCE
176
+ strict_below = local_bbox[1] > last_char_bbox[3]
177
+ segment_width = segment_bbox[2] - segment_bbox[0]
178
+ line_changed = (
179
+ local_bbox[1] > last_char_bbox[3] + _Y_TOLERANCE
180
+ or (strict_below and gap < -5.0)
181
+ or (segment_width > 20.0 and gap < -(segment_width * 0.5))
182
+ )
183
+ average_char_width = sum(char_widths) / len(char_widths)
184
+ should_split = (
185
+ not y_overlap
186
+ or line_changed
187
+ or gap >= _MAX_INLINE_GAP
188
+ or (pending_space and gap > average_char_width * _PENDING_SPACE_SPLIT_RATIO)
189
+ )
190
+ if should_split:
191
+ flush_segment()
192
+ elif pending_space:
193
+ segment_parts.append(" ")
194
+ pending_space = False
195
+ else:
196
+ previous_char = segment_parts[-1][-1] if segment_parts[-1] else ""
197
+ current_char = normalized_char[0]
198
+ if previous_char.isalnum() and current_char.isalnum() and gap > char_height * _MISSING_SPACE_HEIGHT_RATIO:
199
+ segment_parts.append(" ")
200
+
201
+ if segment_bbox is None:
202
+ segment_bbox = local_bbox
203
+ else:
204
+ segment_bbox = _bbox_union(segment_bbox, local_bbox)
205
+ segment_parts.append(normalized_char)
206
+ last_char_bbox = local_bbox
207
+ char_widths.append(local_bbox[2] - local_bbox[0])
208
+
209
+ flush_segment()
210
+ return spatial_items
211
+
212
+
213
+ def _build_ocr_spatial_items(ocr_result: Any, table_size: tuple[int, int]) -> list[_SpatialTextItem]:
214
+ """把 MinerU OCR 四点框结果转换成可投影的空间文本项。"""
215
+ table_width, table_height = table_size
216
+ spatial_items: list[_SpatialTextItem] = []
217
+ for raw_item in ocr_result or []:
218
+ if not raw_item or len(raw_item) < 2:
219
+ continue
220
+ rec_result = raw_item[1]
221
+ if not rec_result or len(rec_result) < 2:
222
+ continue
223
+ text = _normalize_table_text(rec_result[0]).strip()
224
+ if not text:
225
+ continue
226
+ try:
227
+ points = np.asarray(raw_item[0], dtype=np.float32).reshape(-1, 2)
228
+ except (TypeError, ValueError):
229
+ continue
230
+ if points.size == 0 or not np.isfinite(points).all():
231
+ continue
232
+ x0 = max(0.0, float(np.min(points[:, 0])))
233
+ y0 = max(0.0, float(np.min(points[:, 1])))
234
+ x1 = min(float(table_width), float(np.max(points[:, 0])))
235
+ y1 = min(float(table_height), float(np.max(points[:, 1])))
236
+ bbox = _coerce_bbox((x0, y0, x1, y1))
237
+ if bbox is None:
238
+ continue
239
+ try:
240
+ confidence = float(rec_result[1] or 0.0)
241
+ except (TypeError, ValueError):
242
+ confidence = 0.0
243
+ spatial_items.append(_SpatialTextItem(text=text, bbox=bbox, confidence=confidence))
244
+ return spatial_items
245
+
246
+
247
+ def _compute_text_grid_size(items: list[_SpatialTextItem]) -> tuple[float, float]:
248
+ """使用文本项的平均字符宽度和框高计算稳健的中位网格尺寸。"""
249
+ char_widths = [
250
+ (item.bbox[2] - item.bbox[0]) / max(1, len(item.text)) for item in items if item.bbox[2] > item.bbox[0] and item.text
251
+ ]
252
+ heights = [item.bbox[3] - item.bbox[1] for item in items if item.bbox[3] > item.bbox[1]]
253
+ median_width = statistics.median(char_widths) if char_widths else 1.0
254
+ median_height = statistics.median(heights) if heights else 1.0
255
+ return max(0.1, float(median_width)), max(0.1, float(median_height))
256
+
257
+
258
+ def _form_spatial_lines(
259
+ items: list[_SpatialTextItem],
260
+ median_width: float,
261
+ median_height: float,
262
+ ) -> list[list[_SpatialTextItem]]:
263
+ """依据 y 网格、垂直交叠和水平碰撞关系把文本项归并为视觉行。"""
264
+ y_sort_tolerance = max(5.0, median_height * 0.5)
265
+ sorted_items = sorted(
266
+ items,
267
+ key=lambda item: (round(item.bbox[1] / y_sort_tolerance), item.bbox[0]),
268
+ )
269
+ lines: list[list[_SpatialTextItem]] = []
270
+ for item in sorted_items:
271
+ if not lines:
272
+ lines.append([item])
273
+ continue
274
+
275
+ current_line = lines[-1]
276
+ line_top = min(line_item.bbox[1] for line_item in current_line)
277
+ line_bottom = max(line_item.bbox[3] for line_item in current_line)
278
+ horizontal_collision = any(
279
+ min(line_item.bbox[2], item.bbox[2]) - max(line_item.bbox[0], item.bbox[0]) > max(5.0, median_width / 3.0)
280
+ for line_item in current_line
281
+ )
282
+ proposed_top = min(line_top, item.bbox[1])
283
+ proposed_bottom = max(line_bottom, item.bbox[3])
284
+ item_center_y = (item.bbox[1] + item.bbox[3]) / 2.0
285
+ vertically_compatible = line_top <= item_center_y <= line_bottom or line_top <= item.bbox[1] <= line_bottom
286
+ if (
287
+ not horizontal_collision
288
+ and vertically_compatible
289
+ and proposed_bottom - proposed_top <= median_height * _LINE_HEIGHT_RATIO
290
+ ):
291
+ current_line.append(item)
292
+ else:
293
+ lines.append([item])
294
+
295
+ for line in lines:
296
+ line.sort(key=lambda item: item.bbox[0])
297
+ lines.sort(key=lambda line: min(item.bbox[1] for item in line))
298
+ return lines
299
+
300
+
301
+ def _trim_projected_lines(lines: list[str]) -> str:
302
+ """清理行尾空格和公共左缩进,同时保留表格内部列间距。"""
303
+ trimmed_lines = [line.rstrip() for line in lines]
304
+ while trimmed_lines and not trimmed_lines[0]:
305
+ trimmed_lines.pop(0)
306
+ while trimmed_lines and not trimmed_lines[-1]:
307
+ trimmed_lines.pop()
308
+ if not trimmed_lines:
309
+ return ""
310
+
311
+ non_empty_lines = [line for line in trimmed_lines if line]
312
+ common_indent = min(len(line) - len(line.lstrip(" ")) for line in non_empty_lines)
313
+ if common_indent:
314
+ trimmed_lines = [line[common_indent:] if line else "" for line in trimmed_lines]
315
+ return "\n".join(trimmed_lines)
316
+
317
+
318
+ def _project_spatial_items(
319
+ items: list[_SpatialTextItem],
320
+ *,
321
+ preserve_blank_rows: bool = False,
322
+ ) -> str:
323
+ """把空间文本项投影到等宽字符网格,并按需保留明显的空白行。"""
324
+ valid_items = [item for item in items if item.text and item.bbox[2] > item.bbox[0] and item.bbox[3] > item.bbox[1]]
325
+ if not valid_items:
326
+ return ""
327
+
328
+ median_width, median_height = _compute_text_grid_size(valid_items)
329
+ spatial_lines = _form_spatial_lines(valid_items, median_width, median_height)
330
+ projected_lines: list[str] = []
331
+ previous_bottom: float | None = None
332
+ for line in spatial_lines:
333
+ line_top = min(item.bbox[1] for item in line)
334
+ if preserve_blank_rows and previous_bottom is not None and line_top - previous_bottom > 1.25 * median_height:
335
+ blank_count = max(
336
+ 1,
337
+ round((line_top - previous_bottom) / median_height) - 1,
338
+ )
339
+ projected_lines.extend("" for _ in range(blank_count))
340
+ projected_line = ""
341
+ for item in line:
342
+ target_column = max(0, round(item.bbox[0] / median_width))
343
+ minimum_column = len(projected_line)
344
+ if projected_line and not projected_line.endswith(" "):
345
+ minimum_column += 1
346
+ target_column = max(target_column, minimum_column)
347
+ projected_line += " " * (target_column - len(projected_line))
348
+ projected_line += item.text
349
+ projected_lines.append(projected_line)
350
+ previous_bottom = max(item.bbox[3] for item in line)
351
+ return _trim_projected_lines(projected_lines)
352
+
353
+
354
+ def project_pdf_spatial_text(
355
+ chars: list[Char],
356
+ region_bbox: BBox,
357
+ angle: int = 0,
358
+ *,
359
+ preserve_blank_rows: bool = False,
360
+ ) -> str:
361
+ """从 PDF 指定区域提取字符,并返回可选保留空行的空间投影文本。"""
362
+
363
+ normalized_bbox = _coerce_bbox(region_bbox)
364
+ if normalized_bbox is None:
365
+ return ""
366
+ return _project_spatial_items(
367
+ _build_pdf_spatial_items(chars, normalized_bbox, angle),
368
+ preserve_blank_rows=preserve_blank_rows,
369
+ )
370
+
371
+
372
+ def project_pdf_table_text(chars: list[Char], table_bbox: BBox, angle: int = 0) -> str:
373
+ """从 PDF 原生字符中提取指定表格,并返回空间投影纯文本。"""
374
+
375
+ return project_pdf_spatial_text(chars, table_bbox, angle)
376
+
377
+
378
+ def project_ocr_table_text(ocr_result: Any, table_size: tuple[int, int]) -> str:
379
+ """从 MinerU OCR 结果生成指定表格的空间投影纯文本。"""
380
+ table_width, table_height = table_size
381
+ if table_width <= 0 or table_height <= 0:
382
+ return ""
383
+ return _project_spatial_items(_build_ocr_spatial_items(ocr_result, table_size))