#!/usr/bin/env python # -*- coding: utf-8 -*- """ 导出布局脚本 此脚本可以独立运行,用于导出布局,不依赖于PyQt6线程 """ import os import sys import json import arcpy import argparse def log(message): """日志输出函数""" print(message) sys.stdout.flush() # 确保立即输出 def parse_arguments(): """解析命令行参数""" parser = argparse.ArgumentParser(description='导出布局') parser.add_argument('--mode', choices=['single', 'batch'], default='single', help='导出模式') parser.add_argument('--aprx_file_list', help='ArcGIS Pro工程文件路径') parser.add_argument('--input_aprx_folder', help='批量模式下的工程文件夹路径') parser.add_argument('--output_image_path', required=True, help='输出路径') parser.add_argument('--export_format', default='PDF', help='导出格式') parser.add_argument('--resolution', type=int, default=300, help='分辨率(DPI)') parser.add_argument('--use_multiprocessing', action='store_true', help='是否使用多进程') parser.add_argument('--process_count', type=int, default=2, help='进程数') parser.add_argument('--image_force_regenerate', help='输出文件名') args = parser.parse_args() # 处理图层列表参数(从JSON字符串转换为列表) try: # 尝试将字符串解析为JSON if args.aprx_file_list.startswith('[') and args.aprx_file_list.endswith(']'): args.aprx_file_list = json.loads(args.aprx_file_list) else: # 如果不是JSON格式,则假定是单个图层或逗号分隔的列表 if ',' in args.aprx_file_list: cleaned = args.aprx_file_list.strip("[]") args.aprx_file_list = [aprx_file_list.strip() for aprx_file_list in cleaned.split(',')] else: args.aprx_file_list = [args.aprx_file_list] except json.JSONDecodeError: args.aprx_file_list = [args.aprx_file_list] return args def get_file_extension(format_name): """根据格式名称获取文件扩展名""" format_dict = { "PDF": ".pdf", "PNG": ".png", "JPG": ".jpg", "JPEG": ".jpg", "TIFF": ".tif", "EPS": ".eps", "SVG": ".svg", "AI": ".ai" } return format_dict.get(format_name.upper(), ".pdf") def export_layout(params): """导出布局""" aprx = None try: # 获取参数 log(f"开始导出布局...") aprx_path = params['aprx_path'] output_folder = params['output_path'] export_format = params.get('export_format', 'PDF') resolution = params.get('resolution', 300) output_name = params.get('output_name', '') # 确保输出文件夹存在 if not os.path.exists(output_folder): os.makedirs(output_folder) # 打开地图文档 try: log(f"打开地图文档: {aprx_path}") aprx = arcpy.mp.ArcGISProject(aprx_path) # type: ignore except Exception as e: raise Exception(f"无法打开地图文档: {str(e)}") # 获取布局 layouts = aprx.listLayouts() if not layouts: raise Exception("地图文档中没有布局") # 如果未指定输出名称,则使用地图文档名称 if not output_name: output_name = os.path.splitext(os.path.basename(aprx_path))[0] # 获取文件扩展名 file_ext = get_file_extension(export_format) # 导出每个布局 exported_files = [] for layout in layouts: layout_name = layout.name output_file = os.path.join(output_folder, f"{output_name}{file_ext}") log(f"导出布局 {layout_name} 到 {output_file}") try: if export_format.upper() == "PDF": # 导出PDF layout.exportToPDF(output_file, resolution=resolution) elif export_format.upper() in ["PNG", "JPG", "JPEG", "TIFF"]: # 导出栅格图像 layout.exportToJPEG(output_file, resolution=resolution,jpeg_quality=85) if export_format.upper() in ["JPG", "JPEG"] else None layout.exportToPNG(output_file, resolution=resolution) if export_format.upper() == "PNG" else None layout.exportToTIFF(output_file, resolution=resolution) if export_format.upper() == "TIFF" else None elif export_format.upper() in ["EPS", "SVG"]: # 导出矢量图像 layout.exportToEPS(output_file, resolution=resolution) if export_format.upper() == "EPS" else None layout.exportToSVG(output_file, resolution=resolution) if export_format.upper() == "SVG" else None else: # 默认导出PDF layout.exportToPDF(output_file, resolution=resolution) exported_files.append(output_file) log(f"成功导出布局 {layout_name} 到 {output_file}") except Exception as e: log(f"导出布局 {layout_name} 失败: {str(e)}") return { 'exported_files': exported_files, 'count': len(exported_files) } except Exception as e: log(f"导出布局失败: {str(e)}") raise finally: # 释放资源 if aprx: del aprx arcpy.management.ClearWorkspaceCache() def batch_export_layout(params): """批量导出布局""" try: # 获取参数 log(f"开始批量导出布局...") aprx_files = params['aprx_files'] output_folder = params['output_path'] export_format = params.get('export_format', 'PDF') resolution = params.get('resolution', 300) # 确保输出文件夹存在 if not os.path.exists(output_folder): os.makedirs(output_folder) # 记录导出结果 all_exported_files = [] success_count = 0 failed_count = 0 # 逐个处理aprx文件 for aprx_path in aprx_files: try: file_name = os.path.splitext(os.path.basename(aprx_path))[0] log(f"\n处理文件: {file_name}") # 准备参数 export_params = { 'aprx_path': aprx_path, 'output_path': output_folder, 'export_format': export_format, 'resolution': resolution, 'output_name': file_name } # 调用导出布局函数 result = export_layout(export_params) all_exported_files.extend(result['exported_files']) success_count += result['count'] log(f"文件 {file_name} 处理完成") except Exception as e: log(f"处理文件 {os.path.basename(aprx_path)} 失败: {str(e)}") failed_count += 1 # 返回结果 log(f"\n批量导出完成") log(f"成功: {success_count} 个布局") log(f"失败: {failed_count} 个文件") return { 'exported_files': all_exported_files, 'count': success_count, 'success_count': success_count, 'failed_count': failed_count } except Exception as e: log(f"批量导出布局失败: {str(e)}") raise def export_worker(aprx_path, output_path, export_format, resolution): """子进程专用工作函数(保持最小化参数)""" try: # 每个子进程独立初始化ArcPy环境 import arcpy arcpy.env.overwriteOutput = True result = export_layout({ 'aprx_path': aprx_path, 'output_path': output_path, 'export_format': export_format, 'resolution': resolution }) return (True, aprx_path, result) except Exception as e: return (False, aprx_path, str(e)) def main(): """主函数""" try: args = parse_arguments() if len(args.aprx_file_list) == 1: aprx_file = args.aprx_file_list[0] if not os.path.exists(aprx_file): log(f"所选文件{aprx_file}不存在,请确认") return 1 # 准备参数 params = { 'aprx_path': aprx_file, 'output_path': args.output_image_path, 'export_format': args.export_format, 'resolution': args.resolution } # 调用导出函数 result = export_layout(params) log(f"导出完成,成功导出 {result['count']} 个布局") elif len(args.aprx_file_list) >1: if not args.input_aprx_folder: log("批量导出模式需要指定aprx_folder参数") return 1 # 查找所有aprx文件 aprx_files = [] valied_files = [] failed_files = [] for file in args.aprx_file_list: if not os.path.exists(file) and file.lower().endswith('.aprx'): failed_files.append(os.path.basename(file)) continue aprx_files.append(file) valied_files.append(os.path.basename(file)) if not aprx_files: log(f"在指定文件夹中未找到aprx文件: {args.input_aprx_folder}") return 1 log(f"找到 {len(valied_files)} 个有效aprx文件: {', '.join(valied_files)}\n") log(f"{len(failed_files)} 个无效文件: {', '.join(failed_files)}") if args.use_multiprocessing and args.process_count > 1 and len(aprx_files)>1: from multiprocessing import Pool tasks = [(aprx_file, args.output_image_path, args.export_format, args.resolution) for aprx_file in aprx_files] with Pool(min(int(args.process_count), len(tasks))) as p: results = p.starmap(export_worker, tasks) for success, aprx_path, result in results: if success: log(f"成功导出布局 {aprx_path} 到 {result['exported_files']}") # type: ignore else: log(f"导出布局 {aprx_path} 失败: {result}") return 0 else: # 准备参数 params = { 'aprx_files': aprx_files, 'output_path': args.output_image_path, 'export_format': args.export_format, 'resolution': args.resolution } # 调用批量导出函数 result = batch_export_layout(params) log(f"批量导出完成,成功导出 {result['count']} 个布局") return 0 else: log("请选择要处理的aprx文件") return 0 except Exception as e: log(f"导出失败: {str(e)}") return 1 if __name__ == "__main__": sys.exit(main())