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
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
"""固定 CJK 字体资源与 PDFium 字体提供器;导入时不读取字体或初始化 PDFium。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
import ctypes
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from hashlib import sha256
|
|
9
|
+
from importlib import resources
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
import struct
|
|
15
|
+
from typing import Any, Literal
|
|
16
|
+
|
|
17
|
+
_FONT_FILE = "DroidSansFallbackFull.ttf"
|
|
18
|
+
_FONT_SHA256 = "8a4dea0899424438af25a6f1f6eb61e5d111d85367eece0a5d30170861ae6b2e"
|
|
19
|
+
_FONT_NAME = "Droid Sans Fallback Full"
|
|
20
|
+
_POLICY = "droid-cjk-v1"
|
|
21
|
+
_CJK_CHARSETS = frozenset({128, 129, 134, 136})
|
|
22
|
+
_STYLE_SUFFIXES = (
|
|
23
|
+
"bolditalic",
|
|
24
|
+
"boldoblique",
|
|
25
|
+
"semibold",
|
|
26
|
+
"demibold",
|
|
27
|
+
"regular",
|
|
28
|
+
"medium",
|
|
29
|
+
"normal",
|
|
30
|
+
"italic",
|
|
31
|
+
"oblique",
|
|
32
|
+
"light",
|
|
33
|
+
"bold",
|
|
34
|
+
)
|
|
35
|
+
_FONT_ALIASES = {
|
|
36
|
+
"stsong": 134,
|
|
37
|
+
"simsun": 134,
|
|
38
|
+
"nsimsun": 134,
|
|
39
|
+
"simhei": 134,
|
|
40
|
+
"fangsong": 134,
|
|
41
|
+
"kaiti": 134,
|
|
42
|
+
"microsoftyahei": 134,
|
|
43
|
+
"songtisc": 134,
|
|
44
|
+
"heitisc": 134,
|
|
45
|
+
"droidsansfallbackfull": 134,
|
|
46
|
+
"droidsansfallback": 134,
|
|
47
|
+
"notosanscjksc": 134,
|
|
48
|
+
"notoserifcjksc": 134,
|
|
49
|
+
"宋体": 134,
|
|
50
|
+
"新宋体": 134,
|
|
51
|
+
"黑体": 134,
|
|
52
|
+
"仿宋": 134,
|
|
53
|
+
"楷体": 134,
|
|
54
|
+
"微软雅黑": 134,
|
|
55
|
+
"msung": 136,
|
|
56
|
+
"mhei": 136,
|
|
57
|
+
"mingliu": 136,
|
|
58
|
+
"pmingliu": 136,
|
|
59
|
+
"dfkaisb": 136,
|
|
60
|
+
"microsoftjhenghei": 136,
|
|
61
|
+
"songtitc": 136,
|
|
62
|
+
"heititc": 136,
|
|
63
|
+
"notosanscjktc": 136,
|
|
64
|
+
"notoserifcjktc": 136,
|
|
65
|
+
"新細明體": 136,
|
|
66
|
+
"細明體": 136,
|
|
67
|
+
"標楷體": 136,
|
|
68
|
+
"微軟正黑體": 136,
|
|
69
|
+
"heiseiminw3": 128,
|
|
70
|
+
"heiseikakugow5": 128,
|
|
71
|
+
"kozminpro": 128,
|
|
72
|
+
"msmincho": 128,
|
|
73
|
+
"mspmincho": 128,
|
|
74
|
+
"msgothic": 128,
|
|
75
|
+
"mspgothic": 128,
|
|
76
|
+
"yumincho": 128,
|
|
77
|
+
"yugothic": 128,
|
|
78
|
+
"meiryo": 128,
|
|
79
|
+
"notosanscjkjp": 128,
|
|
80
|
+
"notoserifcjkjp": 128,
|
|
81
|
+
"hygothic": 129,
|
|
82
|
+
"hysmyeongjo": 129,
|
|
83
|
+
"gulim": 129,
|
|
84
|
+
"batang": 129,
|
|
85
|
+
"dotum": 129,
|
|
86
|
+
"malgungothic": 129,
|
|
87
|
+
"notosanscjkkr": 129,
|
|
88
|
+
"notoserifcjkkr": 129,
|
|
89
|
+
}
|
|
90
|
+
_logger = logging.getLogger(__name__)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class PdfiumFontError(RuntimeError):
|
|
94
|
+
"""固定字体资源或字体提供器失效,不能作为文档损坏而静默降级。"""
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@dataclass(frozen=True, slots=True)
|
|
98
|
+
class PdfiumRuntimeInfo:
|
|
99
|
+
"""记录当前进程采用的 PDFium 与固定字体身份,不表示每份文档都发生了替代。"""
|
|
100
|
+
|
|
101
|
+
pdfium_version: str
|
|
102
|
+
font_policy: str
|
|
103
|
+
font_name: str
|
|
104
|
+
font_sha256: str
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _cjk_charset(face: bytes, charset: int) -> int | None:
|
|
108
|
+
"""优先按字符集识别 CJK,仅用明确族名和编码标记补充未指定字符集的请求。"""
|
|
109
|
+
if charset in _CJK_CHARSETS:
|
|
110
|
+
return charset
|
|
111
|
+
if charset not in (0, 1):
|
|
112
|
+
return None
|
|
113
|
+
# 明确的符号/其他语言字符集不会被字体名覆盖;不做任意汉字或子串猜测。
|
|
114
|
+
for encoding in ("utf-8", "gb18030", "big5", "cp932", "cp949"):
|
|
115
|
+
try:
|
|
116
|
+
name = face.decode(encoding)
|
|
117
|
+
except UnicodeDecodeError:
|
|
118
|
+
continue
|
|
119
|
+
name = re.sub(r"^[A-Z]{6}\+", "", name.lstrip("@"))
|
|
120
|
+
name = re.sub(r"[\s,_-]+", "", name).casefold()
|
|
121
|
+
candidates = [name]
|
|
122
|
+
for suffix in _STYLE_SUFFIXES:
|
|
123
|
+
if name.endswith(suffix):
|
|
124
|
+
candidates.append(name[: -len(suffix)])
|
|
125
|
+
for candidate in candidates:
|
|
126
|
+
if candidate in _FONT_ALIASES:
|
|
127
|
+
return _FONT_ALIASES[candidate]
|
|
128
|
+
for marker, value in (("gb2312", 134), ("gbk", 134), ("big5", 136)):
|
|
129
|
+
if candidate.endswith(marker):
|
|
130
|
+
return value
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _load_font() -> tuple[bytes, dict[int, tuple[int, int]]]:
|
|
135
|
+
"""校验发行资源身份并读取 SFNT 索引;各表保留偏移,避免复制整份字库。"""
|
|
136
|
+
try:
|
|
137
|
+
root = resources.files("docvortex").joinpath("resources", "fonts")
|
|
138
|
+
manifest = json.loads(root.joinpath("manifest.json").read_text(encoding="utf-8"))
|
|
139
|
+
if (manifest["policy"], manifest["file"], manifest["sha256"]) != (_POLICY, _FONT_FILE, _FONT_SHA256):
|
|
140
|
+
raise ValueError("font manifest does not match this runtime")
|
|
141
|
+
data = root.joinpath(_FONT_FILE).read_bytes()
|
|
142
|
+
if sha256(data).hexdigest() != _FONT_SHA256:
|
|
143
|
+
raise ValueError("font SHA256 mismatch")
|
|
144
|
+
if data[:4] != b"\x00\x01\x00\x00":
|
|
145
|
+
raise ValueError("expected the pinned standalone TrueType font")
|
|
146
|
+
count = struct.unpack_from(">H", data, 4)[0]
|
|
147
|
+
tables = {}
|
|
148
|
+
for index in range(count):
|
|
149
|
+
tag, _checksum, offset, size = struct.unpack_from(">4sIII", data, 12 + index * 16)
|
|
150
|
+
if offset + size > len(data):
|
|
151
|
+
raise ValueError("invalid SFNT table bounds")
|
|
152
|
+
tables[int.from_bytes(tag, "big")] = (offset, size)
|
|
153
|
+
return data, tables
|
|
154
|
+
except Exception as exc:
|
|
155
|
+
raise PdfiumFontError(f"Unable to load bundled {_FONT_FILE}: {exc}") from exc
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@dataclass(frozen=True, slots=True)
|
|
159
|
+
class _FontHandle:
|
|
160
|
+
"""区分 Python 管理的固定字库句柄与默认提供器的原生句柄。"""
|
|
161
|
+
|
|
162
|
+
kind: Literal["bundled", "system"]
|
|
163
|
+
value: int
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class _FontProvider:
|
|
167
|
+
"""包装原生默认提供器,强制 CJK 映射并保持 ABI 回调及字节的进程级所有权。"""
|
|
168
|
+
|
|
169
|
+
def __init__(self, raw: Any, pdfium_version: str) -> None:
|
|
170
|
+
"""先完整验证资源,再分配默认提供器及回调,避免半初始化状态。"""
|
|
171
|
+
self.data, self.tables = _load_font()
|
|
172
|
+
self.raw = raw
|
|
173
|
+
self.pid = os.getpid()
|
|
174
|
+
self.info = PdfiumRuntimeInfo(pdfium_version, _POLICY, _FONT_NAME, _FONT_SHA256)
|
|
175
|
+
self.cache_name = f"DocVortex-{_POLICY}-{_FONT_SHA256}".encode("ascii")
|
|
176
|
+
self.handles: dict[int, _FontHandle] = {}
|
|
177
|
+
self.next_handle = 0
|
|
178
|
+
self.enum_depth = 0
|
|
179
|
+
self.released = False
|
|
180
|
+
self.failure: tuple[str, BaseException] | None = None
|
|
181
|
+
self.reported_delegations: set[tuple[bytes, int]] = set()
|
|
182
|
+
self.request_charsets: dict[bytes, int] = {}
|
|
183
|
+
self.default: Any = None
|
|
184
|
+
self.bundled_requests = 0
|
|
185
|
+
self.full_font_copies = 0
|
|
186
|
+
types = dict(raw.FPDF_SYSFONTINFO._fields_)
|
|
187
|
+
self.callbacks = (
|
|
188
|
+
self._bind(types["Release"], self._release, None),
|
|
189
|
+
self._bind(types["EnumFonts"], self._enum_fonts, None),
|
|
190
|
+
self._bind(types["MapFont"], self._map_font, None),
|
|
191
|
+
self._bind(types["GetFont"], self._get_font, None),
|
|
192
|
+
self._bind(types["GetFontData"], self._get_font_data, 0),
|
|
193
|
+
self._bind(types["GetFaceName"], self._get_face_name, 0),
|
|
194
|
+
self._bind(types["GetFontCharset"], self._get_font_charset, 1),
|
|
195
|
+
self._bind(types["DeleteFont"], self._delete_font, None),
|
|
196
|
+
)
|
|
197
|
+
self.interface = raw.FPDF_SYSFONTINFO(1, *self.callbacks)
|
|
198
|
+
self.default = raw.FPDF_GetDefaultSystemFontInfo()
|
|
199
|
+
if not self.default:
|
|
200
|
+
raise PdfiumFontError("PDFium did not provide its default system font interface")
|
|
201
|
+
|
|
202
|
+
def _bind(self, callback_type: Any, function: Callable[..., Any], failure_value: Any) -> Any:
|
|
203
|
+
"""使用当前平台绑定声明的 ABI,并把异常留到原生调用返回后处理。"""
|
|
204
|
+
|
|
205
|
+
def invoke(*args: Any) -> Any:
|
|
206
|
+
"""C 回调只能返回 ABI 约定的值,异常不得越过原生栈。"""
|
|
207
|
+
try:
|
|
208
|
+
return function(*args)
|
|
209
|
+
except BaseException as exc:
|
|
210
|
+
if self.failure is None:
|
|
211
|
+
self.failure = (function.__name__, exc)
|
|
212
|
+
return failure_value
|
|
213
|
+
|
|
214
|
+
return callback_type(invoke)
|
|
215
|
+
|
|
216
|
+
def install(self) -> None:
|
|
217
|
+
"""在首次字体使用前注册接口,不重建 PDFium 或修改系统字体。"""
|
|
218
|
+
try:
|
|
219
|
+
self.raw.FPDF_SetSystemFontInfo(ctypes.byref(self.interface))
|
|
220
|
+
except BaseException:
|
|
221
|
+
self._release(None)
|
|
222
|
+
raise
|
|
223
|
+
self.raise_if_failed()
|
|
224
|
+
|
|
225
|
+
def raise_if_failed(self) -> None:
|
|
226
|
+
"""原生调用返回后报告永久故障,避免复用可能已降级的字体缓存。"""
|
|
227
|
+
if self.failure is not None:
|
|
228
|
+
name, error = self.failure
|
|
229
|
+
if not isinstance(error, Exception):
|
|
230
|
+
raise error
|
|
231
|
+
raise PdfiumFontError(f"PDFium font callback {name} failed: {error}") from error
|
|
232
|
+
if self.released:
|
|
233
|
+
raise PdfiumFontError("The PDFium font runtime has already been released")
|
|
234
|
+
|
|
235
|
+
def _allocate(self, kind: Literal["bundled", "system"], value: int) -> int:
|
|
236
|
+
"""分配不与系统地址混淆的 opaque ID,使用后统一交给 DeleteFont。"""
|
|
237
|
+
self.next_handle += 1
|
|
238
|
+
self.handles[self.next_handle] = _FontHandle(kind, value)
|
|
239
|
+
return self.next_handle
|
|
240
|
+
|
|
241
|
+
def _release(self, _info: Any) -> None:
|
|
242
|
+
"""由 PDFium 清理接口时释放默认提供器,不重新安装或销毁整个运行时。"""
|
|
243
|
+
if self.released:
|
|
244
|
+
return
|
|
245
|
+
self.released = True
|
|
246
|
+
try:
|
|
247
|
+
for key in list(self.handles):
|
|
248
|
+
self._delete_font(None, key)
|
|
249
|
+
finally:
|
|
250
|
+
if self.default:
|
|
251
|
+
self.raw.FPDF_FreeDefaultSystemFontInfo(self.default)
|
|
252
|
+
self.default = None
|
|
253
|
+
|
|
254
|
+
def _enum_fonts(self, _info: Any, mapper: Any) -> None:
|
|
255
|
+
"""默认枚举负责初始化 Linux 字库;枚举中读取原始名称表,不替换其元数据。"""
|
|
256
|
+
if not self.default or not self.default.contents.EnumFonts:
|
|
257
|
+
return
|
|
258
|
+
self.enum_depth += 1
|
|
259
|
+
try:
|
|
260
|
+
self.default.contents.EnumFonts(self.default, mapper)
|
|
261
|
+
finally:
|
|
262
|
+
self.enum_depth -= 1
|
|
263
|
+
|
|
264
|
+
def _map_font(self, _info: Any, weight: int, italic: int, charset: int, pitch: int, face: Any, exact: Any) -> int | None:
|
|
265
|
+
"""实际 CJK 字体请求优先命中固定字体,其他请求保持默认提供器语义。"""
|
|
266
|
+
name = ctypes.string_at(face) if face else b""
|
|
267
|
+
if not self.enum_depth:
|
|
268
|
+
self.request_charsets[name] = charset
|
|
269
|
+
selected = _cjk_charset(name, charset) if not self.enum_depth else None
|
|
270
|
+
if selected is not None:
|
|
271
|
+
self.bundled_requests += 1
|
|
272
|
+
return self._allocate("bundled", selected)
|
|
273
|
+
if not self.enum_depth and len(self.reported_delegations) < 128 and (name, charset) not in self.reported_delegations:
|
|
274
|
+
self.reported_delegations.add((name, charset))
|
|
275
|
+
_logger.debug("Delegating PDF font request: charset=%d face=%r", charset, name)
|
|
276
|
+
if self.default and self.default.contents.MapFont:
|
|
277
|
+
handle = self.default.contents.MapFont(self.default, weight, italic, charset, pitch, face, exact)
|
|
278
|
+
if handle:
|
|
279
|
+
return self._allocate("system", int(handle))
|
|
280
|
+
return None
|
|
281
|
+
|
|
282
|
+
def _get_font(self, _info: Any, face: Any) -> int | None:
|
|
283
|
+
"""显式字体名查询采用同一替代规则,枚举期间始终读取原系统字体。"""
|
|
284
|
+
name = ctypes.string_at(face) if face else b""
|
|
285
|
+
selected = _cjk_charset(name, self.request_charsets.get(name, 1)) if not self.enum_depth else None
|
|
286
|
+
if selected is not None or (not self.enum_depth and name == self.cache_name):
|
|
287
|
+
self.bundled_requests += 1
|
|
288
|
+
return self._allocate("bundled", selected if selected is not None else 134)
|
|
289
|
+
if self.default and self.default.contents.GetFont:
|
|
290
|
+
handle = self.default.contents.GetFont(self.default, face)
|
|
291
|
+
if handle:
|
|
292
|
+
return self._allocate("system", int(handle))
|
|
293
|
+
return None
|
|
294
|
+
|
|
295
|
+
def _get_font_data(self, _info: Any, handle: int, table: int, buffer: Any, size: int) -> int:
|
|
296
|
+
"""遵守查询长度/复制字节的接口约定;未知 SFNT 表返回零。"""
|
|
297
|
+
font = self.handles[handle]
|
|
298
|
+
if font.kind == "system":
|
|
299
|
+
return self.default.contents.GetFontData(self.default, font.value, table, buffer, size)
|
|
300
|
+
offset, length = (0, len(self.data)) if table == 0 else self.tables.get(table, (0, 0))
|
|
301
|
+
if buffer and size >= length and length:
|
|
302
|
+
ctypes.memmove(buffer, self.data[offset : offset + length], length)
|
|
303
|
+
if table == 0:
|
|
304
|
+
self.full_font_copies += 1
|
|
305
|
+
return length
|
|
306
|
+
|
|
307
|
+
def _get_face_name(self, _info: Any, handle: int, buffer: Any, size: int) -> int:
|
|
308
|
+
"""用含哈希的稳定缓存身份复用 Droid,避免命中系统中的同名不同版本字库。"""
|
|
309
|
+
font = self.handles[handle]
|
|
310
|
+
if font.kind == "system":
|
|
311
|
+
if self.default.contents.GetFaceName:
|
|
312
|
+
return self.default.contents.GetFaceName(self.default, font.value, buffer, size)
|
|
313
|
+
return 0
|
|
314
|
+
value = self.cache_name + b"\0"
|
|
315
|
+
if buffer and size >= len(value):
|
|
316
|
+
ctypes.memmove(buffer, value, len(value))
|
|
317
|
+
return len(value)
|
|
318
|
+
|
|
319
|
+
def _get_font_charset(self, _info: Any, handle: int) -> int:
|
|
320
|
+
"""返回请求对应的 CJK 字符集,系统字体则委托原查询。"""
|
|
321
|
+
font = self.handles[handle]
|
|
322
|
+
if font.kind == "system":
|
|
323
|
+
if self.default.contents.GetFontCharset:
|
|
324
|
+
return self.default.contents.GetFontCharset(self.default, font.value)
|
|
325
|
+
return 1
|
|
326
|
+
return font.value
|
|
327
|
+
|
|
328
|
+
def _delete_font(self, _info: Any, handle: int) -> None:
|
|
329
|
+
"""仅向原提供器释放系统句柄,固定字体字节保留到进程结束。"""
|
|
330
|
+
font = self.handles.pop(handle)
|
|
331
|
+
if font.kind == "system" and self.default and self.default.contents.DeleteFont:
|
|
332
|
+
self.default.contents.DeleteFont(self.default, font.value)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
__all__ = ["PdfiumFontError", "PdfiumRuntimeInfo"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""PDF 页面坐标和裁图的公共纯函数接口。"""
|
|
2
|
+
|
|
3
|
+
from .visual_geometry import (
|
|
4
|
+
_normalize_page_size as normalize_page_size,
|
|
5
|
+
_bbox_to_pixel_bbox as bbox_to_pixel_bbox,
|
|
6
|
+
_normalize_layout_bbox_to_unit as normalize_layout_bbox_to_unit,
|
|
7
|
+
_medium_bbox_to_quad as medium_bbox_to_quad,
|
|
8
|
+
_normalize_medium_content as normalize_medium_content,
|
|
9
|
+
_table_bbox_center as table_bbox_center,
|
|
10
|
+
_normalize_visual_block_angle as normalize_visual_block_angle,
|
|
11
|
+
_rotate_visual_block_image_to_upright as rotate_visual_block_image_to_upright,
|
|
12
|
+
_rotate_medium_table_bbox as rotate_medium_table_bbox,
|
|
13
|
+
_get_medium_table_virtual_image_bbox as get_medium_table_virtual_image_bbox,
|
|
14
|
+
_encode_page_crop_as_jpeg_data_uri as encode_page_crop_as_jpeg_data_uri,
|
|
15
|
+
_sidecar_bbox_to_page_bbox as sidecar_bbox_to_page_bbox,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"normalize_page_size",
|
|
20
|
+
"bbox_to_pixel_bbox",
|
|
21
|
+
"normalize_layout_bbox_to_unit",
|
|
22
|
+
"medium_bbox_to_quad",
|
|
23
|
+
"normalize_medium_content",
|
|
24
|
+
"table_bbox_center",
|
|
25
|
+
"normalize_visual_block_angle",
|
|
26
|
+
"rotate_visual_block_image_to_upright",
|
|
27
|
+
"rotate_medium_table_bbox",
|
|
28
|
+
"get_medium_table_virtual_image_bbox",
|
|
29
|
+
"encode_page_crop_as_jpeg_data_uri",
|
|
30
|
+
"sidecar_bbox_to_page_bbox",
|
|
31
|
+
]
|