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.
- docvortex/__init__.py +21 -0
- docvortex/analyzers/__init__.py +3 -0
- docvortex/analyzers/native/__init__.py +37 -0
- docvortex/analyzers/native/_shared/__init__.py +3 -0
- docvortex/analyzers/native/_shared/hyperlink.py +16 -0
- docvortex/analyzers/native/_shared/image.py +8 -0
- docvortex/analyzers/native/_shared/markup/__init__.py +47 -0
- docvortex/analyzers/native/_shared/markup/anchors.py +30 -0
- docvortex/analyzers/native/_shared/markup/formula.py +37 -0
- docvortex/analyzers/native/_shared/markup/projector.py +57 -0
- docvortex/analyzers/native/_shared/markup/styles.py +19 -0
- docvortex/analyzers/native/_shared/mathml.py +17 -0
- docvortex/analyzers/native/_shared/names.py +7 -0
- docvortex/analyzers/native/_shared/xycut.py +414 -0
- docvortex/analyzers/native/contracts.py +44 -0
- docvortex/analyzers/native/csv.py +351 -0
- docvortex/analyzers/native/epub/__init__.py +18 -0
- docvortex/analyzers/native/epub/constants.py +45 -0
- docvortex/analyzers/native/epub/converter.py +80 -0
- docvortex/analyzers/native/epub/errors.py +20 -0
- docvortex/analyzers/native/epub/metadata.py +31 -0
- docvortex/analyzers/native/epub/package.py +649 -0
- docvortex/analyzers/native/epub/xhtml.py +306 -0
- docvortex/analyzers/native/html/__init__.py +6 -0
- docvortex/analyzers/native/html/anchors.py +271 -0
- docvortex/analyzers/native/html/constants.py +25 -0
- docvortex/analyzers/native/html/contracts.py +7 -0
- docvortex/analyzers/native/html/converter.py +117 -0
- docvortex/analyzers/native/html/document.py +389 -0
- docvortex/analyzers/native/html/errors.py +12 -0
- docvortex/analyzers/native/html/resources.py +365 -0
- docvortex/analyzers/native/html/selector.py +421 -0
- docvortex/analyzers/native/models.py +209 -0
- docvortex/analyzers/native/ofd/__init__.py +14 -0
- docvortex/analyzers/native/ofd/constants.py +59 -0
- docvortex/analyzers/native/ofd/converter.py +31 -0
- docvortex/analyzers/native/ofd/errors.py +16 -0
- docvortex/analyzers/native/ofd/geometry.py +215 -0
- docvortex/analyzers/native/ofd/images.py +124 -0
- docvortex/analyzers/native/ofd/metadata.py +53 -0
- docvortex/analyzers/native/ofd/models.py +170 -0
- docvortex/analyzers/native/ofd/package.py +346 -0
- docvortex/analyzers/native/ofd/path.py +201 -0
- docvortex/analyzers/native/ofd/reading_order.py +293 -0
- docvortex/analyzers/native/ofd/resources.py +122 -0
- docvortex/analyzers/native/ofd/scene.py +347 -0
- docvortex/analyzers/native/ofd/table.py +240 -0
- docvortex/analyzers/native/ofd/text.py +521 -0
- docvortex/analyzers/native/office/__init__.py +3 -0
- docvortex/analyzers/native/office/doc/__init__.py +3 -0
- docvortex/analyzers/native/office/doc/bookmarks.py +81 -0
- docvortex/analyzers/native/office/doc/doc_converter.py +573 -0
- docvortex/analyzers/native/office/doc/fib.py +261 -0
- docvortex/analyzers/native/office/doc/fields.py +101 -0
- docvortex/analyzers/native/office/doc/formatting.py +171 -0
- docvortex/analyzers/native/office/doc/images.py +162 -0
- docvortex/analyzers/native/office/doc/lists.py +356 -0
- docvortex/analyzers/native/office/doc/models.py +164 -0
- docvortex/analyzers/native/office/doc/parser.py +851 -0
- docvortex/analyzers/native/office/doc/pieces.py +256 -0
- docvortex/analyzers/native/office/doc/records.py +40 -0
- docvortex/analyzers/native/office/doc/sprm.py +269 -0
- docvortex/analyzers/native/office/doc/styles.py +215 -0
- docvortex/analyzers/native/office/docx/__init__.py +3 -0
- docvortex/analyzers/native/office/docx/context.py +71 -0
- docvortex/analyzers/native/office/docx/docx_converter.py +614 -0
- docvortex/analyzers/native/office/docx/equationxml.py +119 -0
- docvortex/analyzers/native/office/docx/fields.py +816 -0
- docvortex/analyzers/native/office/docx/formatting_types.py +23 -0
- docvortex/analyzers/native/office/docx/main.py +50 -0
- docvortex/analyzers/native/office/docx/numbering.py +491 -0
- docvortex/analyzers/native/office/docx/office_xml.py +57 -0
- docvortex/analyzers/native/office/docx/package_normalizer.py +248 -0
- docvortex/analyzers/native/office/docx/resources.py +526 -0
- docvortex/analyzers/native/office/docx/styles.py +693 -0
- docvortex/analyzers/native/office/docx/tables.py +515 -0
- docvortex/analyzers/native/office/equation/__init__.py +3 -0
- docvortex/analyzers/native/office/equation/image.py +470 -0
- docvortex/analyzers/native/office/equation/latex_dict.py +324 -0
- docvortex/analyzers/native/office/equation/mtef.py +885 -0
- docvortex/analyzers/native/office/equation/mtef_v5.py +941 -0
- docvortex/analyzers/native/office/equation/omml.py +561 -0
- docvortex/analyzers/native/office/equation/ooxml.py +62 -0
- docvortex/analyzers/native/office/errors.py +33 -0
- docvortex/analyzers/native/office/image.py +307 -0
- docvortex/analyzers/native/office/legacy/__init__.py +3 -0
- docvortex/analyzers/native/office/legacy/binary.py +43 -0
- docvortex/analyzers/native/office/legacy/officeart.py +362 -0
- docvortex/analyzers/native/office/legacy/ole.py +110 -0
- docvortex/analyzers/native/office/limits.py +12 -0
- docvortex/analyzers/native/office/odf/__init__.py +3 -0
- docvortex/analyzers/native/office/odf/chart.py +76 -0
- docvortex/analyzers/native/office/odf/constants.py +70 -0
- docvortex/analyzers/native/office/odf/converters.py +403 -0
- docvortex/analyzers/native/office/odf/errors.py +18 -0
- docvortex/analyzers/native/office/odf/metadata.py +91 -0
- docvortex/analyzers/native/office/odf/models.py +176 -0
- docvortex/analyzers/native/office/odf/package.py +270 -0
- docvortex/analyzers/native/office/odf/styles.py +329 -0
- docvortex/analyzers/native/office/odf/table.py +469 -0
- docvortex/analyzers/native/office/odf/text.py +1002 -0
- docvortex/analyzers/native/office/ooxml_chart.py +1016 -0
- docvortex/analyzers/native/office/opc.py +38 -0
- docvortex/analyzers/native/office/ppt/__init__.py +3 -0
- docvortex/analyzers/native/office/ppt/models.py +118 -0
- docvortex/analyzers/native/office/ppt/parser.py +1895 -0
- docvortex/analyzers/native/office/ppt/ppt_converter.py +292 -0
- docvortex/analyzers/native/office/ppt/records.py +131 -0
- docvortex/analyzers/native/office/ppt/style_text.py +247 -0
- docvortex/analyzers/native/office/pptx/__init__.py +3 -0
- docvortex/analyzers/native/office/pptx/context.py +113 -0
- docvortex/analyzers/native/office/pptx/lists.py +558 -0
- docvortex/analyzers/native/office/pptx/main.py +20 -0
- docvortex/analyzers/native/office/pptx/package_normalizer.py +321 -0
- docvortex/analyzers/native/office/pptx/pptx_converter.py +323 -0
- docvortex/analyzers/native/office/pptx/resources.py +329 -0
- docvortex/analyzers/native/office/pptx/shapes.py +393 -0
- docvortex/analyzers/native/office/pptx/text_styles.py +625 -0
- docvortex/analyzers/native/office/pptx/titles.py +178 -0
- docvortex/analyzers/native/office/rich_text.py +420 -0
- docvortex/analyzers/native/office/rtf/__init__.py +3 -0
- docvortex/analyzers/native/office/rtf/converter.py +708 -0
- docvortex/analyzers/native/office/rtf/lexer.py +213 -0
- docvortex/analyzers/native/office/rtf/math.py +339 -0
- docvortex/analyzers/native/office/rtf/models.py +185 -0
- docvortex/analyzers/native/office/rtf/parser.py +1553 -0
- docvortex/analyzers/native/office/spreadsheet/__init__.py +3 -0
- docvortex/analyzers/native/office/spreadsheet/html.py +81 -0
- docvortex/analyzers/native/office/spreadsheet/models.py +79 -0
- docvortex/analyzers/native/office/spreadsheet/projector.py +928 -0
- docvortex/analyzers/native/office/streams.py +18 -0
- docvortex/analyzers/native/office/xls/__init__.py +3 -0
- docvortex/analyzers/native/office/xls/chart.py +132 -0
- docvortex/analyzers/native/office/xls/embedded_chart.py +299 -0
- docvortex/analyzers/native/office/xls/models.py +109 -0
- docvortex/analyzers/native/office/xls/number_format.py +521 -0
- docvortex/analyzers/native/office/xls/parser.py +1145 -0
- docvortex/analyzers/native/office/xls/records.py +201 -0
- docvortex/analyzers/native/office/xls/strings.py +205 -0
- docvortex/analyzers/native/office/xls/xls_converter.py +354 -0
- docvortex/analyzers/native/office/xlsx/__init__.py +3 -0
- docvortex/analyzers/native/office/xlsx/main.py +20 -0
- docvortex/analyzers/native/office/xlsx/ooxml_ole.py +522 -0
- docvortex/analyzers/native/office/xlsx/package_normalizer.py +310 -0
- docvortex/analyzers/native/office/xlsx/xlsx_converter.py +716 -0
- docvortex/analyzers/native/pdf/__init__.py +3 -0
- docvortex/analyzers/native/pdf/auxiliary_text.py +1671 -0
- docvortex/analyzers/native/pdf/char_geometry.py +1662 -0
- docvortex/analyzers/native/pdf/code_blocks.py +535 -0
- docvortex/analyzers/native/pdf/formulas.py +1985 -0
- docvortex/analyzers/native/pdf/geometry.py +281 -0
- docvortex/analyzers/native/pdf/graphics.py +1501 -0
- docvortex/analyzers/native/pdf/index_blocks.py +268 -0
- docvortex/analyzers/native/pdf/inline/__init__.py +3 -0
- docvortex/analyzers/native/pdf/inline/common.py +112 -0
- docvortex/analyzers/native/pdf/inline/detection.py +590 -0
- docvortex/analyzers/native/pdf/inline/matching.py +1185 -0
- docvortex/analyzers/native/pdf/inline/materialize.py +457 -0
- docvortex/analyzers/native/pdf/inline/scripts.py +975 -0
- docvortex/analyzers/native/pdf/inline/types.py +385 -0
- docvortex/analyzers/native/pdf/line_layout.py +1106 -0
- docvortex/analyzers/native/pdf/line_merging.py +1223 -0
- docvortex/analyzers/native/pdf/models.py +246 -0
- docvortex/analyzers/native/pdf/native_text.py +1004 -0
- docvortex/analyzers/native/pdf/pipeline.py +1390 -0
- docvortex/analyzers/native/pdf/script_geometry.py +636 -0
- docvortex/analyzers/native/pdf/shared.py +30 -0
- docvortex/analyzers/native/pdf/spatial_text.py +383 -0
- docvortex/analyzers/native/pdf/table_annotations.py +446 -0
- docvortex/analyzers/native/pdf/table_constants.py +48 -0
- docvortex/analyzers/native/pdf/table_detection.py +227 -0
- docvortex/analyzers/native/pdf/table_filled_grid.py +218 -0
- docvortex/analyzers/native/pdf/table_geometry.py +40 -0
- docvortex/analyzers/native/pdf/table_materialization.py +444 -0
- docvortex/analyzers/native/pdf/table_recovery/__init__.py +15 -0
- docvortex/analyzers/native/pdf/table_recovery/candidate.py +356 -0
- docvortex/analyzers/native/pdf/table_recovery/contracts.py +154 -0
- docvortex/analyzers/native/pdf/table_recovery/engine.py +609 -0
- docvortex/analyzers/native/pdf/table_recovery/geometry.py +164 -0
- docvortex/analyzers/native/pdf/table_recovery/sparse_common.py +85 -0
- docvortex/analyzers/native/pdf/table_recovery/sparse_hybrid.py +804 -0
- docvortex/analyzers/native/pdf/table_recovery/sparse_multiline.py +1122 -0
- docvortex/analyzers/native/pdf/table_recovery/text.py +414 -0
- docvortex/analyzers/native/pdf/table_recovery/text_grid.py +618 -0
- docvortex/analyzers/native/pdf/table_recovery/vector.py +1931 -0
- docvortex/analyzers/native/pdf/table_rows.py +34 -0
- docvortex/analyzers/native/pdf/table_rules.py +1129 -0
- docvortex/analyzers/native/pdf/table_text_styles.py +283 -0
- docvortex/analyzers/native/pdf/tables.py +147 -0
- docvortex/analyzers/native/pdf/text_assembly/__init__.py +3 -0
- docvortex/analyzers/native/pdf/text_assembly/annotations.py +581 -0
- docvortex/analyzers/native/pdf/text_assembly/assembly.py +292 -0
- docvortex/analyzers/native/pdf/text_assembly/common.py +477 -0
- docvortex/analyzers/native/pdf/text_assembly/footnotes.py +394 -0
- docvortex/analyzers/native/pdf/text_assembly/merging.py +1274 -0
- docvortex/analyzers/native/pdf/text_assembly/rows.py +692 -0
- docvortex/analyzers/native/pdf/text_blocks.py +82 -0
- docvortex/analyzers/native/pdf/text_styles.py +55 -0
- docvortex/analyzers/native/pdf/title_analysis/__init__.py +3 -0
- docvortex/analyzers/native/pdf/title_analysis/body_profile.py +215 -0
- docvortex/analyzers/native/pdf/title_analysis/common.py +117 -0
- docvortex/analyzers/native/pdf/title_analysis/document_profile.py +164 -0
- docvortex/analyzers/native/pdf/title_analysis/lane_titles.py +758 -0
- docvortex/analyzers/native/pdf/title_analysis/page_titles.py +1024 -0
- docvortex/analyzers/native/pdf/title_analysis/prototype.py +194 -0
- docvortex/analyzers/native/pdf/title_analysis/structural.py +1081 -0
- docvortex/analyzers/native/pdf/titles.py +75 -0
- docvortex/analyzers/native/pdf/typography.py +19 -0
- docvortex/analyzers/native/pdf/visual_annotations.py +1262 -0
- docvortex/api.py +180 -0
- docvortex/assets/__init__.py +5 -0
- docvortex/assets/store.py +51 -0
- docvortex/cli.py +54 -0
- docvortex/codecs/__init__.py +3 -0
- docvortex/codecs/html/__init__.py +22 -0
- docvortex/codecs/html/contracts.py +236 -0
- docvortex/codecs/html/materializer.py +331 -0
- docvortex/codecs/html/parser.py +763 -0
- docvortex/codecs/html/resources.py +34 -0
- docvortex/codecs/json.py +17 -0
- docvortex/content/__init__.py +5 -0
- docvortex/content/inline.py +248 -0
- docvortex/content/markup/__init__.py +44 -0
- docvortex/content/markup/anchors.py +188 -0
- docvortex/content/markup/formula.py +280 -0
- docvortex/content/markup/projector.py +1237 -0
- docvortex/content/markup/styles.py +327 -0
- docvortex/content/mathml.py +167 -0
- docvortex/content/normalization.py +188 -0
- docvortex/content/spans.py +183 -0
- docvortex/content/table/__init__.py +18 -0
- docvortex/content/table/blocks.py +152 -0
- docvortex/content/table/content.py +425 -0
- docvortex/content/table/document.py +104 -0
- docvortex/content/table/html.py +399 -0
- docvortex/content/table/models.py +76 -0
- docvortex/content/table/rules.py +42 -0
- docvortex/content/table/structure.py +221 -0
- docvortex/content/tree.py +5 -0
- docvortex/document/__init__.py +3 -0
- docvortex/document/contracts.py +22 -0
- docvortex/document/detection.py +389 -0
- docvortex/document/filetypes.py +175 -0
- docvortex/document/page_range.py +167 -0
- docvortex/document/pdf/__init__.py +19 -0
- docvortex/document/pdf/classify.py +1138 -0
- docvortex/document/pdf/constants.py +132 -0
- docvortex/document/pdf/diagnostics.py +350 -0
- docvortex/document/pdf/document.py +582 -0
- docvortex/document/pdf/font_runtime.py +335 -0
- docvortex/document/pdf/geometry.py +31 -0
- docvortex/document/pdf/images.py +654 -0
- docvortex/document/pdf/native_annotations.py +367 -0
- docvortex/document/pdf/native_contracts.py +169 -0
- docvortex/document/pdf/native_coordinates.py +216 -0
- docvortex/document/pdf/native_lifecycle.py +16 -0
- docvortex/document/pdf/native_objects.py +902 -0
- docvortex/document/pdf/native_text_geometry.py +315 -0
- docvortex/document/pdf/pdfium.py +325 -0
- docvortex/document/pdf/raster.py +46 -0
- docvortex/document/pdf/text/__init__.py +62 -0
- docvortex/document/pdf/text/contracts.py +211 -0
- docvortex/document/pdf/text/extract.py +165 -0
- docvortex/document/pdf/text/geometry.py +16 -0
- docvortex/document/pdf/text/groups.py +162 -0
- docvortex/document/pdf/visual_geometry.py +201 -0
- docvortex/document/pdf/visuals.py +343 -0
- docvortex/document/source.py +92 -0
- docvortex/errors.py +21 -0
- docvortex/export/__init__.py +3 -0
- docvortex/export/bundle.py +98 -0
- docvortex/export/files.py +66 -0
- docvortex/export/middle.py +208 -0
- docvortex/foundation/__init__.py +3 -0
- docvortex/foundation/geometry.py +125 -0
- docvortex/foundation/hyperlink.py +65 -0
- docvortex/foundation/image.py +48 -0
- docvortex/foundation/image_encoding.py +30 -0
- docvortex/foundation/image_payload.py +280 -0
- docvortex/foundation/language.py +92 -0
- docvortex/foundation/platform.py +38 -0
- docvortex/foundation/text.py +153 -0
- docvortex/foundation/type_identity.py +20 -0
- docvortex/foundation/xml_names.py +20 -0
- docvortex/options.py +30 -0
- docvortex/postprocess/__init__.py +3 -0
- docvortex/postprocess/content.py +53 -0
- docvortex/postprocess/document.py +19 -0
- docvortex/postprocess/lists.py +236 -0
- docvortex/postprocess/page_blocks.py +214 -0
- docvortex/postprocess/pages.py +95 -0
- docvortex/postprocess/paragraphs.py +580 -0
- docvortex/postprocess/visual.py +715 -0
- docvortex/render/__init__.py +48 -0
- docvortex/render/_internal/__init__.py +3 -0
- docvortex/render/_internal/common/__init__.py +3 -0
- docvortex/render/_internal/common/context.py +43 -0
- docvortex/render/_internal/common/html_table.py +178 -0
- docvortex/render/_internal/common/index.py +33 -0
- docvortex/render/_internal/common/list_items.py +158 -0
- docvortex/render/_internal/common/planner.py +140 -0
- docvortex/render/_internal/docx/__init__.py +3 -0
- docvortex/render/_internal/docx/assets.py +202 -0
- docvortex/render/_internal/docx/inline.py +434 -0
- docvortex/render/_internal/docx/math.py +220 -0
- docvortex/render/_internal/docx/renderer.py +905 -0
- docvortex/render/_internal/docx/styles.py +195 -0
- docvortex/render/_internal/docx/table.py +442 -0
- docvortex/render/_internal/epub/__init__.py +5 -0
- docvortex/render/_internal/epub/assets.py +173 -0
- docvortex/render/_internal/epub/package.py +249 -0
- docvortex/render/_internal/epub/renderer.py +1156 -0
- docvortex/render/_internal/html/__init__.py +3 -0
- docvortex/render/_internal/html/inline.py +346 -0
- docvortex/render/_internal/html/renderer.py +1041 -0
- docvortex/render/_internal/html/sanitizer.py +478 -0
- docvortex/render/_internal/html/table.py +121 -0
- docvortex/render/_internal/latex/__init__.py +1 -0
- docvortex/render/_internal/latex/assets.py +85 -0
- docvortex/render/_internal/latex/inline.py +145 -0
- docvortex/render/_internal/latex/renderer.py +506 -0
- docvortex/render/_internal/latex/table.py +347 -0
- docvortex/render/_internal/markdown/__init__.py +3 -0
- docvortex/render/_internal/markdown/assets.py +78 -0
- docvortex/render/_internal/markdown/blocks.py +635 -0
- docvortex/render/_internal/markdown/escaping.py +51 -0
- docvortex/render/_internal/markdown/inline.py +260 -0
- docvortex/render/_internal/markdown/renderer.py +93 -0
- docvortex/render/_internal/markdown/table.py +281 -0
- docvortex/render/_internal/pdf/__init__.py +3 -0
- docvortex/render/_internal/pdf/assets.py +197 -0
- docvortex/render/_internal/pdf/formula.py +417 -0
- docvortex/render/_internal/pdf/inline.py +343 -0
- docvortex/render/_internal/pdf/renderer.py +734 -0
- docvortex/render/_internal/pdf/styles.py +206 -0
- docvortex/render/_internal/pdf/table.py +272 -0
- docvortex/render/_internal/structured_content/__init__.py +3 -0
- docvortex/render/_internal/structured_content/renderer.py +193 -0
- docvortex/render/api.py +199 -0
- docvortex/render/contracts.py +205 -0
- docvortex/render/docx.py +38 -0
- docvortex/render/epub.py +35 -0
- docvortex/render/fragments.py +70 -0
- docvortex/render/html.py +29 -0
- docvortex/render/latex.py +24 -0
- docvortex/render/markdown.py +50 -0
- docvortex/render/pdf.py +25 -0
- docvortex/render/structured_content.py +23 -0
- docvortex/resources/epub/docvortex.css +91 -0
- docvortex/resources/fasttext-langdetect/lid.176.ftz +0 -0
- docvortex/resources/fonts/DroidSansFallbackFull.ttf +0 -0
- docvortex/resources/fonts/NOTICE +190 -0
- docvortex/resources/fonts/manifest.json +9 -0
- docvortex/resources/html/docvortex.css +601 -0
- docvortex/resources/html/docvortex.min.css +1 -0
- docvortex/result.py +91 -0
- docvortex/schema.py +1141 -0
- docvortex/version.py +3 -0
- docvortex-0.2.1.dist-info/METADATA +193 -0
- docvortex-0.2.1.dist-info/RECORD +364 -0
- docvortex-0.2.1.dist-info/WHEEL +5 -0
- docvortex-0.2.1.dist-info/entry_points.txt +2 -0
- docvortex-0.2.1.dist-info/licenses/LICENSE.md +21 -0
- docvortex-0.2.1.dist-info/top_level.txt +1 -0
docvortex/render/api.py
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""严格 MiddleJson 多格式渲染的统一公共入口。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Literal, overload
|
|
6
|
+
|
|
7
|
+
from ..schema import MiddleJson
|
|
8
|
+
|
|
9
|
+
from .contracts import (
|
|
10
|
+
DocxRenderOptions,
|
|
11
|
+
EpubRenderOptions,
|
|
12
|
+
HtmlRenderOptions,
|
|
13
|
+
LatexRenderOptions,
|
|
14
|
+
MarkdownRenderOptions,
|
|
15
|
+
PdfRenderOptions,
|
|
16
|
+
RenderFormat,
|
|
17
|
+
RenderOptions,
|
|
18
|
+
RenderOutput,
|
|
19
|
+
StructuredContentRenderOptions,
|
|
20
|
+
)
|
|
21
|
+
from .docx import render_docx
|
|
22
|
+
from .epub import render_epub
|
|
23
|
+
from .html import render_html
|
|
24
|
+
from .latex import render_latex
|
|
25
|
+
from .markdown import render_markdown
|
|
26
|
+
from .pdf import render_pdf
|
|
27
|
+
from .structured_content import render_structured_content
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@overload
|
|
31
|
+
def render(
|
|
32
|
+
middle_json: MiddleJson,
|
|
33
|
+
output_format: Literal[RenderFormat.MARKDOWN],
|
|
34
|
+
*,
|
|
35
|
+
options: MarkdownRenderOptions | None = None,
|
|
36
|
+
) -> str:
|
|
37
|
+
"""声明 Markdown 目标对应的字符串返回类型。"""
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@overload
|
|
42
|
+
def render(
|
|
43
|
+
middle_json: MiddleJson,
|
|
44
|
+
output_format: Literal[RenderFormat.HTML],
|
|
45
|
+
*,
|
|
46
|
+
options: HtmlRenderOptions | None = None,
|
|
47
|
+
) -> str:
|
|
48
|
+
"""声明 HTML 目标对应的字符串返回类型。"""
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@overload
|
|
53
|
+
def render(
|
|
54
|
+
middle_json: MiddleJson,
|
|
55
|
+
output_format: Literal[RenderFormat.LATEX],
|
|
56
|
+
*,
|
|
57
|
+
options: LatexRenderOptions | None = None,
|
|
58
|
+
) -> str:
|
|
59
|
+
"""声明 LaTeX 目标对应的字符串返回类型。"""
|
|
60
|
+
...
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@overload
|
|
64
|
+
def render(
|
|
65
|
+
middle_json: MiddleJson,
|
|
66
|
+
output_format: Literal[RenderFormat.DOCX],
|
|
67
|
+
*,
|
|
68
|
+
options: DocxRenderOptions | None = None,
|
|
69
|
+
) -> bytes:
|
|
70
|
+
"""声明 DOCX 目标对应的字节返回类型。"""
|
|
71
|
+
...
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@overload
|
|
75
|
+
def render(
|
|
76
|
+
middle_json: MiddleJson,
|
|
77
|
+
output_format: Literal[RenderFormat.EPUB],
|
|
78
|
+
*,
|
|
79
|
+
options: EpubRenderOptions | None = None,
|
|
80
|
+
) -> bytes:
|
|
81
|
+
"""声明 EPUB 目标对应的字节返回类型。"""
|
|
82
|
+
...
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@overload
|
|
86
|
+
def render(
|
|
87
|
+
middle_json: MiddleJson,
|
|
88
|
+
output_format: Literal[RenderFormat.PDF],
|
|
89
|
+
*,
|
|
90
|
+
options: PdfRenderOptions | None = None,
|
|
91
|
+
) -> bytes:
|
|
92
|
+
"""声明 PDF 目标对应的字节返回类型。"""
|
|
93
|
+
...
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@overload
|
|
97
|
+
def render(
|
|
98
|
+
middle_json: MiddleJson,
|
|
99
|
+
output_format: Literal[RenderFormat.STRUCTURED_CONTENT],
|
|
100
|
+
*,
|
|
101
|
+
options: StructuredContentRenderOptions | None = None,
|
|
102
|
+
) -> dict[str, Any]:
|
|
103
|
+
"""声明 Structured Content 目标对应的字典返回类型。"""
|
|
104
|
+
...
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def render(
|
|
108
|
+
middle_json: MiddleJson,
|
|
109
|
+
output_format: RenderFormat,
|
|
110
|
+
*,
|
|
111
|
+
options: RenderOptions | None = None,
|
|
112
|
+
) -> RenderOutput:
|
|
113
|
+
"""按严格目标格式和对应选项把 MiddleJson 渲染为原生结果。"""
|
|
114
|
+
if not isinstance(middle_json, MiddleJson):
|
|
115
|
+
raise TypeError("render expects a MiddleJson instance")
|
|
116
|
+
if not isinstance(output_format, RenderFormat):
|
|
117
|
+
raise TypeError("output_format must be a RenderFormat value")
|
|
118
|
+
|
|
119
|
+
if output_format is RenderFormat.MARKDOWN:
|
|
120
|
+
resolved_options = options if options is not None else MarkdownRenderOptions()
|
|
121
|
+
if not isinstance(resolved_options, MarkdownRenderOptions):
|
|
122
|
+
raise TypeError("MARKDOWN output requires MarkdownRenderOptions")
|
|
123
|
+
return render_markdown(
|
|
124
|
+
middle_json,
|
|
125
|
+
latex_delimiters=resolved_options.latex_delimiters,
|
|
126
|
+
mode=resolved_options.mode,
|
|
127
|
+
asset_base_url=resolved_options.asset_base_url,
|
|
128
|
+
image_renderer=resolved_options.image_renderer,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if output_format is RenderFormat.HTML:
|
|
132
|
+
resolved_options = options if options is not None else HtmlRenderOptions()
|
|
133
|
+
if not isinstance(resolved_options, HtmlRenderOptions):
|
|
134
|
+
raise TypeError("HTML output requires HtmlRenderOptions")
|
|
135
|
+
return render_html(
|
|
136
|
+
middle_json,
|
|
137
|
+
mode=resolved_options.mode,
|
|
138
|
+
asset_base_url=resolved_options.asset_base_url,
|
|
139
|
+
standalone=resolved_options.standalone,
|
|
140
|
+
document_title=resolved_options.document_title,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if output_format is RenderFormat.LATEX:
|
|
144
|
+
resolved_options = options if options is not None else LatexRenderOptions()
|
|
145
|
+
if not isinstance(resolved_options, LatexRenderOptions):
|
|
146
|
+
raise TypeError("LATEX output requires LatexRenderOptions")
|
|
147
|
+
return render_latex(
|
|
148
|
+
middle_json,
|
|
149
|
+
asset_base_path=resolved_options.asset_base_path,
|
|
150
|
+
document_title=resolved_options.document_title,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
if output_format is RenderFormat.DOCX:
|
|
154
|
+
resolved_options = options if options is not None else DocxRenderOptions()
|
|
155
|
+
if not isinstance(resolved_options, DocxRenderOptions):
|
|
156
|
+
raise TypeError("DOCX output requires DocxRenderOptions")
|
|
157
|
+
return render_docx(
|
|
158
|
+
middle_json,
|
|
159
|
+
asset_resolver=resolved_options.asset_resolver,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if output_format is RenderFormat.EPUB:
|
|
163
|
+
resolved_options = options if options is not None else EpubRenderOptions()
|
|
164
|
+
if not isinstance(resolved_options, EpubRenderOptions):
|
|
165
|
+
raise TypeError("EPUB output requires EpubRenderOptions")
|
|
166
|
+
return render_epub(
|
|
167
|
+
middle_json,
|
|
168
|
+
title=resolved_options.title,
|
|
169
|
+
authors=resolved_options.authors,
|
|
170
|
+
language=resolved_options.language,
|
|
171
|
+
identifier=resolved_options.identifier,
|
|
172
|
+
modified_at=resolved_options.modified_at,
|
|
173
|
+
asset_resolver=resolved_options.asset_resolver,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
if output_format is RenderFormat.PDF:
|
|
177
|
+
resolved_options = options if options is not None else PdfRenderOptions()
|
|
178
|
+
if not isinstance(resolved_options, PdfRenderOptions):
|
|
179
|
+
raise TypeError("PDF output requires PdfRenderOptions")
|
|
180
|
+
return render_pdf(
|
|
181
|
+
middle_json,
|
|
182
|
+
asset_resolver=resolved_options.asset_resolver,
|
|
183
|
+
document_title=resolved_options.document_title,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
if output_format is RenderFormat.STRUCTURED_CONTENT:
|
|
187
|
+
resolved_options = options if options is not None else StructuredContentRenderOptions()
|
|
188
|
+
if not isinstance(resolved_options, StructuredContentRenderOptions):
|
|
189
|
+
raise TypeError("STRUCTURED_CONTENT output requires StructuredContentRenderOptions")
|
|
190
|
+
return render_structured_content(
|
|
191
|
+
middle_json,
|
|
192
|
+
latex_delimiters=resolved_options.latex_delimiters,
|
|
193
|
+
asset_base_url=resolved_options.asset_base_url,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
raise ValueError(f"Unsupported RenderFormat: {output_format}")
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
__all__ = ["render"]
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""MiddleJson 多格式 renderer 共用的公共类型与调用选项。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from enum import Enum
|
|
8
|
+
import re
|
|
9
|
+
from typing import Any, Callable, TypeAlias
|
|
10
|
+
|
|
11
|
+
from ..schema import BlockBase
|
|
12
|
+
from ..options import LatexDelimitersConfig
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RenderFormat(str, Enum):
|
|
16
|
+
"""统一渲染入口支持的目标格式。"""
|
|
17
|
+
|
|
18
|
+
MARKDOWN = "markdown"
|
|
19
|
+
HTML = "html"
|
|
20
|
+
LATEX = "latex"
|
|
21
|
+
DOCX = "docx"
|
|
22
|
+
EPUB = "epub"
|
|
23
|
+
STRUCTURED_CONTENT = "structured_content"
|
|
24
|
+
PDF = "pdf"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class RenderMode(str, Enum):
|
|
28
|
+
"""Markdown 与 HTML renderer 共用的默认合并视图与完整分页视图。"""
|
|
29
|
+
|
|
30
|
+
DEFAULT = "default"
|
|
31
|
+
FULL = "full"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
AssetResolver: TypeAlias = Callable[[str], bytes]
|
|
35
|
+
ImageRenderer: TypeAlias = Callable[[BlockBase], str]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _validate_mode(mode: object) -> None:
|
|
39
|
+
"""校验 Markdown 与 HTML renderer 的公共模式参数。"""
|
|
40
|
+
if not isinstance(mode, RenderMode):
|
|
41
|
+
raise TypeError("mode must be a RenderMode value")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _validate_asset_base_url(asset_base_url: object) -> None:
|
|
45
|
+
"""校验用于拼接相对图片路径的资源根地址。"""
|
|
46
|
+
if not isinstance(asset_base_url, str):
|
|
47
|
+
raise TypeError("asset_base_url must be a string")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass(frozen=True, slots=True)
|
|
51
|
+
class MarkdownRenderOptions:
|
|
52
|
+
"""Markdown renderer 的统一入口选项。"""
|
|
53
|
+
|
|
54
|
+
latex_delimiters: LatexDelimitersConfig | None = None
|
|
55
|
+
|
|
56
|
+
mode: RenderMode = RenderMode.DEFAULT
|
|
57
|
+
asset_base_url: str = ""
|
|
58
|
+
image_renderer: ImageRenderer | None = None
|
|
59
|
+
|
|
60
|
+
def __post_init__(self) -> None:
|
|
61
|
+
"""在构造时拒绝不符合严格公共契约的选项值。"""
|
|
62
|
+
_validate_mode(self.mode)
|
|
63
|
+
_validate_asset_base_url(self.asset_base_url)
|
|
64
|
+
if self.image_renderer is not None and not callable(self.image_renderer):
|
|
65
|
+
raise TypeError("image_renderer must be callable or None")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass(frozen=True, slots=True)
|
|
69
|
+
class HtmlRenderOptions:
|
|
70
|
+
"""HTML renderer 的统一入口选项。"""
|
|
71
|
+
|
|
72
|
+
mode: RenderMode = RenderMode.DEFAULT
|
|
73
|
+
asset_base_url: str = ""
|
|
74
|
+
standalone: bool = True
|
|
75
|
+
document_title: str | None = None
|
|
76
|
+
|
|
77
|
+
def __post_init__(self) -> None:
|
|
78
|
+
"""在构造时校验 HTML 文档形态与标题选项。"""
|
|
79
|
+
_validate_mode(self.mode)
|
|
80
|
+
_validate_asset_base_url(self.asset_base_url)
|
|
81
|
+
if not isinstance(self.standalone, bool):
|
|
82
|
+
raise TypeError("standalone must be a bool")
|
|
83
|
+
if self.document_title is not None and not isinstance(self.document_title, str):
|
|
84
|
+
raise TypeError("document_title must be a string or None")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass(frozen=True, slots=True)
|
|
88
|
+
class LatexRenderOptions:
|
|
89
|
+
"""LaTeX renderer 的统一入口选项。"""
|
|
90
|
+
|
|
91
|
+
asset_base_path: str = ""
|
|
92
|
+
document_title: str | None = None
|
|
93
|
+
|
|
94
|
+
def __post_init__(self) -> None:
|
|
95
|
+
"""在构造时校验 LaTeX 素材路径前缀与文档标题。"""
|
|
96
|
+
if not isinstance(self.asset_base_path, str):
|
|
97
|
+
raise TypeError("asset_base_path must be a string")
|
|
98
|
+
if self.document_title is not None and not isinstance(self.document_title, str):
|
|
99
|
+
raise TypeError("document_title must be a string or None")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass(frozen=True, slots=True)
|
|
103
|
+
class DocxRenderOptions:
|
|
104
|
+
"""DOCX renderer 的统一入口选项。"""
|
|
105
|
+
|
|
106
|
+
asset_resolver: AssetResolver | None = None
|
|
107
|
+
|
|
108
|
+
def __post_init__(self) -> None:
|
|
109
|
+
"""在构造时校验可选素材解析器。"""
|
|
110
|
+
if self.asset_resolver is not None and not callable(self.asset_resolver):
|
|
111
|
+
raise TypeError("asset_resolver must be callable or None")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
_EPUB_LANGUAGE_RE = re.compile(r"(?:[A-Za-z]{2,8}|und)(?:-[A-Za-z0-9]{1,8})*\Z", re.IGNORECASE)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@dataclass(frozen=True, slots=True)
|
|
118
|
+
class EpubRenderOptions:
|
|
119
|
+
"""EPUB 3.3 renderer 的统一入口选项。"""
|
|
120
|
+
|
|
121
|
+
title: str | None = None
|
|
122
|
+
authors: tuple[str, ...] = ()
|
|
123
|
+
language: str = "und"
|
|
124
|
+
identifier: str | None = None
|
|
125
|
+
modified_at: datetime | None = None
|
|
126
|
+
asset_resolver: AssetResolver | None = None
|
|
127
|
+
|
|
128
|
+
def __post_init__(self) -> None:
|
|
129
|
+
"""在构造时校验 EPUB 元数据、时间与素材解析器。"""
|
|
130
|
+
if self.title is not None and (not isinstance(self.title, str) or not self.title.strip()):
|
|
131
|
+
raise TypeError("title must be a non-empty string or None")
|
|
132
|
+
if not isinstance(self.authors, tuple) or any(
|
|
133
|
+
not isinstance(author, str) or not author.strip() for author in self.authors
|
|
134
|
+
):
|
|
135
|
+
raise TypeError("authors must be a tuple of non-empty strings")
|
|
136
|
+
if not isinstance(self.language, str) or _EPUB_LANGUAGE_RE.fullmatch(self.language.strip()) is None:
|
|
137
|
+
raise ValueError("language must be a supported BCP 47 language tag")
|
|
138
|
+
if self.identifier is not None and (not isinstance(self.identifier, str) or not self.identifier.strip()):
|
|
139
|
+
raise TypeError("identifier must be a non-empty string or None")
|
|
140
|
+
if self.modified_at is not None:
|
|
141
|
+
if not isinstance(self.modified_at, datetime):
|
|
142
|
+
raise TypeError("modified_at must be a datetime or None")
|
|
143
|
+
if self.modified_at.utcoffset() is None:
|
|
144
|
+
raise ValueError("modified_at must be timezone-aware")
|
|
145
|
+
if self.modified_at.year < 1000:
|
|
146
|
+
raise ValueError("modified_at year must use four digits")
|
|
147
|
+
if self.asset_resolver is not None and not callable(self.asset_resolver):
|
|
148
|
+
raise TypeError("asset_resolver must be callable or None")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@dataclass(frozen=True, slots=True)
|
|
152
|
+
class PdfRenderOptions:
|
|
153
|
+
"""PDF renderer 的统一入口选项。"""
|
|
154
|
+
|
|
155
|
+
asset_resolver: AssetResolver | None = None
|
|
156
|
+
document_title: str | None = None
|
|
157
|
+
|
|
158
|
+
def __post_init__(self) -> None:
|
|
159
|
+
"""在构造时校验素材解析器与文档标题。"""
|
|
160
|
+
if self.asset_resolver is not None and not callable(self.asset_resolver):
|
|
161
|
+
raise TypeError("asset_resolver must be callable or None")
|
|
162
|
+
if self.document_title is not None and not isinstance(self.document_title, str):
|
|
163
|
+
raise TypeError("document_title must be a string or None")
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@dataclass(frozen=True, slots=True)
|
|
167
|
+
class StructuredContentRenderOptions:
|
|
168
|
+
"""树形 Markdown Structured Content renderer 的统一入口选项。"""
|
|
169
|
+
|
|
170
|
+
latex_delimiters: LatexDelimitersConfig | None = None
|
|
171
|
+
|
|
172
|
+
asset_base_url: str = ""
|
|
173
|
+
|
|
174
|
+
def __post_init__(self) -> None:
|
|
175
|
+
"""在构造时校验图片资源根地址。"""
|
|
176
|
+
_validate_asset_base_url(self.asset_base_url)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
RenderOptions: TypeAlias = (
|
|
180
|
+
MarkdownRenderOptions
|
|
181
|
+
| HtmlRenderOptions
|
|
182
|
+
| LatexRenderOptions
|
|
183
|
+
| DocxRenderOptions
|
|
184
|
+
| EpubRenderOptions
|
|
185
|
+
| PdfRenderOptions
|
|
186
|
+
| StructuredContentRenderOptions
|
|
187
|
+
)
|
|
188
|
+
RenderOutput: TypeAlias = str | bytes | dict[str, Any]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
__all__ = [
|
|
192
|
+
"AssetResolver",
|
|
193
|
+
"DocxRenderOptions",
|
|
194
|
+
"EpubRenderOptions",
|
|
195
|
+
"HtmlRenderOptions",
|
|
196
|
+
"ImageRenderer",
|
|
197
|
+
"LatexRenderOptions",
|
|
198
|
+
"MarkdownRenderOptions",
|
|
199
|
+
"PdfRenderOptions",
|
|
200
|
+
"RenderFormat",
|
|
201
|
+
"RenderMode",
|
|
202
|
+
"RenderOptions",
|
|
203
|
+
"RenderOutput",
|
|
204
|
+
"StructuredContentRenderOptions",
|
|
205
|
+
]
|
docvortex/render/docx.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""严格 MiddleJson 到 DOCX 的轻量公共门面与稳定异常。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..schema import MiddleJson
|
|
6
|
+
from .contracts import AssetResolver
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DocxRenderError(RuntimeError):
|
|
10
|
+
"""表示 renderer 无法在不丢失必需内容的前提下生成 DOCX。"""
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
message: str,
|
|
15
|
+
*,
|
|
16
|
+
page_idx: int,
|
|
17
|
+
block_index: int | None,
|
|
18
|
+
block_type: str,
|
|
19
|
+
) -> None:
|
|
20
|
+
"""保存错误消息及稳定的 page/block 定位字段。"""
|
|
21
|
+
self.page_idx = page_idx
|
|
22
|
+
self.block_index = block_index
|
|
23
|
+
self.block_type = block_type
|
|
24
|
+
super().__init__(f"{message} (page_idx={page_idx}, block_index={block_index}, block_type={block_type})")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def render_docx(
|
|
28
|
+
middle_json: MiddleJson,
|
|
29
|
+
*,
|
|
30
|
+
asset_resolver: AssetResolver | None = None,
|
|
31
|
+
) -> bytes:
|
|
32
|
+
"""惰性加载 DOCX 实现并渲染严格 MiddleJson。"""
|
|
33
|
+
from ._internal.docx.renderer import render_docx as _render_docx
|
|
34
|
+
|
|
35
|
+
return _render_docx(middle_json, asset_resolver=asset_resolver)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = ["DocxRenderError", "render_docx"]
|
docvortex/render/epub.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""严格 MiddleJson 到 EPUB 3.3 的轻量公共门面。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
|
|
7
|
+
from ..schema import MiddleJson
|
|
8
|
+
from .contracts import AssetResolver
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def render_epub(
|
|
12
|
+
middle_json: MiddleJson,
|
|
13
|
+
*,
|
|
14
|
+
title: str | None = None,
|
|
15
|
+
authors: tuple[str, ...] = (),
|
|
16
|
+
language: str = "und",
|
|
17
|
+
identifier: str | None = None,
|
|
18
|
+
modified_at: datetime | None = None,
|
|
19
|
+
asset_resolver: AssetResolver | None = None,
|
|
20
|
+
) -> bytes:
|
|
21
|
+
"""惰性加载 EPUB 实现并返回完整 EPUB 3.3 容器字节。"""
|
|
22
|
+
from ._internal.epub.renderer import render_epub as _render_epub
|
|
23
|
+
|
|
24
|
+
return _render_epub(
|
|
25
|
+
middle_json,
|
|
26
|
+
title=title,
|
|
27
|
+
authors=authors,
|
|
28
|
+
language=language,
|
|
29
|
+
identifier=identifier,
|
|
30
|
+
modified_at=modified_at,
|
|
31
|
+
asset_resolver=asset_resolver,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
__all__ = ["render_epub"]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""公开共享渲染片段操作,供宿主组合专用输出而不依赖私有模块。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..options import LatexDelimitersConfig
|
|
6
|
+
from ..schema import ImagePayloadBlock, InlineSpan
|
|
7
|
+
from ._internal.common.list_items import ListItem, ListItemKind, OrderedListStyle
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def render_inline_content(content: list[InlineSpan], delimiters: LatexDelimitersConfig) -> str:
|
|
11
|
+
"""将行内语义编码为 Markdown,沿用共享的样式与公式规则。"""
|
|
12
|
+
from ._internal.markdown.inline import render_inline_content as render_value
|
|
13
|
+
|
|
14
|
+
return render_value(content, delimiters)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def render_internal_link(label: str, anchor: str) -> str:
|
|
18
|
+
"""构造与共享 Markdown renderer 一致的内部链接。"""
|
|
19
|
+
from ._internal.markdown.inline import render_internal_link as render_value
|
|
20
|
+
|
|
21
|
+
return render_value(label, anchor)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def resolve_image_source(block: ImagePayloadBlock, asset_base_url: str = "") -> str | None:
|
|
25
|
+
"""按既有素材优先级解析图片引用,不写出文件。"""
|
|
26
|
+
from ._internal.markdown.assets import resolve_image_source as resolve_value
|
|
27
|
+
|
|
28
|
+
return resolve_value(block, asset_base_url)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def normalize_image_source(source: str) -> str:
|
|
32
|
+
"""规范化素材路径,保持共享渲染器的 URL 与路径处理行为。"""
|
|
33
|
+
from ._internal.markdown.assets import normalize_image_source as normalize_value
|
|
34
|
+
|
|
35
|
+
return normalize_value(source)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def format_embedded_html(markup: str, *, asset_base_url: str, delimiters: LatexDelimitersConfig) -> str:
|
|
39
|
+
"""复用嵌入 HTML 的图片地址和公式分隔符处理。"""
|
|
40
|
+
from ._internal.markdown.table import format_embedded_html as format_value
|
|
41
|
+
|
|
42
|
+
return format_value(markup, asset_base_url=asset_base_url, delimiters=delimiters)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def strip_index_page_tail(content: list[InlineSpan]) -> list[InlineSpan]:
|
|
46
|
+
"""剥离目录尾部页码,保持行内样式和链接语义。"""
|
|
47
|
+
from ._internal.common.index import strip_index_page_tail as strip_value
|
|
48
|
+
|
|
49
|
+
return strip_value(content)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def parse_list_item_marker(content: list[InlineSpan]) -> ListItem:
|
|
53
|
+
"""解析列表标记并返回共享的不可变条目描述。"""
|
|
54
|
+
from ._internal.common.list_items import parse_list_item_marker as parse_value
|
|
55
|
+
|
|
56
|
+
return parse_value(content)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
"ListItem",
|
|
61
|
+
"ListItemKind",
|
|
62
|
+
"OrderedListStyle",
|
|
63
|
+
"render_inline_content",
|
|
64
|
+
"render_internal_link",
|
|
65
|
+
"resolve_image_source",
|
|
66
|
+
"normalize_image_source",
|
|
67
|
+
"format_embedded_html",
|
|
68
|
+
"strip_index_page_tail",
|
|
69
|
+
"parse_list_item_marker",
|
|
70
|
+
]
|
docvortex/render/html.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""严格 MiddleJson 到 HTML 的轻量公共门面。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..schema import MiddleJson
|
|
6
|
+
from .contracts import RenderMode
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def render_html(
|
|
10
|
+
middle_json: MiddleJson,
|
|
11
|
+
*,
|
|
12
|
+
mode: RenderMode = RenderMode.DEFAULT,
|
|
13
|
+
asset_base_url: str = "",
|
|
14
|
+
standalone: bool = True,
|
|
15
|
+
document_title: str | None = None,
|
|
16
|
+
) -> str:
|
|
17
|
+
"""惰性加载 HTML 实现并渲染严格 MiddleJson。"""
|
|
18
|
+
from ._internal.html.renderer import render_html as _render_html
|
|
19
|
+
|
|
20
|
+
return _render_html(
|
|
21
|
+
middle_json,
|
|
22
|
+
mode=mode,
|
|
23
|
+
asset_base_url=asset_base_url,
|
|
24
|
+
standalone=standalone,
|
|
25
|
+
document_title=document_title,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
__all__ = ["render_html"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""严格 MiddleJson 到 TeX Live LaTeX 源码的轻量公共门面。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..schema import MiddleJson
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def render_latex(
|
|
9
|
+
middle_json: MiddleJson,
|
|
10
|
+
*,
|
|
11
|
+
asset_base_path: str = "",
|
|
12
|
+
document_title: str | None = None,
|
|
13
|
+
) -> str:
|
|
14
|
+
"""惰性加载 LaTeX 实现并返回完整 UTF-8 文档源码。"""
|
|
15
|
+
from ._internal.latex.renderer import render_latex as _render_latex
|
|
16
|
+
|
|
17
|
+
return _render_latex(
|
|
18
|
+
middle_json,
|
|
19
|
+
asset_base_path=asset_base_path,
|
|
20
|
+
document_title=document_title,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
__all__ = ["render_latex"]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""严格 MiddleJson 到 Markdown 的轻量公共门面。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..options import LatexDelimitersConfig
|
|
6
|
+
from ..schema import MiddleJson, PageBlock
|
|
7
|
+
from .contracts import ImageRenderer, RenderMode
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def render_markdown(
|
|
11
|
+
middle_json: MiddleJson,
|
|
12
|
+
*,
|
|
13
|
+
mode: RenderMode = RenderMode.DEFAULT,
|
|
14
|
+
asset_base_url: str = "",
|
|
15
|
+
image_renderer: ImageRenderer | None = None,
|
|
16
|
+
latex_delimiters: LatexDelimitersConfig | None = None,
|
|
17
|
+
) -> str:
|
|
18
|
+
"""惰性加载 Markdown 实现并渲染严格 MiddleJson。"""
|
|
19
|
+
from ._internal.markdown.renderer import render_markdown as _render_markdown
|
|
20
|
+
|
|
21
|
+
return _render_markdown(
|
|
22
|
+
middle_json,
|
|
23
|
+
latex_delimiters=latex_delimiters,
|
|
24
|
+
mode=mode,
|
|
25
|
+
asset_base_url=asset_base_url,
|
|
26
|
+
image_renderer=image_renderer,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def render_single_block(
|
|
31
|
+
block: PageBlock,
|
|
32
|
+
*,
|
|
33
|
+
delimiters: LatexDelimitersConfig,
|
|
34
|
+
asset_base_url: str,
|
|
35
|
+
image_renderer: ImageRenderer | None = None,
|
|
36
|
+
) -> str:
|
|
37
|
+
"""为文档库等局部读取调用方渲染单个顶层块,不执行文档级合并。"""
|
|
38
|
+
from ._internal.markdown.blocks import render_single_block as render_block
|
|
39
|
+
|
|
40
|
+
return render_block(block, delimiters=delimiters, asset_base_url=asset_base_url, image_renderer=image_renderer)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def build_markdown_image(source: str, alt: str = "") -> str:
|
|
44
|
+
"""通过公开接口构造转义后的图片引用,避免调用方依赖 renderer 私有文件。"""
|
|
45
|
+
from ._internal.markdown.assets import build_markdown_image as build_image
|
|
46
|
+
|
|
47
|
+
return build_image(source, alt)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
__all__ = ["render_markdown", "render_single_block", "build_markdown_image"]
|
docvortex/render/pdf.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""严格 MiddleJson 到 PDF bytes 的轻量公共门面。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..schema import MiddleJson
|
|
6
|
+
from .contracts import AssetResolver
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def render_pdf(
|
|
10
|
+
middle_json: MiddleJson,
|
|
11
|
+
*,
|
|
12
|
+
asset_resolver: AssetResolver | None = None,
|
|
13
|
+
document_title: str | None = None,
|
|
14
|
+
) -> bytes:
|
|
15
|
+
"""惰性加载 PDF 实现并渲染严格 MiddleJson。"""
|
|
16
|
+
from ._internal.pdf.renderer import render_pdf as _render_pdf
|
|
17
|
+
|
|
18
|
+
return _render_pdf(
|
|
19
|
+
middle_json,
|
|
20
|
+
asset_resolver=asset_resolver,
|
|
21
|
+
document_title=document_title,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = ["render_pdf"]
|