Files
ArcGis_Py/tools/core/export_layout.py
2026-04-22 12:27:49 +08:00

310 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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())