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.3.tar.gz (79.5 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.3-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.3-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.3.tar.gz.

File metadata

  • Download URL: dy_docs_tools-0.1.3.tar.gz
  • Upload date:
  • Size: 79.5 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.3.tar.gz
Algorithm Hash digest
SHA256 92d52cdbe95e411ec6da3d418c6e0390252f01936de12e55ed384841a68a9a79
MD5 415d481f8ddd8b99f11fab74b78b081b
BLAKE2b-256 6e4a41c557c4482bafc8db7a3c0e724e07da0a8ef54628b1559dfcdc80c30262

See more details on using hashes here.

Provenance

The following attestation bundles were made for dy_docs_tools-0.1.3.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.3-cp37-abi3-manylinux_2_34_x86_64.manylinux_2_36_x86_64.whl.

File metadata

File hashes

Hashes for dy_docs_tools-0.1.3-cp37-abi3-manylinux_2_34_x86_64.manylinux_2_36_x86_64.whl
Algorithm Hash digest
SHA256 ff870419a73336f90bfa3763d9fd31472b4938a1e3056804be1483407221b086
MD5 0a036336f887aec8d932a922ab1a0463
BLAKE2b-256 2f799b667ce6ceac15bd6befa884f64ba1c50a1ff1f28961f6ac2ceea950dd4d

See more details on using hashes here.

Provenance

The following attestation bundles were made for dy_docs_tools-0.1.3-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.3-cp37-abi3-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for dy_docs_tools-0.1.3-cp37-abi3-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 022c9c0e0973b26184992c98a5321972899cffbaed08767cca39fa42f7ada5f8
MD5 f99dce76aeebfc9942a66c32a39cb01f
BLAKE2b-256 d769da0f9f16ad7b6d00b66a4604a5c62056c3b179e0dbe6067b2bc6ea60db3e

See more details on using hashes here.

Provenance

The following attestation bundles were made for dy_docs_tools-0.1.3-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