初始化

This commit is contained in:
2026-04-22 12:27:49 +08:00
commit 4857cb6e45
73 changed files with 20927 additions and 0 deletions

310
tools/core/export_layout.py Normal file
View File

@@ -0,0 +1,310 @@
#!/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())