import ezdxf import sys from ezdxf.addons.drawing import RenderContext, Frontend from ezdxf.addons.drawing.matplotlib import MatplotlibBackend from ezdxf.addons.drawing.properties import Configuration from ezdxf import bbox # 导入边界框计算模块 import matplotlib.pyplot as plt import os import json # 导入JSON模块 import argparse # 导入命令行参数处理模块 # --- 配置 --- # 将脚本的父目录(项目根目录)添加到Python路径中 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) PROJECT_ROOT = os.path.dirname(SCRIPT_DIR) sys.path.append(PROJECT_ROOT) # 指定字体目录 FONT_DIR = r"C:\Users\83500\久翌\CAD编辑同步excel\测试文件区\03_Python_OpenSource_DXF\fonts" def main(): """ 主函数,用于解析命令行参数并调用核心处理函数。 """ # --- 1. 设置命令行参数解析 --- parser = argparse.ArgumentParser( description="将 DXF 文件导出为 PDF, PNG, 并提取其坐标保存为 JSON。", formatter_class=argparse.RawTextHelpFormatter # 保持帮助文本的格式 ) parser.add_argument( "input_dxf_path", type=str, help="要处理的源 DXF 文件的完整路径。" ) # 设置默认输出目录 default_output_dir = os.path.join(PROJECT_ROOT, "04_Test_Files", "结果") parser.add_argument( "--output_dir", type=str, default=default_output_dir, help="指定输出文件(PDF, PNG, JSON)的保存目录。\n" f"如果未提供,将默认使用:\n{default_output_dir}" ) parser.add_argument( '--crop', nargs=4, type=float, metavar=('X1', 'Y1', 'X2', 'Y2'), help="提供一个矩形区域的两个对角点坐标 (X1 Y1 X2 Y2) 来裁剪输出的图像。" ) args = parser.parse_args() # --- 2. 确保输出目录存在 --- os.makedirs(args.output_dir, exist_ok=True) # --- 3. 调用核心功能 --- export_dxf_with_coords(args.input_dxf_path, args.output_dir, crop_coords=args.crop) def export_dxf_with_coords(input_path, output_dir, crop_coords=None): """ 将指定的 DXF 文件中的 "布局1" 渲染为 PDF 和 PNG,并将其边界坐标保存为 JSON 文件。 如果提供了 crop_coords,则会对输出的图像进行裁剪。 """ # --- 1. 检查输入文件是否存在 --- if not os.path.exists(input_path): print(f"错误: 输入的 DXF 文件未找到: '{input_path}'") return # --- 2. 设置输出文件名 --- base_name = os.path.splitext(os.path.basename(input_path))[0] json_path = os.path.join(output_dir, f"{base_name}_coords.json") pdf_path = os.path.join(output_dir, f"{base_name}.pdf") png_path = os.path.join(output_dir, f"{base_name}.png") try: # --- 3. 加载并解析 DXF 文件 --- print(f"--- 正在加载 DXF 文件: {os.path.basename(input_path)} ---") doc = ezdxf.readfile(input_path) # --- 新增: 查找并使用 "布局1" --- layout_name = '布局1' try: layout = doc.layouts.get(layout_name) print(f"--- 已成功找到并切换到布局: '{layout_name}' ---") except KeyError: available_layouts = ", ".join(doc.layouts.names()) print(f"错误: 在 DXF 文件中找不到名为 '{layout_name}' 的布局。") print(f"该文件中可用的布局有: [{available_layouts}]") return # --- 4. 计算图纸边界并保存为 JSON (基于布局) --- print(f"--- 正在计算 '{layout_name}' 的边界坐标 ---") extents = bbox.extents(layout, fast=True) if not extents.has_data: print(f"警告: 布局 '{layout_name}' 中不包含任何实体,无法计算坐标。") # 即使没有坐标,也可能需要渲染一个空白页面,所以这里我们不直接返回 coords = {} else: coords = { "bottom_left": {"x": round(extents.extmin.x, 2), "y": round(extents.extmin.y, 2)}, "bottom_right": {"x": round(extents.extmax.x, 2), "y": round(extents.extmin.y, 2)}, "top_left": {"x": round(extents.extmin.x, 2), "y": round(extents.extmax.y, 2)}, "top_right": {"x": round(extents.extmax.x, 2), "y": round(extents.extmax.y, 2)}, } with open(json_path, 'w', encoding='utf-8') as f: json.dump(coords, f, ensure_ascii=False, indent=4) print(f"坐标已成功保存到: '{json_path}'") # --- 5. 配置渲染器(包括字体) --- # 鉴于当前环境存在无法解释的版本冲突问题, # 我们回退到使用全局 support_dirs 的方法,这种方法兼容性更强,可以绕过问题。 if FONT_DIR not in ezdxf.options.support_dirs: ezdxf.options.support_dirs.append(FONT_DIR) # 使用默认配置, 并添加解决方法来处理3D点实体 config = Configuration.defaults().with_changes( # 将点的大小设置为0,这会让渲染器将点绘制为单个像素, # 从而绕过在处理3D点(POINT)的复杂几何图形时可能出现的Z坐标问题。 pdsize=0, ) # --- 6. 渲染 DXF 内容 --- fig = plt.figure() ax = fig.add_axes([0, 0, 1, 1]) ctx = RenderContext(doc) out = MatplotlibBackend(ax) print("--- 开始渲染 DXF 内容 ---") Frontend(ctx, out, config=config).draw_layout(layout, finalize=True) # --- 新增: 应用裁剪区域 --- if crop_coords: x1, y1, x2, y2 = crop_coords min_x, max_x = min(x1, x2), max(x1, x2) min_y, max_y = min(y1, y2), max(y1, y2) print(f"--- 正在应用裁剪区域: X({min_x:.2f} - {max_x:.2f}), Y({min_y:.2f} - {max_y:.2f}) ---") ax.set_xlim(min_x, max_x) ax.set_ylim(min_y, max_y) # --- 7. 保存为 PDF --- print(f"--- 正在保存为 PDF: {os.path.basename(pdf_path)} ---") fig.savefig(pdf_path, dpi=300, bbox_inches='tight', pad_inches=0.1) print(f"PDF 文件已保存到: '{pdf_path}'") # --- 8. 保存为 PNG --- print(f"--- 正在保存为 PNG: {os.path.basename(png_path)} ---") fig.savefig(png_path, dpi=300, bbox_inches='tight', pad_inches=0.1) print(f"PNG 文件已保存到: '{png_path}'") plt.close(fig) print("\n操作成功完成!") except IOError: print(f"错误: 无法读取文件: '{input_path}'") except Exception as e: print(f"处理并转换 DXF 文件时发生未知错误: {e}") if __name__ == "__main__": main()