Skip to main content

High-performance document conversion tools powered by Rust + PyO3.

Project description

dy_docs_tools

docs_tools 是一个基于 Rust + PyO3 的文档转换工具包,当前支持:

  • PDF -> 图片
  • PDF -> PDF(先转为受控图片,再重建回 PDF)
  • 图片 -> PDF
  • DOCX -> PDF
  • DOCX -> 图片

1. 环境准备

Rust 工具链

在 Windows PowerShell 中安装 Rust:

winget install Rustlang.Rustup

安装完成后重新打开终端,并执行:

cargo --version
rustc --version

Python 构建工具

python -m pip install --upgrade pip
python -m pip install maturin

外部转换器

  • pdftoppm(来自 Poppler),用于 PDF -> 图片
  • soffice(来自 LibreOffice),用于 DOCX -> PDF
  • 如果 pdftoppm 不在 PATH 中,库会在 Windows 和 Linux 的常见安装目录中自动查找

Windows 示例安装命令:

winget install oschwartz10612.Poppler
winget install TheDocumentFoundation.LibreOffice

确认命令可用:

pdftoppm -v
soffice --version

2. 构建与安装

在项目根目录执行:

maturin develop

如果更倾向于构建 wheel:

maturin build --release
python -m pip install .\target\wheels\*.whl

Linux 发布基线说明:

  • 已发布的 Linux wheel 覆盖 manylinux_2_24glibc >= 2.24
  • 额外提供 manylinux_2_36glibc >= 2.36)版本
  • GitHub Actions 发布流程默认基于 manylinux_2_24 构建
  • manylinux_2_36 wheel 在 Debian 12 容器中通过 maturin + auditwheel 构建
  • 如果要复现 Linux 发布环境,优先使用 cibuildwheel 或与 manylinux_2_24 一致的容器,不要直接在更新的宿主机系统上构建发布轮子

快速验证

python scripts\verify.py

如果包导入失败,脚本会自动尝试加载 target/wheels 中最新生成的 wheel。

3. Python 接口

from docs_tools import (
    close_converter_service,
    pdf_to_pdf,
    pdf_to_image,
    image_to_pdf,
    docx_to_pdf,
    docx_to_image,
    get_converter_service,
)

# PDF -> 图片
images = pdf_to_image(
    "a.pdf",
    "out",
    dpi=300,
    fmt="png",
    prefix="page",
    max_area=36_000_000,
    max_size_mb=10,
)

# PDF -> PDF(默认 fmt 为 jpg)
pdf_out = pdf_to_pdf(
    "a.pdf",
    "a_rebuilt.pdf",
    dpi=300,
    fmt="jpg",
    max_area=36_000_000,
    max_size_mb=10,
)

# 图片 -> PDF
pdf_path = image_to_pdf(["1.png", "2.png"], "merged.pdf", max_area=36_000_000, max_size_mb=10)
pdf_bytes = image_to_pdf(["1.png", "2.png"], return_bytes=True)

# DOCX -> PDF(默认 fmt 为 jpg)
pdf_path = docx_to_pdf("a.docx", "out/a.pdf", dpi=300, fmt="jpg", max_area=36_000_000, max_size_mb=10)

# DOCX -> PDF,并启用受限重编码(默认关闭)
pdf_path_limited = docx_to_pdf(
    "a.docx",
    "out/a_limited.pdf",
    apply_constraints=True,
    dpi=300,
    fmt="jpg",
    max_area=36_000_000,
    max_size_mb=10,
)
pdf_bytes2 = docx_to_pdf("a.docx", return_bytes=True)

# DOCX -> 图片
images = docx_to_image("a.docx", "out", dpi=200, fmt="jpg", max_area=36_000_000, max_size_mb=10)
image_bytes_list = docx_to_image("a.docx", dpi=200, fmt="jpg", return_bytes=True)

# 持久化工作线程池,用于提升批量吞吐
service = get_converter_service(workers=4)
try:

    # 异步提交并获取句柄
    h1 = service.submit_to_images("a.pdf", "out/a", 200, "png", "page", max_area=36_000_000, max_size_mb=10)
    h2 = service.submit_to_pdf("a.docx", "out/a_from_service.pdf")
    h3 = service.submit_to_pdf(
        "a.docx",
        "out/auto_from_docx.pdf",
        apply_constraints=True,
        dpi=300,
        fmt="jpg",
        max_area=36_000_000,
        max_size_mb=10,
    )

    if not h1.done():
        print("h1 仍在运行")

    images = h1.result()             # 阻塞直到完成
    pdf_path = h2.result(10_000)     # 超时单位为毫秒
    pdf_path2 = h3.result(10_000)
finally:
    close_converter_service()

图片输出限制:

  • 所有转换接口都支持:pdf_to_imagedocx_to_imageimage_to_pdfdocx_to_pdfpdf_to_pdf,以及对应的池化版本
  • 参数为 max_area(像素面积)和 max_size_mb(MB)
  • 默认值分别为 36_000_00010
  • 当图片超过限制时,会自动缩放或压缩,直到满足约束

返回模式:

  • 路径模式:默认返回输出路径或路径列表
  • 字节模式:传入 return_bytes=True

调试日志:

  • 设置 DOCS_TOOLS_DEBUG=1,可在 stderr 中输出更详细的处理日志,方便分析快捷路径、栅格化、约束收敛和 PDF 重建过程

4. 优化与压测结论

4.1 当前版本已落地的优化

  • 基准脚本和压测脚本支持 --in-flight 滑窗提交,避免一次性把任务全部压入队列
  • 对 Poppler 和 LibreOffice 外部进程做全局并发限制,减少过度竞争
  • 优先按可信扩展名判断输入类型,减少内容嗅探开销
  • PDF 重建时减少重复图片解码和重复读取尺寸信息
  • return_bytes / data_url 路径改为内存构建 PDF,去掉临时文件往返
  • 保留扫描件快路径和并行图片转码路径
  • simple-scan JPEG 默认质量保持为 90

4.2 测试数据集信息

  • 数据集目录:C:\Users\PC\pros\python\tests
  • 文件总数:10
  • 总大小:27,515,936 字节(约 26.24 MiB
  • 本次 README 中的最新结果基于 wheel:target\wheels\docs_tools-0.1.0-cp37-abi3-win_amd64.whl
类型 数量 总字节 占比
.pdf 4 21,061,866 76.54%
.jpg 5 5,627,337 20.45%
[无扩展名] 1 826,733 3.00%
  • 最大文件:505344.pdf
  • 文件大小:19,430,977 字节(约 18.53 MiB
  • 页数:6
  • 占整个测试集字节量:70.62%
  • 结论:505344.pdf 是这个目录下最主要的性能瓶颈文件

4.3 最新连续压测结果(return_mode=pathdpi=300page_dpi=300

  • 结果目录:target\stress_loop_monitor_page300_latest_path
  • 汇总文件:target\stress_loop_monitor_page300_latest_path\summary.json
  • 明细文件:target\stress_loop_monitor_page300_latest_path\details.json
  • 压测参数:workers=4in_flight=4fmt=jpgrounds=10
指标 数值
总轮数 10
每轮文件数 10
总任务数 100
成功 / 失败 100 / 0
总耗时 47.171s
平均每轮耗时 4.717s
单轮最短耗时 4.200s
单轮最长耗时 4.985s
平均吞吐 2.120 files/s
Python 自身 RSS 起止 21.81 MB -> 24.01 MB
Python 自身峰值 RSS 63.109 MB
根进程峰值 RSS 59.934 MB
进程树峰值 RSS 729.738 MB
  • 结论:连续 10 轮压测全部成功,Python 自身常驻内存变化较小,峰值主要来自外部转换子进程

4.4 大文件 505344.pdf 重点指标

  • 输入文件:C:\Users\PC\pros\python\tests\505344.pdf
  • 10 轮平均耗时:4.696371s
  • P50 耗时:4.778077s
  • 最快 / 最慢:4.175831s / 4.971845s
  • 输出大小:3,432,157 字节(约 3.27 MiB
  • 相对源文件减小:82.34%
  • 占平均轮耗时:99.57%
  • 样例输出:target\stress_loop_monitor_page300_latest_path\outputs\505344.round10.pdf

补充说明:

  • 同目录下其余较慢 PDF 中,505976.pdf 的 10 轮平均耗时为 2.483662s
  • 另一份扫描票据类 PDF 的 10 轮平均耗时为 2.481054s
  • 在这组测试数据中,505344.pdf 明显决定了整轮尾延迟

4.5 dpi=150 补充压测结果

  • 结果目录:target\stress_loop_monitor_page150_latest_path
  • 汇总文件:target\stress_loop_monitor_page150_latest_path\summary.json
  • 明细文件:target\stress_loop_monitor_page150_latest_path\details.json
  • 压测参数:workers=4in_flight=4fmt=jpgrounds=1page_dpi=300
指标 数值
单轮总耗时 4.302403s
吞吐 2.323 files/s
Python 自身峰值 RSS 59.492 MB
进程树峰值 RSS 611.133 MB
505344.pdf 单轮耗时 4.278890s
505344.pdf 输出大小 3,432,157 字节
505344.pdf 样例输出 target\stress_loop_monitor_page150_latest_path\outputs\505344.round01.pdf
  • 结论:把 dpi300 调到 150 后,这个大文件的耗时和输出大小都没有出现明显下降,说明当前瓶颈并不主要由栅格 DPI 本身决定

4.6 505344.pdf 的分辨率、压缩与清晰度说明

  • 源页面宽度:2355.91 pt(约 32.72 inch
  • 输出页面宽度:564.96 pt(约 7.85 inch
  • 源页图宽度:2354 px
  • 输出页图宽度:2354 px
  • 源有效 DPI:约 71.94
  • 输出有效 DPI:300

关键结论:

  • 当前快路径没有把 505344.pdf 的页图像素放大
  • 300 dpi 来自物理页面尺寸缩小,不是把页图重采样到更高像素
  • 如果沿用源 PDF 的 MediaBox,有效 DPI 会继续接近 72,而不是 300

JPEG 与画质说明:

  • simple-scan 的默认 JPEG 质量是 90
  • 本次 505344.pdf 测试没有触发 max_size_mb=10 的二次压缩阈值,因此没有额外降低 JPEG 质量
  • 抽取页图总字节约为 18.09 MB -> 3.27 MB
  • 平均 PSNR43.13 dB
  • 平均绝对像素差:1.07 / 255
  • 综合判断:这是轻微有损压缩,文本和票据类内容的可读性变化较小

4.7 复现命令

下面这组命令可直接复现当前 README 中的核心性能数据:

# 构建最新 wheel
python -m maturin build --release -o target\wheels

# 单次目录基准:顺序提交
python scripts\benchmark_submit_to_pdf.py `
  --input-dir C:\Users\PC\pros\python\tests `
  --output-dir target\benchmark_seq_page300 `
  --dpi 300 --page-dpi 300 --fmt jpg `
  --workers 4 --in-flight 1 `
  --csv target\benchmark_seq_page300\results.csv

# 单次目录基准:并发滑窗提交
python scripts\benchmark_submit_to_pdf.py `
  --input-dir C:\Users\PC\pros\python\tests `
  --output-dir target\benchmark_conc_page300 `
  --dpi 300 --page-dpi 300 --fmt jpg `
  --workers 4 --in-flight 4 `
  --csv target\benchmark_conc_page300\results.csv

# 连续 10 轮压测(README 当前主结果)
python scripts\stress_submit_to_pdf_monitor.py `
  --input-dir C:\Users\PC\pros\python\tests `
  --output-dir target\stress_loop_monitor_page300_latest_path `
  --rounds 10 `
  --dpi 300 --page-dpi 300 --fmt jpg `
  --workers 4 --in-flight 4

# dpi=150 补充对比
python scripts\stress_submit_to_pdf_monitor.py `
  --input-dir C:\Users\PC\pros\python\tests `
  --output-dir target\stress_loop_monitor_page150_latest_path `
  --rounds 1 `
  --dpi 150 --page-dpi 300 --fmt jpg `
  --workers 4 --in-flight 4

5. CI 与发布

  • CI 工作流:.github/workflows/ci.yml
    • 构建 Linux 的 abi3 wheel
    • Linux wheel 默认基于 manylinux_2_24glibc >= 2.24
    • 额外构建 manylinux_2_36glibc >= 2.36
    • 同时构建源码分发包 sdist
  • 发布工作流:.github/workflows/publish.yml
    • 通过 v0.1.0 这类 git tag 触发
    • 将所有构建产物上传到 PyPI
    • Linux wheel 基线固定为 manylinux_2_24
    • 同时上传 manylinux_2_36 版本

推荐的 PyPI 配置:

  • 优先使用 GitHub 仓库 / 工作流对应的 Trusted Publishing(OIDC)
  • 如果使用 API Token 方式,需要在发布步骤中切换为 token 认证,并在仓库密钥中配置 PYPI_API_TOKEN

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dy_docs_tools-0.1.1.tar.gz (78.1 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

dy_docs_tools-0.1.1-cp37-abi3-manylinux_2_34_x86_64.manylinux_2_36_x86_64.whl (2.3 MB view details)

Uploaded CPython 3.7+manylinux: glibc 2.34+ x86-64manylinux: glibc 2.36+ x86-64

dy_docs_tools-0.1.1-cp37-abi3-manylinux_2_24_x86_64.whl (2.3 MB view details)

Uploaded CPython 3.7+manylinux: glibc 2.24+ x86-64

File details

Details for the file dy_docs_tools-0.1.1.tar.gz.

File metadata

  • Download URL: dy_docs_tools-0.1.1.tar.gz
  • Upload date:
  • Size: 78.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dy_docs_tools-0.1.1.tar.gz
Algorithm Hash digest
SHA256 0c86c9304be06ccdb836bc4a11f1746fb17c71a7c78fbfd9e6c180461162b869
MD5 67f2548bf2112c8c38682b5a7d092001
BLAKE2b-256 d3391b2c7c1df3b92070472e7a4ea410054ac944dd505efa8dd965f2ad23cd67

See more details on using hashes here.

Provenance

The following attestation bundles were made for dy_docs_tools-0.1.1.tar.gz:

Publisher: publish.yml on ClassesOver/docs_tools

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dy_docs_tools-0.1.1-cp37-abi3-manylinux_2_34_x86_64.manylinux_2_36_x86_64.whl.

File metadata

File hashes

Hashes for dy_docs_tools-0.1.1-cp37-abi3-manylinux_2_34_x86_64.manylinux_2_36_x86_64.whl
Algorithm Hash digest
SHA256 27228dde1c7fe0e27b33e8d9dc20cf3d587c9182d2e5f8eeef887c83b7bc4fd1
MD5 c7602ddfcd6fd997aa4739d3630a7b44
BLAKE2b-256 5009c8944727621a5cf80712ad70c7c629eaf9a322cb05a0599ab895e7979ee9

See more details on using hashes here.

Provenance

The following attestation bundles were made for dy_docs_tools-0.1.1-cp37-abi3-manylinux_2_34_x86_64.manylinux_2_36_x86_64.whl:

Publisher: publish.yml on ClassesOver/docs_tools

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dy_docs_tools-0.1.1-cp37-abi3-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for dy_docs_tools-0.1.1-cp37-abi3-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 9b3868256a2d3ea772456b893cfa1737d08aa79f561c02178d96f3aeec91e23a
MD5 2cdc08527d8ecfe32434792a018be5d1
BLAKE2b-256 2e02f7927458065491d626d6b0ec16df49d1f52a8824f7ca4b087c6291495009

See more details on using hashes here.

Provenance

The following attestation bundles were made for dy_docs_tools-0.1.1-cp37-abi3-manylinux_2_24_x86_64.whl:

Publisher: publish.yml on ClassesOver/docs_tools

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page