cad2image 0.1.0__tar.gz

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.
Files changed (31) hide show
  1. cad2image-0.1.0/LICENSE +21 -0
  2. cad2image-0.1.0/PKG-INFO +287 -0
  3. cad2image-0.1.0/README.md +256 -0
  4. cad2image-0.1.0/pyproject.toml +77 -0
  5. cad2image-0.1.0/setup.cfg +4 -0
  6. cad2image-0.1.0/src/cad2image/__init__.py +34 -0
  7. cad2image-0.1.0/src/cad2image/__main__.py +6 -0
  8. cad2image-0.1.0/src/cad2image/batch.py +158 -0
  9. cad2image-0.1.0/src/cad2image/cli.py +152 -0
  10. cad2image-0.1.0/src/cad2image/config.py +164 -0
  11. cad2image-0.1.0/src/cad2image/dwg2dxf.py +175 -0
  12. cad2image-0.1.0/src/cad2image/fonts/NOTICE +6 -0
  13. cad2image-0.1.0/src/cad2image/fonts/NotoSansMono-Regular.ttf +0 -0
  14. cad2image-0.1.0/src/cad2image/fonts/NotoSansSC-Regular.otf +0 -0
  15. cad2image-0.1.0/src/cad2image/fonts/OFL.txt +93 -0
  16. cad2image-0.1.0/src/cad2image/plotstyle.py +52 -0
  17. cad2image-0.1.0/src/cad2image/py.typed +0 -0
  18. cad2image-0.1.0/src/cad2image/render.py +358 -0
  19. cad2image-0.1.0/src/cad2image.egg-info/PKG-INFO +287 -0
  20. cad2image-0.1.0/src/cad2image.egg-info/SOURCES.txt +29 -0
  21. cad2image-0.1.0/src/cad2image.egg-info/dependency_links.txt +1 -0
  22. cad2image-0.1.0/src/cad2image.egg-info/entry_points.txt +2 -0
  23. cad2image-0.1.0/src/cad2image.egg-info/requires.txt +11 -0
  24. cad2image-0.1.0/src/cad2image.egg-info/top_level.txt +1 -0
  25. cad2image-0.1.0/tests/test_batch.py +86 -0
  26. cad2image-0.1.0/tests/test_cli.py +31 -0
  27. cad2image-0.1.0/tests/test_config.py +80 -0
  28. cad2image-0.1.0/tests/test_dwg2dxf.py +73 -0
  29. cad2image-0.1.0/tests/test_integration.py +37 -0
  30. cad2image-0.1.0/tests/test_plotstyle.py +51 -0
  31. cad2image-0.1.0/tests/test_render.py +185 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zhy201810576
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,287 @@
1
+ Metadata-Version: 2.1
2
+ Name: cad2image
3
+ Version: 0.1.0
4
+ Summary: DWG/DXF → PNG/SVG 渲染管线,用 ODA File Converter + ezdxf 替换 Acme CAD Converter
5
+ License: MIT
6
+ Project-URL: Homepage, https://github.com/zhy201810576/cad2image
7
+ Project-URL: Repository, https://github.com/zhy201810576/cad2image
8
+ Project-URL: Issues, https://github.com/zhy201810576/cad2image/issues
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
18
+ Requires-Python: >=3.8
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: ezdxf<1.2,>=1.1.3
22
+ Requires-Dist: PyMuPDF<1.25,>=1.23
23
+ Requires-Dist: numpy>=1.22
24
+ Requires-Dist: typer>=0.9
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0; extra == "dev"
27
+ Requires-Dist: ruff>=0.1; extra == "dev"
28
+ Requires-Dist: mypy>=1.0; extra == "dev"
29
+ Requires-Dist: Pillow>=9.0; extra == "dev"
30
+ Requires-Dist: fonttools>=4.30; extra == "dev"
31
+
32
+ # cad2image · 让 CAD 图纸渲染告别残余杂线
33
+
34
+ [![PyPI version](https://img.shields.io/pypi/v/cad2image.svg)](https://pypi.org/project/cad2image/)
35
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
36
+
37
+ 用「ODA File Converter + ezdxf」重建 DWG/DXF → PNG/SVG 渲染管线,替换 Acme CAD Converter。
38
+
39
+ 消除 Acme 底层 GDI 栅格化路径产生的「残余杂线」问题——圆弧走真圆弧,无多边形折痕与毛须。
40
+
41
+ ## 数据流
42
+
43
+ ```
44
+ DWG ──(ODA File Converter, DWG→DXF)──▶ DXF ──(ezdxf.addons.drawing)──▶ PNG / SVG
45
+ ▲ ▲
46
+ 稳定、可读文本 PyMuPDF 后端(无 GDI bug)
47
+ ```
48
+
49
+ - ODA File Converter 负责解析 DWG 二进制 → 标准 ASCII DXF(与 Acme 同 Teigha 内核)。
50
+ - 其余读取、渲染、样式、批处理全部在 Python 内完成。
51
+
52
+ ## 安装
53
+
54
+ 要求 Python 3.8+。
55
+
56
+ ```bash
57
+ # 从 PyPI 安装(推荐)
58
+ pip install cad2image
59
+
60
+ # 开发安装(含 pytest / ruff / mypy 等)
61
+ pip install -e ".[dev]"
62
+ ```
63
+
64
+ 需要单独安装 ODA File Converter(免费,https://www.opendesign.com/guestfiles/oda_file_converter)。
65
+
66
+ ODA 可执行文件路径解析优先级:
67
+
68
+ 1. 环境变量 `ODA_FILE_CONVERTER_PATH`
69
+ 2. 默认路径 `D:\ODA\ODAFileConverter_title 21.5.0\ODAFileConverter.exe`
70
+
71
+ ## 快速开始
72
+
73
+ ```bash
74
+ # 单个 DWG → PNG
75
+ python -m cad2image 轴套.dwg -o 轴套.png --dpi 1200
76
+
77
+ # 单个 DWG → SVG
78
+ python -m cad2image 轴套.dwg -o 轴套.svg
79
+
80
+ # 直接渲染已转好的 DXF(跳过 ODA)
81
+ python -m cad2image 轴套.dxf -o 轴套.png
82
+
83
+ # 批量处理目录
84
+ python -m cad2image "CAD Test/" -o out/ --recursive
85
+ ```
86
+
87
+ 安装后也可用控制台命令 `cad2image`。
88
+
89
+ ## CLI 参数
90
+
91
+ | 参数 | 说明 | 默认 |
92
+ |---|---|---|
93
+ | `--output, -o` | 输出文件/目录 | 与输入同目录 |
94
+ | `--dpi` | PNG 分辨率 | 300 |
95
+ | `--format, -f` | 输出格式 `png` / `svg` | png |
96
+ | `--background` | `default` / `white` / `black` / `off` | white |
97
+ | `--color` | `color` / `monochrome` / `grayscale` / `black` / `white` | color |
98
+ | `--lineweight` | `absolute` / `relative` | absolute |
99
+ | `--lineweight-scaling` | 线宽整体缩放系数(仅绝对线宽生效) | 1.0 |
100
+ | `--min-lineweight` | 最小打印线宽(mm) | 无 |
101
+ | `--relative-max-stroke-width` | 相对线宽:最粗线宽占页面较小边比例 | 0.001(0.1%) |
102
+ | `--relative-min-stroke-width` | 相对线宽:最细线宽占最粗线宽比例 | 0.05(5%) |
103
+ | `--ctb` | CTB 打印样式表路径 | 无 |
104
+ | `--font-dir` | 附加的 SHX/TTF 字体目录 | 无 |
105
+ | `--layout` | 布局名(缺省模型空间) | 模型空间 |
106
+ | `--width` / `--height` | 页面尺寸(mm) | 自适应 |
107
+ | `--fit` | 按内容包围盒自适应页面 | False |
108
+ | `--margin` | 内容自适应页面时的四周余量(%,相对内容较小边) | 3.0 |
109
+ | `--recursive` | 目录批量时递归子目录 | False |
110
+ | `--oda-path` | ODA 可执行文件路径 | 环境变量/默认路径 |
111
+
112
+ 退出码:`0` 成功;`1` 转换或渲染失败(批量时存在任一失败即非零)。
113
+
114
+ ## Python API 使用
115
+
116
+ 除 CLI 外,也可作为 Python 库导入,提供三层能力:**渲染**(DXF→PNG/SVG)、**转换**(DWG→DXF)、**批处理**。
117
+
118
+ > 前置条件:仅 DWG→DXF 转换需要 ODA File Converter;纯 DXF 渲染不需要。
119
+
120
+ ### 渲染 DXF → PNG/SVG
121
+
122
+ ```python
123
+ from cad2image import RenderOptions, render_dxf
124
+
125
+ # 按输出扩展名自动选 PNG/SVG 后端
126
+ render_dxf("轴套.dxf", "轴套.png", RenderOptions(dpi=300))
127
+ render_dxf("轴套.dxf", "轴套.svg", RenderOptions())
128
+ ```
129
+
130
+ ### DWG → 图片(端到端)
131
+
132
+ ```python
133
+ from cad2image import RenderOptions, process_dwg
134
+
135
+ out = process_dwg("轴套.dwg", "out/", RenderOptions(dpi=600)) # 返回 Path
136
+ ```
137
+
138
+ ### 分步转换(先转 DXF 再渲染,便于缓存)
139
+
140
+ ```python
141
+ from cad2image import convert_dwg_to_dxf, render_to_svg
142
+
143
+ dxf = convert_dwg_to_dxf("轴套.dwg", "dxf_cache/") # 返回 Path
144
+ render_to_svg(dxf, "轴套.svg", RenderOptions())
145
+ ```
146
+
147
+ ### 批量处理目录
148
+
149
+ ```python
150
+ from cad2image import RenderOptions, process_directory
151
+
152
+ result = process_directory("CAD Test/", "out/", RenderOptions(),
153
+ output_format="png", recursive=True)
154
+ print(f"成功 {result.success_count},失败 {result.failure_count}")
155
+ for f in result.failures:
156
+ print(f"[{f.stage}] {f.source.name}: {f.error}") # stage: convert / render
157
+ ```
158
+
159
+ ### CTB 打印样式
160
+
161
+ ```python
162
+ from cad2image import RenderOptions, load_ctb, get_lineweight, render_dxf
163
+
164
+ styles = load_ctb("黑白线型.ctb")
165
+ lw = get_lineweight(styles, aci=1) # 颜色索引 1 的线宽(mm),未覆盖时为 None
166
+
167
+ render_dxf("图.dxf", "图.png", RenderOptions(ctb="黑白线型.ctb"))
168
+ ```
169
+
170
+ ### RenderOptions 常用参数
171
+
172
+ ```python
173
+ RenderOptions(
174
+ dpi=300, # PNG 分辨率
175
+ background="white", # default/white/black/off
176
+ color_policy="color", # color/monochrome/grayscale/black/white
177
+ lineweight_policy="absolute", # absolute/relative
178
+ lineweight_scaling=1.0, # 线宽整体缩放(仅绝对线宽)
179
+ min_lineweight=None, # 最小打印线宽(mm)
180
+ relative_max_stroke_width=0.001, # 相对线宽最粗比例
181
+ relative_min_stroke_width=0.05, # 相对线宽最细比例
182
+ ctb="", # CTB 样式表路径
183
+ font_dir="", # 附加字体目录(SHX/TTF)
184
+ layout_name=None, # 布局名,None=模型空间
185
+ width_mm=None, height_mm=None, # 显式页面尺寸(mm)
186
+ fit_to_extents=False, # 按内容包围盒自适应
187
+ margin=3.0, # 自适应时四周余量(%)
188
+ )
189
+ ```
190
+
191
+ 错误统一抛 `FileNotFoundError` / `ValueError` / `RuntimeError`,可放心捕获;中文与 ASCII 标注随包内置开源字体(见下文「字体与中文」)。
192
+
193
+ ## Acme 参数映射
194
+
195
+ | Acme 参数 | 本工具映射 |
196
+ |---|---|
197
+ | `/res N` | `--dpi N` |
198
+ | `/w` `/h`(mm) | `--width` / `--height` |
199
+ | `/e` `/ad`(缩放扩展) | `--fit`(包围盒自适应) |
200
+ | `/b` 背景色 | `--background` |
201
+ | `/lw 0/1/2` | `--lineweight` + `--lineweight-scaling` |
202
+ | `/p 1/2/3`(1bit/灰度/256色) | `--color`(灰度暂以 monochrome 近似,待 Phase 2) |
203
+ | `/pw myset` | `plotstyle.load_ctb`(尚未实现,见已知限制) |
204
+ | `/a 0/-1/-2`(布局选择) | `--layout` |
205
+ | `/l` 报告 | 批处理汇总 + 退出码 |
206
+
207
+ ## 项目结构
208
+
209
+ ```
210
+ src/cad2image/
211
+ ├── cli.py # typer CLI 入口
212
+ ├── dwg2dxf.py # ODA File Converter 封装(目录级转换编排)
213
+ ├── render.py # ezdxf → PNG/SVG 渲染核心
214
+ ├── config.py # 参数 → ezdxf Configuration 映射
215
+ ├── plotstyle.py # CTB 打印样式(占位)
216
+ └── batch.py # 批量 + 部分失败结果对象
217
+ ```
218
+
219
+ ## 测试
220
+
221
+ ```bash
222
+ pytest # 单元测试(无外部依赖)
223
+ pytest -m integration # 集成测试(需真实 DWG + ODA)
224
+ ```
225
+
226
+ 集成测试通过环境变量提供真实图纸:
227
+
228
+ ```bash
229
+ CAD_TEST_DWG=E:/path/to/轴套.dwg pytest tests/test_integration.py -m integration
230
+ ```
231
+
232
+ ## 打包发布
233
+
234
+ ```bash
235
+ # 构建 wheel(本机需加 --no-build-isolation 规避构建隔离环境联网拉 setuptools 的 SSL 劫持)
236
+ python -m pip wheel . --no-deps --no-build-isolation -w dist
237
+
238
+ # 构建 sdist(可选)
239
+ python -c "import setuptools.build_meta as b; b.build_sdist('dist')"
240
+
241
+ # 安装到干净环境并验证中文渲染
242
+ python -m pip install dist/cad2image-0.1.0-py3-none-any.whl
243
+ python -m cad2image 轴套.dwg -o 轴套.png
244
+ ```
245
+
246
+ 产物 `dist/cad2image-0.1.0-py3-none-any.whl` 自带开源字体(Noto Sans SC / Noto Sans Mono)与 `py.typed`,无 `--no-build-isolation` 需要时可用标准 `python -m build` 生成 wheel + sdist。
247
+
248
+ ## 质量门禁
249
+
250
+ ```bash
251
+ ruff check .
252
+ ruff format .
253
+ mypy src/
254
+ pytest
255
+ ```
256
+
257
+ ## 字体与中文
258
+
259
+ 渲染时**默认自动扫描**随包内置的 `fonts/` 目录,也可通过 `--font-dir` 追加其它目录。内置字体均为**开源字体(SIL OFL 1.1)**,随仓库与 wheel 一起分发,中文与 ASCII 渲染开箱即用:
260
+
261
+ | 字体文件 | 用途 | 许可 |
262
+ |---|---|---|
263
+ | `NotoSansSC-Regular.otf` | 中文(含拉丁字符) | SIL OFL 1.1 |
264
+ | `NotoSansMono-Regular.ttf` | ASCII 等宽,近似 CAD 单线字体 | SIL OFL 1.1 |
265
+
266
+ > 完整许可与署名见 `src/cad2image/fonts/OFL.txt` 与 `NOTICE`。
267
+
268
+ CAD 图纸的文字样式常引用专有字体(微软 `SimSun`/`NSimSun`、Autodesk `romans.shx`/`txt.shx` 等)。渲染时会自动把这些字体名**重写为内置开源字体**:
269
+
270
+ - `SimSun` / `NSimSun` / `宋体` / `新宋体` / 中文 bigfont(`hztxt` / `gbcbig` 等)→ `NotoSansSC-Regular.otf`
271
+ - 其余 SHX 字形字体(`romans.shx` / `txt.shx` / `simplex` 等)→ `NotoSansMono-Regular.ttf`
272
+
273
+ > 替换会改变文字外观(SimSun → Noto Sans SC、SHX 单线体 → Noto Sans Mono 等宽),但保证纯开源、无专有字体再分发风险。若需严格保留原字体观感,可自行将对应字体放入 `fonts/` 或通过 `--font-dir` 指定。
274
+
275
+ **重要限制**:ezdxf 1.1.x 的 `ShapeFile` 解析器**不支持 bigfont 中文大字体**(`HZDX.SHX`/`gbcbig.shx` 等,源码中明确抛出 `UnsupportedShapeFile("BIGFONT shapes are not supported yet")`),因此本项目不内置 SHX 大字体;引用这类字体的图纸会被自动重写为 `NotoSansSC-Regular.otf`,中文可正常渲染。
276
+
277
+ ## 已知限制
278
+
279
+ - **灰度输出**(Acme `/p 2`):暂以 monochrome 近似,真正的 256 级灰度需像素级后处理。
280
+ - **SHX 中文 bigfont**:ezdxf 1.1.x 不支持,中文走 TTF 字体(见上)。
281
+ - **3D 消隐**(Acme `/hide`):未实现,假设输入为 2D 工程图。
282
+ - **Xref 外部引用**:转换前需确保 xref 文件与主图同目录(与 Acme 行为一致)。
283
+ - **页面单位**:模型空间包围盒自适应时假定绘图单位为 mm(`$INSUNITS` 未做换算)。
284
+
285
+ ## License
286
+
287
+ [MIT](./LICENSE)
@@ -0,0 +1,256 @@
1
+ # cad2image · 让 CAD 图纸渲染告别残余杂线
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/cad2image.svg)](https://pypi.org/project/cad2image/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
5
+
6
+ 用「ODA File Converter + ezdxf」重建 DWG/DXF → PNG/SVG 渲染管线,替换 Acme CAD Converter。
7
+
8
+ 消除 Acme 底层 GDI 栅格化路径产生的「残余杂线」问题——圆弧走真圆弧,无多边形折痕与毛须。
9
+
10
+ ## 数据流
11
+
12
+ ```
13
+ DWG ──(ODA File Converter, DWG→DXF)──▶ DXF ──(ezdxf.addons.drawing)──▶ PNG / SVG
14
+ ▲ ▲
15
+ 稳定、可读文本 PyMuPDF 后端(无 GDI bug)
16
+ ```
17
+
18
+ - ODA File Converter 负责解析 DWG 二进制 → 标准 ASCII DXF(与 Acme 同 Teigha 内核)。
19
+ - 其余读取、渲染、样式、批处理全部在 Python 内完成。
20
+
21
+ ## 安装
22
+
23
+ 要求 Python 3.8+。
24
+
25
+ ```bash
26
+ # 从 PyPI 安装(推荐)
27
+ pip install cad2image
28
+
29
+ # 开发安装(含 pytest / ruff / mypy 等)
30
+ pip install -e ".[dev]"
31
+ ```
32
+
33
+ 需要单独安装 ODA File Converter(免费,https://www.opendesign.com/guestfiles/oda_file_converter)。
34
+
35
+ ODA 可执行文件路径解析优先级:
36
+
37
+ 1. 环境变量 `ODA_FILE_CONVERTER_PATH`
38
+ 2. 默认路径 `D:\ODA\ODAFileConverter_title 21.5.0\ODAFileConverter.exe`
39
+
40
+ ## 快速开始
41
+
42
+ ```bash
43
+ # 单个 DWG → PNG
44
+ python -m cad2image 轴套.dwg -o 轴套.png --dpi 1200
45
+
46
+ # 单个 DWG → SVG
47
+ python -m cad2image 轴套.dwg -o 轴套.svg
48
+
49
+ # 直接渲染已转好的 DXF(跳过 ODA)
50
+ python -m cad2image 轴套.dxf -o 轴套.png
51
+
52
+ # 批量处理目录
53
+ python -m cad2image "CAD Test/" -o out/ --recursive
54
+ ```
55
+
56
+ 安装后也可用控制台命令 `cad2image`。
57
+
58
+ ## CLI 参数
59
+
60
+ | 参数 | 说明 | 默认 |
61
+ |---|---|---|
62
+ | `--output, -o` | 输出文件/目录 | 与输入同目录 |
63
+ | `--dpi` | PNG 分辨率 | 300 |
64
+ | `--format, -f` | 输出格式 `png` / `svg` | png |
65
+ | `--background` | `default` / `white` / `black` / `off` | white |
66
+ | `--color` | `color` / `monochrome` / `grayscale` / `black` / `white` | color |
67
+ | `--lineweight` | `absolute` / `relative` | absolute |
68
+ | `--lineweight-scaling` | 线宽整体缩放系数(仅绝对线宽生效) | 1.0 |
69
+ | `--min-lineweight` | 最小打印线宽(mm) | 无 |
70
+ | `--relative-max-stroke-width` | 相对线宽:最粗线宽占页面较小边比例 | 0.001(0.1%) |
71
+ | `--relative-min-stroke-width` | 相对线宽:最细线宽占最粗线宽比例 | 0.05(5%) |
72
+ | `--ctb` | CTB 打印样式表路径 | 无 |
73
+ | `--font-dir` | 附加的 SHX/TTF 字体目录 | 无 |
74
+ | `--layout` | 布局名(缺省模型空间) | 模型空间 |
75
+ | `--width` / `--height` | 页面尺寸(mm) | 自适应 |
76
+ | `--fit` | 按内容包围盒自适应页面 | False |
77
+ | `--margin` | 内容自适应页面时的四周余量(%,相对内容较小边) | 3.0 |
78
+ | `--recursive` | 目录批量时递归子目录 | False |
79
+ | `--oda-path` | ODA 可执行文件路径 | 环境变量/默认路径 |
80
+
81
+ 退出码:`0` 成功;`1` 转换或渲染失败(批量时存在任一失败即非零)。
82
+
83
+ ## Python API 使用
84
+
85
+ 除 CLI 外,也可作为 Python 库导入,提供三层能力:**渲染**(DXF→PNG/SVG)、**转换**(DWG→DXF)、**批处理**。
86
+
87
+ > 前置条件:仅 DWG→DXF 转换需要 ODA File Converter;纯 DXF 渲染不需要。
88
+
89
+ ### 渲染 DXF → PNG/SVG
90
+
91
+ ```python
92
+ from cad2image import RenderOptions, render_dxf
93
+
94
+ # 按输出扩展名自动选 PNG/SVG 后端
95
+ render_dxf("轴套.dxf", "轴套.png", RenderOptions(dpi=300))
96
+ render_dxf("轴套.dxf", "轴套.svg", RenderOptions())
97
+ ```
98
+
99
+ ### DWG → 图片(端到端)
100
+
101
+ ```python
102
+ from cad2image import RenderOptions, process_dwg
103
+
104
+ out = process_dwg("轴套.dwg", "out/", RenderOptions(dpi=600)) # 返回 Path
105
+ ```
106
+
107
+ ### 分步转换(先转 DXF 再渲染,便于缓存)
108
+
109
+ ```python
110
+ from cad2image import convert_dwg_to_dxf, render_to_svg
111
+
112
+ dxf = convert_dwg_to_dxf("轴套.dwg", "dxf_cache/") # 返回 Path
113
+ render_to_svg(dxf, "轴套.svg", RenderOptions())
114
+ ```
115
+
116
+ ### 批量处理目录
117
+
118
+ ```python
119
+ from cad2image import RenderOptions, process_directory
120
+
121
+ result = process_directory("CAD Test/", "out/", RenderOptions(),
122
+ output_format="png", recursive=True)
123
+ print(f"成功 {result.success_count},失败 {result.failure_count}")
124
+ for f in result.failures:
125
+ print(f"[{f.stage}] {f.source.name}: {f.error}") # stage: convert / render
126
+ ```
127
+
128
+ ### CTB 打印样式
129
+
130
+ ```python
131
+ from cad2image import RenderOptions, load_ctb, get_lineweight, render_dxf
132
+
133
+ styles = load_ctb("黑白线型.ctb")
134
+ lw = get_lineweight(styles, aci=1) # 颜色索引 1 的线宽(mm),未覆盖时为 None
135
+
136
+ render_dxf("图.dxf", "图.png", RenderOptions(ctb="黑白线型.ctb"))
137
+ ```
138
+
139
+ ### RenderOptions 常用参数
140
+
141
+ ```python
142
+ RenderOptions(
143
+ dpi=300, # PNG 分辨率
144
+ background="white", # default/white/black/off
145
+ color_policy="color", # color/monochrome/grayscale/black/white
146
+ lineweight_policy="absolute", # absolute/relative
147
+ lineweight_scaling=1.0, # 线宽整体缩放(仅绝对线宽)
148
+ min_lineweight=None, # 最小打印线宽(mm)
149
+ relative_max_stroke_width=0.001, # 相对线宽最粗比例
150
+ relative_min_stroke_width=0.05, # 相对线宽最细比例
151
+ ctb="", # CTB 样式表路径
152
+ font_dir="", # 附加字体目录(SHX/TTF)
153
+ layout_name=None, # 布局名,None=模型空间
154
+ width_mm=None, height_mm=None, # 显式页面尺寸(mm)
155
+ fit_to_extents=False, # 按内容包围盒自适应
156
+ margin=3.0, # 自适应时四周余量(%)
157
+ )
158
+ ```
159
+
160
+ 错误统一抛 `FileNotFoundError` / `ValueError` / `RuntimeError`,可放心捕获;中文与 ASCII 标注随包内置开源字体(见下文「字体与中文」)。
161
+
162
+ ## Acme 参数映射
163
+
164
+ | Acme 参数 | 本工具映射 |
165
+ |---|---|
166
+ | `/res N` | `--dpi N` |
167
+ | `/w` `/h`(mm) | `--width` / `--height` |
168
+ | `/e` `/ad`(缩放扩展) | `--fit`(包围盒自适应) |
169
+ | `/b` 背景色 | `--background` |
170
+ | `/lw 0/1/2` | `--lineweight` + `--lineweight-scaling` |
171
+ | `/p 1/2/3`(1bit/灰度/256色) | `--color`(灰度暂以 monochrome 近似,待 Phase 2) |
172
+ | `/pw myset` | `plotstyle.load_ctb`(尚未实现,见已知限制) |
173
+ | `/a 0/-1/-2`(布局选择) | `--layout` |
174
+ | `/l` 报告 | 批处理汇总 + 退出码 |
175
+
176
+ ## 项目结构
177
+
178
+ ```
179
+ src/cad2image/
180
+ ├── cli.py # typer CLI 入口
181
+ ├── dwg2dxf.py # ODA File Converter 封装(目录级转换编排)
182
+ ├── render.py # ezdxf → PNG/SVG 渲染核心
183
+ ├── config.py # 参数 → ezdxf Configuration 映射
184
+ ├── plotstyle.py # CTB 打印样式(占位)
185
+ └── batch.py # 批量 + 部分失败结果对象
186
+ ```
187
+
188
+ ## 测试
189
+
190
+ ```bash
191
+ pytest # 单元测试(无外部依赖)
192
+ pytest -m integration # 集成测试(需真实 DWG + ODA)
193
+ ```
194
+
195
+ 集成测试通过环境变量提供真实图纸:
196
+
197
+ ```bash
198
+ CAD_TEST_DWG=E:/path/to/轴套.dwg pytest tests/test_integration.py -m integration
199
+ ```
200
+
201
+ ## 打包发布
202
+
203
+ ```bash
204
+ # 构建 wheel(本机需加 --no-build-isolation 规避构建隔离环境联网拉 setuptools 的 SSL 劫持)
205
+ python -m pip wheel . --no-deps --no-build-isolation -w dist
206
+
207
+ # 构建 sdist(可选)
208
+ python -c "import setuptools.build_meta as b; b.build_sdist('dist')"
209
+
210
+ # 安装到干净环境并验证中文渲染
211
+ python -m pip install dist/cad2image-0.1.0-py3-none-any.whl
212
+ python -m cad2image 轴套.dwg -o 轴套.png
213
+ ```
214
+
215
+ 产物 `dist/cad2image-0.1.0-py3-none-any.whl` 自带开源字体(Noto Sans SC / Noto Sans Mono)与 `py.typed`,无 `--no-build-isolation` 需要时可用标准 `python -m build` 生成 wheel + sdist。
216
+
217
+ ## 质量门禁
218
+
219
+ ```bash
220
+ ruff check .
221
+ ruff format .
222
+ mypy src/
223
+ pytest
224
+ ```
225
+
226
+ ## 字体与中文
227
+
228
+ 渲染时**默认自动扫描**随包内置的 `fonts/` 目录,也可通过 `--font-dir` 追加其它目录。内置字体均为**开源字体(SIL OFL 1.1)**,随仓库与 wheel 一起分发,中文与 ASCII 渲染开箱即用:
229
+
230
+ | 字体文件 | 用途 | 许可 |
231
+ |---|---|---|
232
+ | `NotoSansSC-Regular.otf` | 中文(含拉丁字符) | SIL OFL 1.1 |
233
+ | `NotoSansMono-Regular.ttf` | ASCII 等宽,近似 CAD 单线字体 | SIL OFL 1.1 |
234
+
235
+ > 完整许可与署名见 `src/cad2image/fonts/OFL.txt` 与 `NOTICE`。
236
+
237
+ CAD 图纸的文字样式常引用专有字体(微软 `SimSun`/`NSimSun`、Autodesk `romans.shx`/`txt.shx` 等)。渲染时会自动把这些字体名**重写为内置开源字体**:
238
+
239
+ - `SimSun` / `NSimSun` / `宋体` / `新宋体` / 中文 bigfont(`hztxt` / `gbcbig` 等)→ `NotoSansSC-Regular.otf`
240
+ - 其余 SHX 字形字体(`romans.shx` / `txt.shx` / `simplex` 等)→ `NotoSansMono-Regular.ttf`
241
+
242
+ > 替换会改变文字外观(SimSun → Noto Sans SC、SHX 单线体 → Noto Sans Mono 等宽),但保证纯开源、无专有字体再分发风险。若需严格保留原字体观感,可自行将对应字体放入 `fonts/` 或通过 `--font-dir` 指定。
243
+
244
+ **重要限制**:ezdxf 1.1.x 的 `ShapeFile` 解析器**不支持 bigfont 中文大字体**(`HZDX.SHX`/`gbcbig.shx` 等,源码中明确抛出 `UnsupportedShapeFile("BIGFONT shapes are not supported yet")`),因此本项目不内置 SHX 大字体;引用这类字体的图纸会被自动重写为 `NotoSansSC-Regular.otf`,中文可正常渲染。
245
+
246
+ ## 已知限制
247
+
248
+ - **灰度输出**(Acme `/p 2`):暂以 monochrome 近似,真正的 256 级灰度需像素级后处理。
249
+ - **SHX 中文 bigfont**:ezdxf 1.1.x 不支持,中文走 TTF 字体(见上)。
250
+ - **3D 消隐**(Acme `/hide`):未实现,假设输入为 2D 工程图。
251
+ - **Xref 外部引用**:转换前需确保 xref 文件与主图同目录(与 Acme 行为一致)。
252
+ - **页面单位**:模型空间包围盒自适应时假定绘图单位为 mm(`$INSUNITS` 未做换算)。
253
+
254
+ ## License
255
+
256
+ [MIT](./LICENSE)
@@ -0,0 +1,77 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cad2image"
7
+ version = "0.1.0"
8
+ description = "DWG/DXF → PNG/SVG 渲染管线,用 ODA File Converter + ezdxf 替换 Acme CAD Converter"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = {text = "MIT"}
12
+ classifiers = [
13
+ "License :: OSI Approved :: MIT License",
14
+ "Operating System :: OS Independent",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.8",
17
+ "Programming Language :: Python :: 3.9",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Topic :: Multimedia :: Graphics :: Graphics Conversion",
22
+ ]
23
+ dependencies = [
24
+ "ezdxf>=1.1.3,<1.2",
25
+ "PyMuPDF>=1.23,<1.25",
26
+ "numpy>=1.22",
27
+ "typer>=0.9",
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ dev = [
32
+ "pytest>=7.0",
33
+ "ruff>=0.1",
34
+ "mypy>=1.0",
35
+ "Pillow>=9.0", # 测试中读取 PNG 像素校验渲染结果
36
+ "fonttools>=4.30", # ezdxf 渲染字体时的运行时依赖(ezdxf 自身也会安装)
37
+ ]
38
+
39
+ [project.scripts]
40
+ cad2image = "cad2image.cli:app"
41
+
42
+ [project.urls]
43
+ Homepage = "https://github.com/zhy201810576/cad2image"
44
+ Repository = "https://github.com/zhy201810576/cad2image"
45
+ Issues = "https://github.com/zhy201810576/cad2image/issues"
46
+
47
+ [tool.setuptools.packages.find]
48
+ where = ["src"]
49
+
50
+ # 开源字体(Noto Sans SC / Noto Sans Mono,SIL OFL 1.1)与 py.typed 作为包数据随 wheel 分发,
51
+ # 确保安装后中文与 ASCII 渲染开箱即用。
52
+ [tool.setuptools.package-data]
53
+ cad2image = ["py.typed", "fonts/*.otf", "fonts/*.ttf", "fonts/OFL.txt", "fonts/NOTICE"]
54
+
55
+ [tool.ruff]
56
+ line-length = 120
57
+ target-version = "py38"
58
+
59
+ [tool.ruff.lint]
60
+ select = ["E", "W", "F", "I", "B", "C4", "UP", "SIM"]
61
+ # E501 由 formatter 处理;B008 是 typer/fastapi 将 Option 作为默认值的框架惯用法。
62
+ ignore = ["E501", "B008"]
63
+
64
+ [tool.mypy]
65
+ python_version = "3.8"
66
+ strict = true
67
+ # ezdxf 未声明 __all__,关闭隐式再导出检查以避免误报(运行时正确)。
68
+ implicit_reexport = true
69
+
70
+ [[tool.mypy.overrides]]
71
+ module = "tests.*"
72
+ disallow_untyped_defs = false
73
+
74
+ [tool.pytest.ini_options]
75
+ markers = [
76
+ "integration: 需要真实 DWG 与 ODA File Converter 的集成测试",
77
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,34 @@
1
+ """cad2image — DWG/DXF → PNG/SVG 渲染管线。
2
+
3
+ 用 ODA File Converter(DWG→DXF)+ ezdxf(DXF→PNG/SVG)重建 Acme CAD Converter
4
+ 的渲染能力,消除 GDI 栅格化路径产生的「残余杂线」问题。
5
+
6
+ 公开接口:
7
+ - convert_dwg_to_dxf / convert_directory:DWG → DXF(ODA File Converter 封装)
8
+ - render_dxf / render_to_png / render_to_svg:DXF → PNG/SVG(ezdxf 渲染核心)
9
+ - process_dwg / process_directory:单文件 / 目录批处理
10
+ - RenderOptions:渲染参数
11
+ """
12
+
13
+ from cad2image.batch import BatchResult, process_directory, process_dwg
14
+ from cad2image.config import RenderOptions, get_oda_converter_path
15
+ from cad2image.dwg2dxf import convert_directory, convert_dwg_to_dxf
16
+ from cad2image.plotstyle import get_lineweight, load_ctb
17
+ from cad2image.render import render_dxf, render_to_png, render_to_svg
18
+
19
+ __all__ = [
20
+ "BatchResult",
21
+ "RenderOptions",
22
+ "convert_directory",
23
+ "convert_dwg_to_dxf",
24
+ "get_lineweight",
25
+ "get_oda_converter_path",
26
+ "load_ctb",
27
+ "process_directory",
28
+ "process_dwg",
29
+ "render_dxf",
30
+ "render_to_png",
31
+ "render_to_svg",
32
+ ]
33
+
34
+ __version__ = "0.1.0"
@@ -0,0 +1,6 @@
1
+ """支持 ``python -m cad2image`` 直接调用 CLI。"""
2
+
3
+ from cad2image.cli import app
4
+
5
+ if __name__ == "__main__":
6
+ app()