代码详解
代码主要包含:
Python部分2个文件,分别为:解析地图文档程序(导出文本、另存地图文档)、导出地图到图片的程序。
- FastParseMapDocument.py
# -*- coding:utf8 -*-
import os
import arcpy
import sys
reload(sys)
sys.setdefaultencoding('utf8')
def parse_map_doc(doc_dir, doc_name, work_issue_prefix):
"""
解析mxd文档,用途:
1.创建工作目录
2.复制一份文档,作为我们真正使用的(以防对原始文件造成修改或破坏)
3.遍历目录图层,将各要素居中显示并导出属性、另存mxd文档
:param doc_dir: 原始mxd文档所在目录
:param doc_name: 原始mxd文档名称
:param work_issue_prefix: 工作目录名称(不包含其上各层级目录)前缀
:return:无
"""
doc_path = os.path.join(doc_dir, doc_name)
map_doc = arcpy.mapping.MapDocument(doc_path)
work_dir = os.path.join(doc_dir, work_issue_prefix)
if os.path.exists(work_dir):
os.rmdir(work_dir)
os.makedirs(work_dir)
work_doc_name = work_issue_prefix + '_' + doc_name # 真正使用的mxd
work_doc_path = os.path.join(doc_dir, work_doc_name)
if os.path.exists(work_doc_path):
del work_doc_path
map_doc.saveACopy(work_doc_path)
del map_doc
work_map_doc = arcpy.mapping.MapDocument(work_doc_path)
data_frames = arcpy.mapping.ListDataFrames(work_map_doc)
layers = arcpy.mapping.ListLayers(work_map_doc, None, data_frames[0])
for layer in layers:
if layer.name != u'RT地产用地': # 目标图层名
continue
else:
with arcpy.da.SearchCursor(layer, ['FID', 'Shape@', u'文件名称', u'宗地号', u'停尝编号2', u'坐落土地面', u'项目名称', u'项目地址',
u'土地证_房']) as cursor:
for row in cursor:
print u'FID = {0}, 项目地址:{1}'.format(row[0], row[7])
feature_values = [doc_name.split('.')[0], row[2],
u'宗地号', row[3],
u'宗地代码', row[4],
u'宗地面积', row[5],
u'所在位置', row[6],
u'用地单位', row[7],
u'用地合同号', row[8]]
data_frames[0].panToExtent(row[1].extent) # 当前要素居中
feature_file_name = u'temp_feature_{0}.txt'.format(row[0]) # 保存到文本文件中
feature_file_path = os.path.join(work_dir, feature_file_name)
feature_file = open(feature_file_path, 'w')
for a_feature_value in feature_values:
feature_file.write(a_feature_value)
feature_file.writelines(u'\n')
feature_file.close()
a_work_file_name = 'temp_feature_' + str(row[0])
a_work_doc_path = os.path.join(work_dir, a_work_file_name + '.mxd')
work_map_doc.saveACopy(a_work_doc_path) # 另存为地图文档
- FastExportMapDocument.py
# -*- coding:utf8 -*-
import os
import arcpy
import sys
reload(sys)
sys.setdefaultencoding('utf8')
def export_map_doc(doc_dir, work_issue_prefix, resolution=512):
"""
导出地图文档到JPG图片
:param doc_dir: 原始mxd文档所在目录
:param work_issue_prefix: 工作目录名称(不包含其上各层级目录)前缀
:param resolution: 导出图片的分辨率
:return:无
"""
# doc_dir = u'D:\\A1_正在处理\\制图1116'
work_dir = os.path.join(doc_dir, work_issue_prefix)
print(u'工作目录: {0}'.format(work_dir))
mxd_files = list(
filter(lambda filename: os.path.splitext(filename)[1] == '.mxd',
os.listdir(work_dir))) # 遍历目录下的mxd文档
row_index = 0
for a_doc_file_path in mxd_files:
row_index += 1
print(u'{0}/{1} - 正在导出如下文件至图片: {2}'.format(row_index, len(mxd_files), a_doc_file_path))
a_doc_file_name = os.path.basename(a_doc_file_path).split('.')[0]
a_doc_full_path = os.path.join(work_dir, a_doc_file_path)
a_map_doc = arcpy.mapping.MapDocument(a_doc_full_path)
picture_element = arcpy.mapping.ListLayoutElements(a_map_doc, u'PICTURE_ELEMENT')[0]
a_source_image_full_path = os.path.join(work_dir, u'{0}.jpg'.format(a_doc_file_name)) # 替换表格图片
picture_element.sourceImage = a_source_image_full_path
arcpy.mapping.ExportToJPEG(a_map_doc, u'e_{0}.jpg'.format(a_doc_file_name), resolution=resolution)
print(u'{0}/{1} - 成功导出图片: {2}'.format(row_index, len(mxd_files), u'e_{0}.jpg'.format(a_doc_file_name)))
del a_map_doc
os.remove(a_doc_full_path) # 删除过程文件
del picture_element
os.remove(a_source_image_full_path) # 删除过程文件
print(u'导出完毕!将打开结果目录...')
cmd_param = u"explorer.exe \"%s\"" % work_dir
os.system(cmd_param.decode('utf-8').encode('gbk'))
C#部分1个文件,即:通过文本替换xlsx表格中的内容,动态导出为图片(含图片白边裁切)。
- Program.cs
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using Spire.Xls;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
namespace Text2Picture
{
class Program
{
static void Main(string[] args)
{
try
{
if (null == args || 2 > args.Length)
{
throw new Exception("参数有误!");
}
if (!Directory.Exists(args[0]))
{
Console.WriteLine(args[0]);
throw new Exception("请传入工作目录并确保路径合法!");
}
if (!File.Exists(args[1]))
{
Console.WriteLine(args[1]);
throw new Exception("请传入表格模板文件完整路径并确保路径合法!");
}
var sWorkDir = args[0];
var sTemplatePath = args[1];
using (var fsTemplate = File.OpenRead(sTemplatePath))
{
//采用NPOI组件替换xlsx文件的内容并另存
IWorkbook pWorkbook = new XSSFWorkbook(fsTemplate);
if (null == pWorkbook)
throw new Exception("Template File Does Not Exist");
var pWorkSheet = pWorkbook.GetSheetAt(0);
var lstFileInfo = new DirectoryInfo(sWorkDir).GetFiles("*.txt", SearchOption.TopDirectoryOnly);
foreach (var aFileInfo in lstFileInfo)
{
Console.WriteLine($"----->开始干活: {aFileInfo.Name}");
using (var sr = aFileInfo.OpenText())
{
var sLine = string.Empty;
var nLineIndex = 0;
var nRowIndex = 0;
var nColumnIndex = 0;
while (null != (sLine = sr.ReadLine()))
{
Console.WriteLine($"第{nLineIndex + 1}个(行号{nRowIndex},列号C{nColumnIndex}), 值: {sLine}");
nRowIndex = nLineIndex / 2;
nColumnIndex = nLineIndex % 2;
nLineIndex++;
var row = pWorkSheet.GetRow(nRowIndex);
if (nRowIndex == 3 && nColumnIndex == 1)
{
sLine += "m\x00B2";//平方米,其中目标用unicode编码表示
}
row.GetCell(nColumnIndex).SetCellValue(sLine);
}
sr.Close();
}
var sFilePathNoExt = Path.Combine(sWorkDir, aFileInfo.Name.Split('.')[0]);
var sNewFilePath = sFilePathNoExt + ".xlsx";
Console.WriteLine($"保存文件: {sNewFilePath}");
using (var sNewFileStream = new FileStream(sNewFilePath, FileMode.Create))
{
pWorkbook.Write(sNewFileStream);
sNewFileStream.Close();
}
//采用Spire.XLS组件将xlsx特定区域导出为图片
Workbook workbook = new Workbook();
workbook.LoadFromFile(sNewFilePath);
var worksheet = workbook.Worksheets[0];
worksheet.AllocatedRange["A1:B7"].AutoFitRows();
var image = worksheet.ToImage(0, 0, 7, 2);
var newImage = ClipImage(new Bitmap(image));
newImage.Save((sFilePathNoExt + ".jpg"));
Console.WriteLine($"导出图片: {sFilePathNoExt}.jpg");
File.Delete(aFileInfo.FullName);
File.Delete(sNewFilePath);
Console.WriteLine("完结撒花!<-----");
}
fsTemplate.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine("0");
}
}
/// <summary>
/// 裁剪图片
/// 使用默认导出的文件,上下左右各有约65像素的白边,
/// 导入到地图文档中时,会遮盖地图,影响布局,
/// 因此,在导出xlsx特定区域到图片文件前,先裁切白边
/// </summary>
/// <param name="bmp"></param>
/// <param name="nBorderSize"></param>
/// <returns></returns>
private static Image ClipImage(Bitmap bmp, int nBorderSize = 65)
{
Bitmap newBmp = null;
if (bmp.Height > 2 * nBorderSize && bmp.Width > 2 * nBorderSize)
{
newBmp = new Bitmap(bmp.Width - 2 * nBorderSize, bmp.Height - 2 * nBorderSize);
var g = Graphics.FromImage(newBmp);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.DrawImage(bmp,
new Rectangle(0, 0, bmp.Width - 2 * nBorderSize, bmp.Height - 2 * nBorderSize),
new Rectangle(nBorderSize, nBorderSize, bmp.Width - 2 * nBorderSize, bmp.Height - 2 * nBorderSize),
GraphicsUnit.Pixel);
g.Dispose();
}
return newBmp;
}
}
}
程序封装
采用一个Python文件,通过少量几行代码,实现对Python代码、C#编译的可执行文件的调用。
- Startup.py
# -*- coding:utf8 -*-
import os
import time
import sys
import arcpy
import FastParseMapDocument
import FastExportMapDocument
reload(sys)
sys.setdefaultencoding('utf8')
if __name__ == '__main__':
mxd_full_path = u'{0}'.format(sys.argv[1].decode('gbk').encode('utf-8'))
arcpy.AddMessage(u'输入的mxd文档路径为: {0}'.format(mxd_full_path))
doc_dir = os.path.dirname(mxd_full_path)
doc_name = os.path.basename(mxd_full_path)
work_issue_prefix = 'T' + time.strftime("%Y%m%d%H%M%S", time.localtime())
exe_bin_dir = os.path.join(os.path.abspath(os.curdir), u'bin')
# exe_bin_dir = u'D:\\A15_Test\\FastExportMxd\\bin'
template_xlsx_path = os.path.join(exe_bin_dir, u'data_template.xlsx')
bat_file_path = os.path.join(exe_bin_dir, u'temp.bat')
FastParseMapDocument.parse_map_doc(doc_dir, doc_name, work_issue_prefix)
cmd_param = u"%s \"%s\" \"%s\"" % (bat_file_path, os.path.join(doc_dir, work_issue_prefix), template_xlsx_path)
process_cmd = os.popen(cmd_param.decode('utf-8').encode('gbk'))
print process_cmd.read()
process_cmd.close()
FastExportMapDocument.export_map_doc(doc_dir, work_issue_prefix)
- temp.bat
set current_path=%~dp0
start %current_path%\Text2Picture.exe %1 %2