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,356 @@
1
+ """Native PDF 表格候选的网格校验、字符落格和 HTML 序列化。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import html
6
+ from bisect import bisect_left, bisect_right
7
+ from collections.abc import Callable
8
+ from dataclasses import dataclass
9
+
10
+ from .....schema import BBox
11
+
12
+ from .contracts import NativeTableCandidate, NativeTableCandidateSource, NativeTableCell, NativeTableGlyph, NativeTableText
13
+ from .geometry import bbox_center
14
+ from .text import build_cell_text, glyph_overlap_ratio
15
+
16
+ MIN_TEXT_CAPTURE = 0.98
17
+
18
+
19
+ @dataclass(frozen=True, slots=True)
20
+ class GridCellSpec:
21
+ """保存尚未回填文本的逻辑网格单元格。"""
22
+
23
+ row: int
24
+ col: int
25
+ rowspan: int
26
+ colspan: int
27
+ bbox: BBox
28
+
29
+
30
+ @dataclass(frozen=True, slots=True)
31
+ class _GridSpecIndex:
32
+ """保存规则网格的原子轨道和原子格到逻辑单元格映射。"""
33
+
34
+ x_tracks: tuple[float, ...]
35
+ y_tracks: tuple[float, ...]
36
+ owners: tuple[tuple[int, ...], ...]
37
+
38
+
39
+ def _validate_grid_specs(
40
+ rows: int,
41
+ cols: int,
42
+ specs: tuple[GridCellSpec, ...],
43
+ *,
44
+ allow_single_row: bool = False,
45
+ allow_single_column: bool = False,
46
+ ) -> bool:
47
+ """校验逻辑单元格完整覆盖矩形网格且没有重叠。"""
48
+
49
+ minimum_rows = 1 if allow_single_row else 2
50
+ minimum_cols = 1 if allow_single_column else 2
51
+ if rows < minimum_rows or cols < minimum_cols or (rows == 1 and cols == 1) or not specs:
52
+ return False
53
+ occupied = [[False for _ in range(cols)] for _ in range(rows)]
54
+ for spec in specs:
55
+ if (
56
+ spec.row < 0
57
+ or spec.col < 0
58
+ or spec.rowspan < 1
59
+ or spec.colspan < 1
60
+ or spec.row + spec.rowspan > rows
61
+ or spec.col + spec.colspan > cols
62
+ or spec.bbox[2] <= spec.bbox[0]
63
+ or spec.bbox[3] <= spec.bbox[1]
64
+ ):
65
+ return False
66
+ for row_index in range(spec.row, spec.row + spec.rowspan):
67
+ for col_index in range(spec.col, spec.col + spec.colspan):
68
+ if occupied[row_index][col_index]:
69
+ return False
70
+ occupied[row_index][col_index] = True
71
+ return all(all(row) for row in occupied)
72
+
73
+
74
+ def _choose_cell_for_glyph(
75
+ glyph: NativeTableGlyph,
76
+ specs: tuple[GridCellSpec, ...],
77
+ ) -> tuple[int | None, bool]:
78
+ """按字符面积交叠选择唯一单元格,并标记近似平局的边界歧义。"""
79
+
80
+ overlaps = [(glyph_overlap_ratio(glyph, spec.bbox), index) for index, spec in enumerate(specs)]
81
+ overlaps.sort(reverse=True)
82
+ best_ratio, best_index = overlaps[0]
83
+ if best_ratio <= 0:
84
+ center_x, center_y = bbox_center(glyph.bbox)
85
+ containing = [
86
+ index
87
+ for index, spec in enumerate(specs)
88
+ if spec.bbox[0] <= center_x <= spec.bbox[2] and spec.bbox[1] <= center_y <= spec.bbox[3]
89
+ ]
90
+ return (containing[0], False) if len(containing) == 1 else (None, False)
91
+ ambiguous = len(overlaps) > 1 and overlaps[1][0] >= 0.45 and abs(best_ratio - overlaps[1][0]) <= 0.02
92
+ return best_index, ambiguous
93
+
94
+
95
+ def _build_grid_spec_index(
96
+ rows: int,
97
+ cols: int,
98
+ specs: tuple[GridCellSpec, ...],
99
+ ) -> _GridSpecIndex | None:
100
+ """从完整矩形网格规格恢复原子轨道,供大表快速落格。"""
101
+
102
+ x_values: list[list[float]] = [[] for _ in range(cols + 1)]
103
+ y_values: list[list[float]] = [[] for _ in range(rows + 1)]
104
+ owners = [[-1 for _ in range(cols)] for _ in range(rows)]
105
+ for index, spec in enumerate(specs):
106
+ x_values[spec.col].append(spec.bbox[0])
107
+ x_values[spec.col + spec.colspan].append(spec.bbox[2])
108
+ y_values[spec.row].append(spec.bbox[1])
109
+ y_values[spec.row + spec.rowspan].append(spec.bbox[3])
110
+ for row in range(spec.row, spec.row + spec.rowspan):
111
+ for col in range(spec.col, spec.col + spec.colspan):
112
+ owners[row][col] = index
113
+ if any(not values for values in (*x_values, *y_values)) or any(owner < 0 for row in owners for owner in row):
114
+ return None
115
+ x_tracks = tuple(sum(values) / len(values) for values in x_values)
116
+ y_tracks = tuple(sum(values) / len(values) for values in y_values)
117
+ if any(current <= previous for previous, current in zip(x_tracks, x_tracks[1:])) or any(
118
+ current <= previous for previous, current in zip(y_tracks, y_tracks[1:])
119
+ ):
120
+ return None
121
+ return _GridSpecIndex(
122
+ x_tracks=x_tracks,
123
+ y_tracks=y_tracks,
124
+ owners=tuple(tuple(row) for row in owners),
125
+ )
126
+
127
+
128
+ def _choose_cell_for_glyph_indexed(
129
+ glyph: NativeTableGlyph,
130
+ specs: tuple[GridCellSpec, ...],
131
+ index: _GridSpecIndex,
132
+ ) -> tuple[int | None, bool]:
133
+ """只在字符覆盖的邻近原子格中选择逻辑单元格。"""
134
+
135
+ cols = len(index.x_tracks) - 1
136
+ rows = len(index.y_tracks) - 1
137
+ left_col = max(0, min(cols - 1, bisect_right(index.x_tracks, glyph.bbox[0]) - 1))
138
+ right_col = max(
139
+ 0,
140
+ min(cols - 1, bisect_left(index.x_tracks, glyph.bbox[2]) - 1),
141
+ )
142
+ top_row = max(0, min(rows - 1, bisect_right(index.y_tracks, glyph.bbox[1]) - 1))
143
+ bottom_row = max(
144
+ 0,
145
+ min(rows - 1, bisect_left(index.y_tracks, glyph.bbox[3]) - 1),
146
+ )
147
+ candidate_indices = {
148
+ index.owners[row][col] for row in range(top_row, bottom_row + 1) for col in range(left_col, right_col + 1)
149
+ }
150
+ overlaps = [(glyph_overlap_ratio(glyph, specs[cell_index].bbox), cell_index) for cell_index in candidate_indices]
151
+ overlaps.sort(reverse=True)
152
+ if not overlaps:
153
+ return None, False
154
+ best_ratio, best_index = overlaps[0]
155
+ if best_ratio <= 0:
156
+ center_x, center_y = bbox_center(glyph.bbox)
157
+ containing = [
158
+ cell_index
159
+ for cell_index in candidate_indices
160
+ if specs[cell_index].bbox[0] <= center_x <= specs[cell_index].bbox[2]
161
+ and specs[cell_index].bbox[1] <= center_y <= specs[cell_index].bbox[3]
162
+ ]
163
+ return (containing[0], False) if len(containing) == 1 else (None, False)
164
+ ambiguous = len(overlaps) > 1 and overlaps[1][0] >= 0.45 and abs(best_ratio - overlaps[1][0]) <= 0.02
165
+ return best_index, ambiguous
166
+
167
+
168
+ def _order_consistency(
169
+ text: NativeTableText,
170
+ assignments: dict[int, int],
171
+ specs: tuple[GridCellSpec, ...],
172
+ ) -> float:
173
+ """衡量每条视觉行中的字符单元格序号是否保持从左到右单调。"""
174
+
175
+ comparable = 0
176
+ ordered_pairs = 0
177
+ glyph_by_id = {glyph.glyph_id: glyph for glyph in text.glyphs}
178
+ for row in text.rows:
179
+ glyphs = sorted(
180
+ (glyph_by_id[glyph_id] for glyph_id in row.glyph_ids if glyph_id in assignments),
181
+ key=lambda glyph: (glyph.bbox[0], glyph.glyph_id),
182
+ )
183
+ previous_position: tuple[int, int] | None = None
184
+ for glyph in glyphs:
185
+ spec = specs[assignments[glyph.glyph_id]]
186
+ position = spec.row, spec.col
187
+ if previous_position is not None:
188
+ comparable += 1
189
+ if position >= previous_position:
190
+ ordered_pairs += 1
191
+ previous_position = position
192
+ return ordered_pairs / comparable if comparable else 1.0
193
+
194
+
195
+ def _count_split_tokens(
196
+ text: NativeTableText,
197
+ assignments: dict[int, int],
198
+ ) -> int:
199
+ """统计字符被分配到多个逻辑单元格的原子 token。"""
200
+
201
+ split_count = 0
202
+ for row in text.rows:
203
+ for token in row.tokens:
204
+ owners = {assignments[glyph_id] for glyph_id in token.glyph_ids if glyph_id in assignments}
205
+ if len(owners) > 1:
206
+ split_count += 1
207
+ return split_count
208
+
209
+
210
+ def build_candidate(
211
+ *,
212
+ source: NativeTableCandidateSource,
213
+ rows: int,
214
+ cols: int,
215
+ specs: tuple[GridCellSpec, ...],
216
+ text: NativeTableText,
217
+ structure_support: float,
218
+ row_stability: float,
219
+ column_stability: float,
220
+ issues: tuple[str, ...] = (),
221
+ allow_single_row: bool = False,
222
+ allow_single_column: bool = False,
223
+ require_atomic_tokens: bool = False,
224
+ use_grid_index: bool = False,
225
+ diagnostics: dict[str, object] | None = None,
226
+ ) -> NativeTableCandidate | None:
227
+ """校验网格、唯一分配字符并计算统一质量分。"""
228
+
229
+ if not _validate_grid_specs(
230
+ rows,
231
+ cols,
232
+ specs,
233
+ allow_single_row=allow_single_row,
234
+ allow_single_column=allow_single_column,
235
+ ):
236
+ if diagnostics is not None:
237
+ diagnostics["candidate_rejection_gate"] = "grid_specs"
238
+ return None
239
+ assignments: dict[int, int] = {}
240
+ cell_glyphs: list[list[NativeTableGlyph]] = [[] for _ in specs]
241
+ ambiguous_count = 0
242
+ grid_index = _build_grid_spec_index(rows, cols, specs) if use_grid_index else None
243
+ for glyph in text.glyphs:
244
+ cell_index, ambiguous = (
245
+ _choose_cell_for_glyph_indexed(glyph, specs, grid_index)
246
+ if grid_index is not None
247
+ else _choose_cell_for_glyph(glyph, specs)
248
+ )
249
+ if cell_index is None:
250
+ continue
251
+ assignments[glyph.glyph_id] = cell_index
252
+ cell_glyphs[cell_index].append(glyph)
253
+ ambiguous_count += int(ambiguous)
254
+
255
+ glyph_count = len(text.glyphs)
256
+ text_capture = len(assignments) / glyph_count if glyph_count else 0.0
257
+ ambiguous_ratio = ambiguous_count / glyph_count if glyph_count else 0.0
258
+ split_token_count = _count_split_tokens(text, assignments)
259
+ if diagnostics is not None:
260
+ diagnostics["token_split_count"] = split_token_count
261
+ diagnostics["ambiguous_glyph_ratio"] = ambiguous_ratio
262
+ if text_capture < MIN_TEXT_CAPTURE or ambiguous_ratio > 0.02:
263
+ if diagnostics is not None:
264
+ diagnostics["candidate_rejection_gate"] = "text_assignment"
265
+ return None
266
+ if require_atomic_tokens and split_token_count:
267
+ if diagnostics is not None:
268
+ diagnostics["candidate_rejection_gate"] = "token_split"
269
+ return None
270
+ cells = tuple(
271
+ NativeTableCell(
272
+ row=spec.row,
273
+ col=spec.col,
274
+ rowspan=spec.rowspan,
275
+ colspan=spec.colspan,
276
+ bbox=spec.bbox,
277
+ content=build_cell_text(
278
+ cell_glyphs[index],
279
+ text.median_glyph_height,
280
+ ),
281
+ source_char_indices=tuple(
282
+ glyph.source_index
283
+ for glyph in sorted(
284
+ cell_glyphs[index],
285
+ key=lambda item: (item.visual_row, item.bbox[0], item.glyph_id),
286
+ )
287
+ ),
288
+ )
289
+ for index, spec in enumerate(specs)
290
+ )
291
+ order_consistency = _order_consistency(text, assignments, specs)
292
+ normalized_structure = max(0.0, min(1.0, structure_support))
293
+ normalized_row = max(0.0, min(1.0, row_stability))
294
+ normalized_column = max(0.0, min(1.0, column_stability))
295
+ score = min(
296
+ text_capture,
297
+ normalized_structure,
298
+ normalized_row,
299
+ normalized_column,
300
+ order_consistency,
301
+ )
302
+ if diagnostics is not None:
303
+ diagnostics["candidate_rejection_gate"] = None
304
+ return NativeTableCandidate(
305
+ source=source,
306
+ rows=rows,
307
+ cols=cols,
308
+ cells=cells,
309
+ score=score,
310
+ text_capture=text_capture,
311
+ structure_support=normalized_structure,
312
+ row_stability=normalized_row,
313
+ column_stability=normalized_column,
314
+ order_consistency=order_consistency,
315
+ issues=issues,
316
+ )
317
+
318
+
319
+ def serialize_candidate_html(candidate: NativeTableCandidate) -> str:
320
+ """把合法候选序列化为稳定、转义且不猜测表头语义的 HTML。"""
321
+
322
+ return serialize_native_table_html(candidate.rows, candidate.cells)
323
+
324
+
325
+ def serialize_native_table_html(
326
+ rows: int,
327
+ cells: tuple[NativeTableCell, ...],
328
+ *,
329
+ render_cell: Callable[[NativeTableCell], str] | None = None,
330
+ ) -> str:
331
+ """按稳定拓扑序列化表格,并允许调用方提供已安全转义的 cell 内容。"""
332
+
333
+ cells_by_row: dict[int, list[NativeTableCell]] = {}
334
+ for cell in cells:
335
+ cells_by_row.setdefault(cell.row, []).append(cell)
336
+ rendered_rows: list[str] = []
337
+ for row_index in range(rows):
338
+ rendered_cells: list[str] = []
339
+ for cell in sorted(cells_by_row.get(row_index, []), key=lambda item: item.col):
340
+ attributes = []
341
+ if cell.rowspan > 1:
342
+ attributes.append(f' rowspan="{cell.rowspan}"')
343
+ if cell.colspan > 1:
344
+ attributes.append(f' colspan="{cell.colspan}"')
345
+ content = render_cell(cell) if render_cell is not None else html.escape(cell.content, quote=False)
346
+ rendered_cells.append(f"<td{''.join(attributes)}>{content}</td>")
347
+ rendered_rows.append(f"<tr>{''.join(rendered_cells)}</tr>")
348
+ return f"<table><tbody>{''.join(rendered_rows)}</tbody></table>"
349
+
350
+
351
+ __all__ = [
352
+ "GridCellSpec",
353
+ "build_candidate",
354
+ "serialize_candidate_html",
355
+ "serialize_native_table_html",
356
+ ]
@@ -0,0 +1,154 @@
1
+ """Native PDF 表格结构恢复使用的中立内部数据契约。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Literal
7
+
8
+ from .....document.pdf.text.contracts import Char
9
+
10
+ from .....schema import BBox
11
+
12
+ NativeTableCandidateSource = Literal[
13
+ "vector_grid",
14
+ "sparse_hybrid",
15
+ "sparse_multiline",
16
+ "sparse_grid",
17
+ "text_grid",
18
+ "key_value",
19
+ ]
20
+
21
+
22
+ @dataclass(frozen=True, slots=True)
23
+ class NativeTableRule:
24
+ """保存页面坐标中的一条可见横线或竖线。"""
25
+
26
+ bbox: BBox
27
+ width: float
28
+ orientation: Literal["horizontal", "vertical"]
29
+
30
+
31
+ @dataclass(frozen=True, slots=True)
32
+ class NativeTableRectangle:
33
+ """保存页面坐标中的 PDF 矩形路径及其绘制属性。"""
34
+
35
+ bbox: BBox
36
+ segment_count: int
37
+ fill_visible: bool
38
+ stroke_visible: bool
39
+ form_depth: int = 0
40
+
41
+
42
+ @dataclass(frozen=True, slots=True)
43
+ class NativeTableInput:
44
+ """保存一次已知表格区域结构恢复所需的全部页面原语。"""
45
+
46
+ table_bbox: BBox
47
+ page_size: tuple[float, float]
48
+ angle: int
49
+ chars: tuple[Char, ...]
50
+ drawing_lines: tuple[NativeTableRule, ...] = field(default_factory=tuple)
51
+ rectangles: tuple[NativeTableRectangle, ...] = field(default_factory=tuple)
52
+
53
+
54
+ @dataclass(frozen=True, slots=True)
55
+ class NativeTableGlyph:
56
+ """保存正向表格局部坐标中的单个可见 PDF 字符。"""
57
+
58
+ glyph_id: int
59
+ source_index: int
60
+ text: str
61
+ bbox: BBox
62
+ visual_row: int
63
+ explicit_space_before: bool = False
64
+ explicit_break_before: bool = False
65
+
66
+
67
+ @dataclass(frozen=True, slots=True)
68
+ class NativeTableToken:
69
+ """保存同一视觉行内由连续字符组成的表格文本项。"""
70
+
71
+ text: str
72
+ bbox: BBox
73
+ glyph_ids: tuple[int, ...]
74
+ source_char_indices: tuple[int, ...]
75
+
76
+
77
+ @dataclass(frozen=True, slots=True)
78
+ class NativeTableTextRow:
79
+ """保存表格局部坐标中的一条视觉文本行。"""
80
+
81
+ row_index: int
82
+ bbox: BBox
83
+ tokens: tuple[NativeTableToken, ...]
84
+ glyph_ids: tuple[int, ...]
85
+
86
+
87
+ @dataclass(frozen=True, slots=True)
88
+ class NativeTableText:
89
+ """保存统一字符预处理后的字形、文本行与尺度统计。"""
90
+
91
+ glyphs: tuple[NativeTableGlyph, ...]
92
+ rows: tuple[NativeTableTextRow, ...]
93
+ median_glyph_width: float
94
+ median_glyph_height: float
95
+
96
+
97
+ @dataclass(frozen=True, slots=True)
98
+ class NativeTableCell:
99
+ """保存一个逻辑单元格的网格位置、内容和字符来源。"""
100
+
101
+ row: int
102
+ col: int
103
+ rowspan: int
104
+ colspan: int
105
+ bbox: BBox
106
+ content: str
107
+ source_char_indices: tuple[int, ...] = field(default_factory=tuple)
108
+
109
+
110
+ @dataclass(frozen=True, slots=True)
111
+ class NativeTableCandidate:
112
+ """保存单路算法生成且已完成文本落格的表格候选。"""
113
+
114
+ source: NativeTableCandidateSource
115
+ rows: int
116
+ cols: int
117
+ cells: tuple[NativeTableCell, ...]
118
+ score: float
119
+ text_capture: float
120
+ structure_support: float
121
+ row_stability: float
122
+ column_stability: float
123
+ order_consistency: float
124
+ issues: tuple[str, ...] = field(default_factory=tuple)
125
+
126
+ @property
127
+ def topology(self) -> tuple[int, int, tuple[tuple[int, int, int, int], ...]]:
128
+ """返回不含文本的稳定拓扑签名,供候选冲突仲裁。"""
129
+
130
+ spans = tuple(sorted((cell.row, cell.col, cell.rowspan, cell.colspan) for cell in self.cells))
131
+ return self.rows, self.cols, spans
132
+
133
+
134
+ @dataclass(frozen=True, slots=True)
135
+ class NativeTableResult:
136
+ """保存最终采用的原生表格 HTML 及其可诊断内部结构。"""
137
+
138
+ html: str
139
+ rows: int
140
+ cols: int
141
+ cells: tuple[NativeTableCell, ...]
142
+ text: NativeTableText
143
+ source: NativeTableCandidateSource
144
+ confidence: float
145
+ diagnostics: tuple[str, ...] = field(default_factory=tuple)
146
+
147
+
148
+ __all__ = [
149
+ "NativeTableCell",
150
+ "NativeTableInput",
151
+ "NativeTableRectangle",
152
+ "NativeTableResult",
153
+ "NativeTableRule",
154
+ ]