atlisp-pdf2dwg
把 PDF 图纸/文档转换为可编辑的 DXF(可选 DWG)。
流程:OCR 图文混排 → 原生 PDF 矢量提取 + 位图矢量化 → ezdxf 组装 DXF。
- OCR 图文混排:默认为本地 RapidOCR(PP-OCR,逐行坐标、CPU、快);可选 surya VLM (整页布局 + 文本,精度高但重)。
- 原生矢量:若 PDF 仍是矢量(含被转曲的文字),直接提取线条,比追踪位图更清晰、更小; 文字块内的字形轮廓会被剔除并替换为真实文字实体。
- 位图矢量化:PDF 内嵌图片先做中值分割颜色量化,再用 potrace 拟合平滑贝塞尔曲线 (回退到 OpenCV 轮廓追踪),随后采样+简化多边形,按原始变换/旋转映射回图纸并裁剪到页面。 相同图片(页眉 logo、二维码等)跨页只追踪一次,并可多进程并行,质量与速度兼顾。
- 默认输出线条(LWPOLYLINE),不用 HATCH。这是实测决定的:同一张图经 LibreDWG 转 DWG,
HATCH 版报 249 条
Skip HATCH common handles告警(填充大面积丢失),线条版只有 1 条。 代价是墨迹召回 84.2% → 68.3%(平铺多段线依赖绘制顺序,HATCH 则是逐环奇偶填充)。 若 DXF 是最终交付、且更在意洞的正确性,可加--vector-mode rings改用 HATCH。 - 页面堆叠:多页 PDF 默认纵向堆叠到模型空间,页间留间距;可用
--flat关闭。
安装
pip install atlisp-pdf2dwg # 核心(矢量 + OpenCV 位图,不含 OCR)
pip install "atlisp-pdf2dwg[potrace]" # + potrace 曲线追踪(推荐,图片更精细)
pip install "atlisp-pdf2dwg[rapid]" # + RapidOCR(推荐的本地 OCR)
pip install "atlisp-pdf2dwg[all]" # rapid + potrace
pip install "atlisp-pdf2dwg[surya]" # + surya VLM(可选,重)
需要 DWG 输出时另装 GNU LibreDWG 的 dxf2dwg,
或设置环境变量 PDF2DWG_DXF2DWG=/path/to/dxf2dwg。
命令行
# 默认:RapidOCR + 矢量 + 位图,输出 DXF
pdf2dwg convert 图纸.pdf -o 图纸.dxf
# 指定页码、DPI、关闭位图矢量化
pdf2dwg convert 图纸.pdf --pages 1-5,8 --dpi 300 --no-images
# 只提取矢量+位图(不 OCR,文字保留为轮廓)
pdf2dwg convert 图纸.pdf --no-ocr
# 输出 DWG(需 dxf2dwg)
pdf2dwg convert 图纸.pdf --format dwg
# 复用/缓存 OCR 结果
pdf2dwg convert 图纸.pdf --ocr-cache .ocr_cache
# 图片追踪质量/性能
pdf2dwg convert 图纸.pdf --trace potrace --image-max-dim 1600 --image-colors 8 --jobs 8
pdf2dwg convert 图纸.pdf --trace opencv # 不装 potrace 时的回退
pdf2dwg convert 图纸.pdf --image-min-area 8 --image-max-polys 20000 # 压体积
# 其它子命令
pdf2dwg ocr 图纸.pdf -o ocr_json --engine rapid
pdf2dwg render 图纸.dxf -o preview.png --scale 1.5
pdf2dwg to-dwg 图纸.dxf
pdf2dwg info # 查看引擎与 dxf2dwg 路径
Python API
from pdf2dwg import convert_pdf
convert_pdf(
"图纸.pdf",
"图纸.dxf",
page_spec="1-10", # 1-based;或 pages=[0,1,2]
dpi=200,
ocr="rapid", # 或 "surya" / None
images=True, # 位图矢量化
vectors=True, # 原生 PDF 矢量
stack=True, # 多页纵向堆叠
ocr_cache=".ocr_cache",
)
分步使用:
import pymupdf
from pdf2dwg import get_engine, build_dxf, render_page
doc = pymupdf.open("图纸.pdf")
engine = get_engine("rapid")
pages_ocr = {i: engine.run_image(render_page(doc, i, 200), i + 1, 200)
for i in range(doc.page_count)}
build_dxf("图纸.pdf", "图纸.dxf", pages_ocr=pages_ocr)
输出图层
| 图层 | 内容 |
|---|---|
TEXT / TEXT-TITLE |
OCR 文字(正文 / 标题),样式 HZ(默认 simsun.ttc) |
GRAPHICS / GRAPHICS-FILL |
PDF 原生矢量(描边 / 填充),真彩色 |
IMAGES |
位图矢量化结果(真彩色) |
PAGE |
页面边框与页码 |
说明
-
坐标单位与 PDF 一致(points,1 pt = 1/72 inch)。
-
输出为 R2004 DXF:更早的版本无法写出真彩色(420 组码),颜色会全部丢失。
-
线稿可切换为笔画中心线追踪:
--image-line-art on跳过"填充区域"模型,直接追踪笔画的 中轴线,适合扫描线稿。注意实测收益比想象中小:第 20 页 IoU 0.357 → 0.382,而召回基本不变 (0.862 → 0.859)。请用text_mode="none"测量——若用"strokes"评分,文字会被 OCR 实体 和线稿各画一遍,线稿会因此虚高。照片会变糟,所以默认关闭;--auto-tune会实测后再决定要不要用。 -
默认
--vector-mode legacy(平铺 LWPOLYLINE)。rings用 HATCH 带洞,IoU 更高 (第 1/5/20 页 0.402 对 0.312),但 LibreDWG 无法承载 HATCH:653 个 HATCH 的图会报 653 条Skip HATCH common handles,而多边形一条都没有。只有需要 DWG 输出时才值得切到 rings。 -
中文文字样式默认字体
simsun.ttc,可在build_dxf(..., text_font=...)中修改; 若 CAD 中字体缺失,替换为本地已安装的中文字体即可。 -
文字也带真彩色:从原页面在每个 OCR 文字框内采样墨色写入实体,所以蓝色标题不会变黑。 每个框按自身纸张底色取阈值(取比纸色暗 60% 的像素中位数),因此灰度扫描件和有色纸都能用。 9 页实测彩色一致率 86.19% → 88.53%,
rgb_mae24.43 → 21.52。--no-text-color可关闭。 -
位图矢量化对线条图效果最佳;照片类图片会产生较多多边形,可用
--image-min-area/--image-max-polys/--no-images控制。 -
灰阶抗锯齿归并(默认开启,
merge_neutral):~200 DPI 扫描件里的 0.25 pt 线只有一个 抗锯齿像素,一条黑线会散成 (121,121,121)…(216,216,216) 一整条灰阶,每一级都变成独立的 填充,最浅那级在白纸上基本看不见。现���把严格中性灰(max-min ≤ 12)归并到最深的一档, 并合并标签消除重复环。只处理中性灰是有意为之:封面的米色 (200,197,185) 通道差为 15、 蓝色 logo 根本不是中性色,都会被保留。实测墨迹召回 70.1% → 82.0%,实体数 −19.8%。 用vectorize_image(..., merge_neutral=False)可关闭。 -
合并后的中性灰掩膜再做 3×3 形态学闭运算(
neutral_close,默认 3)。合并会交错灰阶各级,掩膜边界呈阶梯状,产生大量冗余环。只对这一个标签做闭运算即可:9 页实测召回 82.0% → 84.2%,IoU 0.482 → 0.487,实体数 −9.4%,体积 −8.0%(第 5 页 2.18 → 1.59 MB)。注意闭运算会让笔画略微变粗,rgb_mae会上升。 -
--image-max-dim(默认 600)是体积与保真的主要开关。绝大多数内嵌图实际放置尺寸 远小于其像素尺寸,600 已足够;只有当某页把扫描图放大显示时(如 2500px 的图放到 700pt 宽)才需要调到 1000~1600,否则细线会丢。 -
质量度量工具。
ink_iou/pct_bad_px是灰度的,对颜色完全失明——把整张图压成 单一墨色也能拿高 IoU。所以务必同时看ink_colour_acc与rgb_mae:python tools/compare_modes.py 图纸.pdf --pages 1-5 --dpi 100 # legacy vs rings python tools/auto_tune.py 图纸.pdf --pages 1-61 # 逐文档评估追踪参数
-
--auto-tune N(实验性)会抽样 N 页评估追踪参数并采纳胜出者。它只在超过保守阈值时 才改变配置;在参考图纸上它的建议在未抽样页上反而更差(颜色 −1.2 点、实体 +4.6%, 仅换 +0.005 IoU),因此默认值被保留。建议先用tools/auto_tune.py诊断再决定。
开发
pip install -e ".[dev,rapid]"
pytest
ruff check src tests tools # 硬闸门:只查真 bug
python -m build
许可
MIT
Metadata
Release files for atlisp-pdf2dwg 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| atlisp_pdf2dwg-0.1.1.tar.gz | 73.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| atlisp_pdf2dwg-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 130.7 kB
Release files / atlisp_pdf2dwg-0.1.1.tar.gz
| Download URL | atlisp_pdf2dwg-0.1.1.tar.gz |
|---|---|
| Size | 73.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1654a302c5b2d44014a0fc46786095f78e3955b8b81bde19addbf9c914a77120
|
|
BLAKE2b-256 checksum How to use checksums |
fc5cf8a8ef53a6b895dc23692500e5591ac3b737dc40d75bfce4b165afa936bf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / atlisp_pdf2dwg-0.1.1-py3-none-any.whl
| Download URL | atlisp_pdf2dwg-0.1.1-py3-none-any.whl |
|---|---|
| Size | 56.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6cae6ba5bb3904797554bad2e57d17caa79cbcffe4455e2b77182affea1d5975
|
|
BLAKE2b-256 checksum How to use checksums |
5992ba8048e6611a5d34e7ca5c0efe9e21e487b5c9dd22701647bc7b93851a49
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|