简介面向GIS制图人员和需处理卫片图斑的ArcGIS用户这份实操文档围绕按图斑批量出图展开重点解决大量图斑逐一手工导出效率低的问题。内容以ArcGIS 10及以上版本的数据驱动页面为核心梳理图层、名称字段、排序、显示范围与比例尺等配置要点并说明如何借助动态文本展示图斑编号、面积、类型等属性同时提供基于arcpy遍历页面、调用ExportToPNG批量输出的脚本思路可按需调整输出格式、尺寸和保存目录也便于扩展异常处理与个性化参数并兼顾不同比例尺、图斑属性完整性与输出质量等实际需求。包内共1个doc文件约29KB适合作为配置参考和脚本模板查阅。已有8322人学习能够帮助读者快速建立从布局组织到批量出图的完整操作框架。1. 图斑批量出图这件事难的不是「批量」是每张图都对得上号手上压着一层卫片图斑几百上千个多边形每一个都要单独出一张带图廓、带属性、带比例尺的 JPG交给外业核查、上报或者归档——手动一张张点点到最后手都麻了。Arcgis 批量出图 的老路子其实很成熟Data Driven Pages 负责按记录翻页一段 arcpy 脚本负责把每一页导出成图片十来行代码就能把整层图斑跑成一批图。但真正跑过的人都知道脚本能跑通只是起点真正的麻烦在于索引字段配错、比例尺单位不对、导出参数用默认值跑出来的图张张糊、张张偏。这篇写给手上有图斑层、需要成批出图的从业者环境怎么检查、参数怎么设、脚本怎么写、翻车了看哪里照着走一遍就能复现。2. 数据驱动页面六项配置决定成图对不对得上号Data Driven Pages下称 DDP是 ArcMap 里把「一份 mxd」变成「N 份版面」的机制。它不复制地图只复制页面的「视角」同一个数据框、同一套符号、同一套版面元素每一页把范围挪到一条索引记录上名称字段的值决定这一页叫什么。理解这一点很关键——出图结果的好坏八成取决于 DDP 那六个配置项填得对不对脚本只是把你手动翻页的动作录下来重放一遍。所以别急着打开编辑器写代码先把这几项逐个捋清楚。2.1 版本、坐标系与索引图层的前置检查版本是第一道门槛。DDP 从 ArcGIS 10 才开始有9.x 里根本没有这个工具条找半天找不到不是操作问题。10.2 是这套流程里最稳的版本Python 环境是 2.7arcpy.mapping 模块齐全ArcGIS Pro 换了名字叫 Map Series思路一样但接口换成了 arcpy.mp老的 mxd 脚本在 Pro 里一行都跑不了这一点要提前想清楚别写完发现环境不对。坐标系这件事更隐蔽。DDP 的「最佳适合」范围模式是按索引要素的外接矩形算的如果数据框和图层坐标系不一致、或者数据本身没投影算出来的范围会莫名其妙地大一圈或者小一圈出来的图要么图斑缩成一个小点要么直接跑到图框外面。我一般会在出图前把数据框坐标系、图层坐标系、索引要素类坐标系统一成同一个投影坐标系而不是地理坐标系——地理坐标系下「一度」和「一米」混着算比例尺字段完全没法用。下面这张表是我自己出图前必过一遍的检查清单逐项打勾能省掉后面八成的返工。检查项合格标准不合格的后果ArcGIS 版本10.0 及以上建议 10.29.x 无 DDP工具条根本不存在索引图层与图斑一一对应的面要素类一个面套多个图斑出图张数对不上坐标系索引层与数据框同为投影坐标系比例尺失真、范围偏移名称字段文本型、非空、全局唯一文件重名覆盖、报错中断排序字段数值或文本可空页码顺序乱、抽查对不上号数据框裁剪关闭 Clip to Shape 或按需开启图斑被裁掉一半索引图层不一定是图斑层本身。图斑数量少、形状规整的时候直接拿图斑层当索引最省事但图斑数量上千、形状长条形的时候我一般会先用制图工具生成一层规则的分幅格网当索引再让每个图斑落到对应的格网里出一张图覆盖一片张数从一千降到一百跑图时间和人工翻阅成本都下来了。选哪种取决于交付方要的是「一斑一图」还是「一景一图」。2.2 名称字段与排序字段批量出图的「主键」名称字段是整套流程的主键它同时承担三个职责页面的显示名、动态文本的来源、导出文件名的来源。选错字段后面所有环节都会跟着错。三条硬性要求必须是文本型或者能被安全转成文本、不能有重复值、不能包含 Windows 文件名里的非法字符\ / : * ? |。最常见的翻车是名称字段里带斜杠。图斑编号习惯写成「某区域-2024-001」这种还能忍一旦写成「区/片/001」脚本跑到这一页直接抛 IOError前面跑了几百张全白跑。我一般会在属性表里新建一个 TEXT 字段用字段计算器拼一个干净的名字顺手把中文的括号、空格也换掉虽然麻烦五分钟但能省掉后面重跑两小时。# 在 ArcMap 字段计算器里Python 解析器为新建的 TEXT 字段赋值 # 逻辑把可能出现在文件名里的非法字符统一替换成下划线 def clean_name(v): s str(v).strip() for ch in \\/:*?|: s s.replace(ch, _) return s.replace( , ) clean_name(!图斑编号!)这段逻辑很短但它解决的是「一张图都出不来」和「出一半崩掉」的区别。替换成下划线而不是直接删掉是为了保留可读性——日后有人翻到某区域_2024_001.jpg还能一眼看出这是哪一条记录。空格也一并去掉是因为命令行和批处理脚本对含空格路径的处理经常出玄学问题。排序字段决定页面编号顺序。它不影响出图正确性但影响你事后核对。图斑数量上千的时候出完图总要抽检几张如果页码按图斑编号升序排翻到第 37 页就知道该查哪个图斑如果按 ObjectID 乱序抽检就变成了开盲盒。我习惯把排序字段设成和名称字段一致或者设成「片区编号 图斑编号」的组合字段让出的图和台账顺序对得上。2.3 范围与比例尺三种模式的取舍DDP 工具条上的 Extent 有三个选项很多人一路默认点下去结果出来的图有的图斑占满整页、有的缩在角落。这三个选项的差别本质是「每页缩放级别变不变」。Best Fit最佳适合最省事每页按索引要素的外接矩形自动缩放图斑永远撑满图框。缺点是比例尺每页都不一样几百张图排在一起同一个村的两块地图斑看起来大小差三倍交给不懂行的人看很容易被质疑「是不是画错了」。而且比例尺不统一面积对比、目视解译都没法做。Center and Maintain Scale居中并保持比例尺保持一个固定比例尺只挪中心点。图斑大小一致、观感统一代价是超大的图斑会被裁掉边角超小的图斑只占指甲盖那么大一块。这一般是我出正式成果图时用的模式比例尺统一这一点对交付太重要了。Data Driven Scale按字段设定比例尺是折中方案在索引层里建一个比例尺字段按图斑面积分档赋值——面积大的给 1:10000中等的 1:5000小的 1:2000。这样既避免了大图斑被裁、小图斑太小又保持了「同一档内比例尺一致」。分档规则我一般按面积的分位数来切而不是拍脑袋定阈值具体数值要看项目区的地物密度城市周边密、山区疏同一个比例尺在两个地方的效果能差出一倍。比例尺字段的单位有个坑ArcMap 认的是比例尺分母填 5000 就代表 1:5000不是 0.0005也不是「五米」。填错了出来的图会离谱到无法直视而且不会报错只能靠肉眼发现——这是典型的黑匣子型错误第一次踩的时候我盯着屏幕愣了半分钟。2.4 动态文本把属性写进版面而不是事后 PSDDP 最有价值的副产物是动态文本。Insert 菜单下的 Dynamic Text 里有一组 Data Driven Page Attribute 条目插到版面上之后每一页会自动显示当前页对应记录的字段值。图斑编号、所在片区、面积、地类、核查状态想显示什么就选什么字段不需要出图后再一张张 P 图加字。实际操作里要注意两件事。第一动态文本只在 DDP 启用且版面处于 Layout 视图时才会随页刷新在 Data 视图里看到的永远是第一页的值别以为配错了。第二文本的长度不受控——某个字段的值特别长会顶破文本框压到图例或者指北针上。稳妥的做法是给文本框设一个固定宽度并开启自动换行同时在索引层里把要显示的字段做一次截断比如面积统一保留两位小数、备注类字段截到 20 个字。动态文本还支持页码Page Number和页数Page Count「第 3 页 / 共 217 页」这种信息放到图廓角上收图的人一眼就知道有没有缺页。这个小细节在批量交付里特别有用缺页、错页一眼就能看出来比事后一张张数快得多。3. arcpy 脚本流水线从 mxd 到成批 JPG 的十几个参数DDP 配好之后手动翻页也能出图但那是体力活。真正的自动化靠 arcpy.mapping 里的两个对象MapDocument 和它的 dataDrivenPages 属性。思路简单到粗暴——把 mxd 读进来拿到总页数写一个循环逐页设置当前页码取当前页名称调导出函数存盘。这一段代码网上一搜一大把但绝大多数版本都带着同一个不易察觉的缺陷而且导出参数几乎全是默认值跑出来的东西能不能用全看运气。3.1 一段能跑但会漏页的脚本错在哪原始范例脚本大致长这样很多转载版本一字不改地沿用了它# coding:utf-8 import arcpy mxd arcpy.mapping.MapDocument(rD:\gis_work\block\block_index.mxd) out_dir rD:\gis_work\block\out_jpg\\ # 问题一range 的上界写成了 pageCount最后一页永远出不来 for pageNum in range(1, mxd.dataDrivenPages.pageCount): mxd.dataDrivenPages.currentPageID pageNum mapName mxd.dataDrivenPages.pageRow.getValue(mxd.dataDrivenPages.pageNameField.name) print mapName arcpy.mapping.ExportToPNG(mxd, out_dir mapName .png) print ok这段代码能跑也能出图但它至少有三处需要动刀。第一处最致命currentPageID从 1 开始编号而range(1, n)生成的是 1 到 n-1最后一页永远被跳过。图斑 200 个出来 199 张而且不报错、不提示只有你拿台账一条条比对才会发现少了一张。这种静默失败是最难查的一类我当年是交了图被退回来才发现漏的。第二处out_dir mapName这种字符串拼接在 Python 2.7 下遇到中文会直接抛 UnicodeDecodeError因为 mapName 通常是 unicode 对象和 str 类型的路径拼在一起会触发隐式 ASCII 解码。第三处输出目录不存在时ExportToPNG 不会自动创建目录直接报 IOError而且是从第一页就失败看起来像是脚本根本跑不起来。改完之后的最小可用版本如下四行关键改动我都标了注释# coding:utf-8 import arcpy import os mxd_path rD:\gis_work\block\block_index.mxd out_dir rD:\gis_work\block\out_jpg # 输出目录不存在就先建别指望导出函数帮你建 if not os.path.isdir(out_dir): os.makedirs(out_dir) mxd arcpy.mapping.MapDocument(mxd_path) ddp mxd.dataDrivenPages # 改动一上界 1把最后一页捞回来 for page_id in range(1, ddp.pageCount 1): ddp.currentPageID page_id # 改动二统一成 unicode避免中文名拼接报错 name u%s % ddp.pageRow.getValue(ddp.pageNameField.name) out_file os.path.join(out_dir, name u.jpg) # 改动三显式给出像素尺寸和 dpi别用默认的 640x480 arcpy.mapping.ExportToJPG( mxd, out_file, df_export_width3508, df_export_height2480, resolution300, jpeg_quality90 ) print(udone: %s % name) del mxd print all ok逻辑上没什么玄机就是「设页码 → 取名字 → 存盘」三步循环。真正决定成品质量的是那几个参数下一节单独拆。3.2 ExportToJPG 的参数表默认值基本不能用arcpy.mapping.ExportToJPG有九个参数实际动手时只需要关心其中五个。默认的df_export_width640、df_export_height480、resolution96跑出来的图拿到手机上看都嫌糊更别说打印。这几个默认值不改后面所有努力都白费。参数默认值建议值说明df_export_width6403508输出像素宽A4 横向 300dpi 对应 3508df_export_height4802480输出像素高A4 横向 300dpi 对应 2480resolution96300写入图片的 DPI 元数据影响符号渲染精细度jpeg_quality7085951100超过 95 体积涨得快、肉眼无差别world_fileFalse视需求置 True 时同时输出 jgw 坐标文件color_mode24-BIT_COLOR24-BIT_COLOR8 位调色板体积小但渐变会断层像素尺寸和 dpi 要成对给只改一个会出问题。只把resolution提到 300 而不动宽高输出还是 640×480 像素只是元数据里写着 300dpi打印出来跟邮票一样大。只改宽高不改 dpi图片像素够了但符号渲染的线宽、注记大小是按 96dpi 算的放大后线条细得像头发丝。页面尺寸和像素的换算关系值得记一下A4 横向是 297mm × 210mm300dpi 下就是297/25.4*300 ≈ 3508、210/25.4*300 ≈ 2480。A3 翻倍就是 4961×3508。图斑特别小的项目、要放大看图斑边界的可以用 400dpi 甚至 600dpi代价是单张图从 2MB 涨到 8MB几百张就是几个 G硬盘和传输都得提前算。world_file这个参数容易被忽略但它在需要把出图结果再叠回 GIS 里比对时很关键。置 True 之后每张 jpg 旁边会多一个同名 jgw 文件里面记着这张图的左上角坐标和像元大小拖进 QGIS 或者 ArcMap 就能自动定位。做核查比对、做变化检测的时候有它没它完全是两种体验。代价是文件数翻倍目录会显得很乱所以要不要开取决于交付形态。3.3 文件名、编码与目录三个不报错但会让你白跑的地方文件名这块的坑我在 2.2 已经提过一半这里补另一半编码。ArcGIS 10.x 配的是 Python 2.7字符串分str和unicode两种pageRow.getValue()返回的通常是 unicode路径常量是 str两者相加会触发隐式 ASCII 解码。如果名称字段里只有英文数字这个问题永远不出现一旦有中文报错信息还是一句含糊的UnicodeDecodeError: ascii codec cant decode看得人一头雾水。稳妥写法是全程用 unicode路径常量前面加u拼接用u%s % value显式转换os.path.join处理分隔符。代码里不要出现str()强转 unicode 的写法那在 Python 2.7 里就是定时炸弹。如果脚本必须在命令行里跑控制台编码也要对print中文可能抛异常加一句# -*- coding: utf-8 -*-并不解决控制台问题直接把日志写成文件更省心。目录这块导出函数不会帮你建目录也不会帮你清理旧文件。重跑的时候如果不清空新旧文件混在一起你根本分不清哪张是这次跑的。我一般会在脚本开头做一次判断目录存在且非空就加个时间戳后缀另建一个目录或者干脆先手动清空。宁可多占点硬盘也别让两批图混在一个文件夹里——这个后悔药没有。3.4 断点续跑与失败日志几百张图的中途崩溃怎么接跑一百张图可能顺顺利利跑到第五百张的时候因为某个图斑的几何异常、某个字段为空整条流水线中断前面跑的全在那儿后面的一动不动。重跑一次又要半小时。解决办法很简单跳过已存在的文件单页失败不中断把失败记录写进日志。# coding:utf-8 import arcpy import os import codecs mxd_path rD:\gis_work\block\block_index.mxd out_dir rD:\gis_work\block\out_jpg log_path rD:\gis_work\block\export_log.txt if not os.path.isdir(out_dir): os.makedirs(out_dir) mxd arcpy.mapping.MapDocument(mxd_path) ddp mxd.dataDrivenPages log codecs.open(log_path, a, utf-8) ok_count 0 skip_count 0 fail_list [] for page_id in range(1, ddp.pageCount 1): ddp.currentPageID page_id name u%s % ddp.pageRow.getValue(ddp.pageNameField.name) out_file os.path.join(out_dir, name u.jpg) # 断点续跑已经出过的直接跳过重跑时只补缺的 if os.path.exists(out_file): skip_count 1 continue try: arcpy.mapping.ExportToJPG( mxd, out_file, df_export_width3508, df_export_height2480, resolution300, jpeg_quality90 ) ok_count 1 log.write(uOK\t%d\t%s\n % (page_id, name)) except Exception as e: # 单页失败不影响后续把页码和原因记下来事后单独处理 fail_list.append((page_id, name)) log.write(uFAIL\t%d\t%s\t%s\n % (page_id, name, e)) log.write(u---- ok:%d skip:%d fail:%d ----\n % (ok_count, skip_count, len(fail_list))) log.close() del mxd print ok:%d skip:%d fail:%d % (ok_count, skip_count, len(fail_list)) for pid, nm in fail_list: print fail page %d: %s % (pid, nm)这段脚本的关键变化有三处。os.path.exists让重跑变成增量补图第一次跑完 480 张、失败 20 张第二次跑只处理那 20 张几秒钟收工。try/except把失败隔离在单页里一个图斑的几何问题不会拖垮整批。日志文件用追加模式写每行一个 tab 分隔的状态记录Excel 直接打开就能筛选。失败清单比成功计数更有价值。常见失败原因集中在三类名称字段为空导致文件名为.jpg、名称字段含非法字符、索引要素几何为空或自相交。前两类在出图前用字段计算器和属性查询就能清掉第三类得回到源数据做几何修复。跑完先看日志里的 FAIL 行比对着目录数文件快得多。4. 版面一致性定义查询、比例尺和图层在批量出图里的处理脚本跑通只是把「能不能出」解决了「出的图能不能用」是另一回事。批量出图最容易挨批的地方不是图斑位置错而是每一页的观感不一致——有的页图例挡住了图斑有的页比例尺文字压出框外有的页所有图斑都亮着、分不清哪个是主角。这些问题在单张图里手调两下就解决了批量出图必须靠版面层面的规则一次性约束住。4.1 页面定义查询每页只留当前图斑别让邻居抢戏默认情况下DDP 只是挪动视野图层里所有图斑都还画着。出来的图上当前图斑和周围几十个图斑一个颜色谁是谁全靠猜。这个问题的标准解法叫 Page Definition页面定义查询入口在图层的 Definition Query 选项卡里勾上「Page Definition」并指定索引图层和字段之后每一页只显示字段值等于当前页名称的那一条记录。配置的时候要注意字段匹配。页面定义查询用的字段值必须和 DDP 的名称字段值严格一致——大小写、空格、前后缀都算。我见过名称字段里是「001」而图斑属性里是「图斑001」的情况勾上之后每一页都是空白看着像是数据丢了其实是一条都没匹配上。更实用的做法是分两层底层放完整的图斑层用灰色细线渲染作为背景参考上层放同一个图层的副本开页面定义查询、用醒目的填充色渲染只显示当前图斑。这样出来的图既有上下文能看出这块图斑在整片区域里的位置又有明确主体当前图斑一眼可辨。两层用同一个数据源不会出现数据不同步的问题。还有一点容易忽略页面定义查询只影响显示不影响导出范围。范围还是由 DDP 的 Extent 设置决定两者是独立的。有时候图斑跑出图框不是范围设错了而是图层被裁剪Clip to Shape了两个设置混在一起排查会绕很久。4.2 比例尺、页面尺寸与 dpi 的换算关系这三个量是绑在一起的改一个另外两个必须跟着动。常见的出错方式是版面按 A4 设计导出时按 A3 的像素出结果图框只占了画面左上角四分之一右边一大片白。或者反过来版面按 A3 设计导出按 A4 像素出图框被截断图例直接消失。换算关系不复杂页面物理尺寸英寸× dpi 输出像素。A4 横向 11.69 英寸 × 300dpi ≈ 3508 像素A3 横向 16.54 英寸 × 300dpi ≈ 4961 像素。脚本里的df_export_width/df_export_height必须和 mxd 里设置的页面尺寸对应否则就是上面说的错位。比例尺和页面尺寸也有联动。同样一张 A4比例尺 1:10000 时图框覆盖约 2.9km × 2.1km1:2000 时只覆盖 590m × 420m。图斑平均尺寸决定了该用哪个比例尺——不是越大越好比例尺放大一倍图斑在图上的面积翻四倍稍大一点的图斑就会被裁掉。我一般会先拿几个面积最大和最小的图斑试跑看它们在版面上占的比例是否合适再定最终参数。提示试跑阶段把 dpi 调低比如 150出图速度快十倍只看版面布局够用了定稿时再改回 300 全量跑。4.3 图例、指北针与动态文本的版面收口版面元素在批量模式下最容易被挤爆的是图例。图例按图层生成条目图层里有几个分类符号就列几行图层多了图例能长到页面外面去。解决办法是给图例设固定列数、限制显示的图层数量或者直接改成「只显示当前图斑类别」——用页面定义查询过滤后的图层做图例源每页图例只列一行干净利落。指北针和比例尺条要贴着图框放并且锁定位置。ArcMap 里选中元素后右键「Properties」里有位置和大小的精确输入框比鼠标拖准得多。批量出图时版面元素的位置是全局的只设一次就够但它们相对图框的位置不会自动跟随图框尺寸变化所以图框大小一改所有元素都得重新对一遍。动态文本的收口前面提过这里补一个实操细节动态文本的字号不要用固定值用相对页面尺寸的磅值并且给长文本字段预留两行高度。字段值短的时候下面空一行不显眼值长的时候自动换行也不会压到别的元素上。这个细节在几百张图的批量交付里特别值——只要有五张图文字溢出整套就得重出。4.4 把 mxd 做成模板换数据不换版面同一套版面在一个项目里能用几十次。我的习惯是把配置好的 mxd 另存一份当模板里面的图层名、数据框名、动态文本字段名全部固定下来后续新项目只需要把新数据按同样的图层名挂进去脚本一行不改就能跑。这个习惯省下来的时间比优化脚本本身多得多。模板化的前提是命名规范。图层名用英文、不带空格、不带中文数据框统一叫Main之类。脚本里如果要引用数据框arcpy.mapping.ListDataFrames(mxd)[0]这种按索引取的方式在单数据框版面里没问题但模板一旦被人加了附图框顺序一变就全乱按名字取更稳。模板还要配一份参数清单贴在文件旁边写清楚这套版面适用的比例尺范围、页面尺寸、导出像素、名称字段规范。半年后自己回头看或者交接给别人的时候这份清单比任何注释都管用。5. 批量出图避坑与排查五类翻车现场的现象、原因和解决上面几章讲的是「怎么让它跑起来」这一章讲「跑歪了怎么找回来」。下面这五类问题是我这些年实际遇到频率最高的每一条都按现象、原因、解决三段写对着排查基本能覆盖九成的故障。剩下那一成八成是数据本身的问题回到源数据看几何和属性比在脚本里debug快。5.1 跑完发现少了一张图现象图斑 200 个输出目录里 199 张缺的那张往往正好是最后一页而且脚本没有任何报错日志显示全部成功。原因循环边界写错。currentPageID的取值是 1 到pageCount闭区间而range(1, pageCount)生成的是 1 到pageCount-1。这是从教程里照抄下来的最常见错误因为原始范例本身就有这个问题转载的人也没改。解决把循环改成range(1, ddp.pageCount 1)。同时建议在脚本末尾加一句校验assert len(os.listdir(out_dir)) ddp.pageCount让漏页在跑完的瞬间就暴露而不是等交图后被退回来。如果导出的是 PNG 且开了 world_file文件数要按两倍算别被自己的 assert 误伤。5.2 每张图长得一模一样现象跑了几百张图打开一看全是同一块图斑或者全是最开始那一页的范围。原因三种可能。一是循环里根本没设currentPageID导出函数每次都按默认的第一页出二是currentPageID设了但没生效常见于 mxd 里 DDP 处于未启用状态pageCount返回 1三是 mxd 里存在多个数据框导出函数默认只处理第一个而 DDP 驱动的不是它。解决先打印ddp.pageCount看是不是等于图斑数不等于就说明 DDP 没启用或索引图层没设对回到工具条重新配。等于的话检查导出函数有没有指定数据框多数据框版面要显式传data_frame参数或者用arcpy.mapping.ListDataFrames(mxd)按名字取。设完currentPageID之后加一句ddp.refresh()某些版本下不刷新会导致视野不更新。5.3 图斑偏出图框或者被裁掉一半现象单张图看没问题批量跑出来有几十张图斑压在边框上一部分跑到图框外面看不见了。原因Extent 用了 Center and Maintain Scale 但比例尺定得太小大图斑放不下或者用了 Best Fit 但边距百分比设成了 0图斑外接矩形正好贴边符号和标注全被裁掉还有一种情况是数据框开了 Clip to Shape按某个不规则范围做了裁剪图斑自然被切。解决Center and Maintain Scale 模式下按最大图斑的外接矩形反算所需比例尺宁可整体缩小一档。Best Fit 模式下把边距设到 5%10%给标注和符号留出余量。逐个排查数据框的 Clip Options非必要不开。改完之后挑面积最大的三个图斑单独试跑看着没问题再全量跑别拿几百张图试错。5.4 跑到一半崩掉报 IOError 或 UnicodeDecodeError现象前几十张正常某一张开始报错中断报错信息全是英文且指向不明。原因名称字段里含有\ / : * ? |之一或者含中文而脚本用了 str 拼接。另一种情况是输出的图片正被看图软件打开占用Windows 下会直接拒绝写入。解决出图前用字段计算器清洗名称字段非法字符统一替换。脚本里全程用 unicode路径常量前加u。跑图前关掉所有图片查看器或者把输出目录换一个新的。批量跑之前先跑一遍「只导出不写文件」的干跑把每个名称打印出来肉眼扫一眼有没有明显异常的名字几十秒的事。5.5 跑得慢到怀疑人生现象一张图导出要五六秒几百张跑一两个小时中途还容易卡死。原因dpi 和像素尺寸设得太高600dpi 的 A3、版面里有大量栅格底图或者复杂符号、图层数太多每页都要重绘、脚本里每次都重新打开 mxd。还有一种隐蔽的原因是索引要素的几何复杂度太高节点数上万的图斑每页重算外接矩形都慢。解决试跑用 150dpi定稿再上 300。把不参与出图的图层关掉不是删掉尤其是影像底图这类栅格能省掉一大半渲染时间。mxd 只在循环外打开一次循环内只切页。几何特别复杂的图斑先用简化工具处理一遍。如果这些做完还是慢考虑按片区分批跑几个进程并行比单进程硬扛快得多。6. 进阶先造索引再出图出完图把质检也交给脚本图斑层直接当索引是最省事的路径但真正让这套流程变得可复用的是把它拆成「造索引」和「出图」两段。造索引指的是不拿图斑本身当索引而是按行政区、按分幅格网、按核查批次生成一层规则的面每个面覆盖若干个图斑出图时一个面出一张。这样张数可控比例尺可控后续补图也容易——某个片区要重出只跑那个片区的页码就行。用 arcpy 造分幅索引不复杂制图工具箱里的GridIndexFeatures就够用按范围、行列数或者要素宽度生成规则格网生成后加一个名称字段拼上片区编号直接就能当 DDP 的索引层。我一般会在格网里再算两个字段覆盖的图斑数量和总面积出图前先看一眼分布格网切得不均匀就调参数重来比出完图再发现某张图上挤了三十个图斑强。出完图的质检同样可以脚本化。批量出图最怕的不是出不来是出来了但内容是白的、或者糊的、或者根本没加载图层。用脚本扫一遍输出目录读每张图的文件大小和像素尺寸明显偏离中位数的挑出来单独看# coding:utf-8 # 出图后的批量抽检按文件大小找异常白图通常远小于中位数 import os from PIL import Image out_dir rD:\gis_work\block\out_jpg sizes [] for fn in os.listdir(out_dir): if not fn.lower().endswith(.jpg): continue p os.path.join(out_dir, fn) sizes.append((fn, os.path.getsize(p))) if sizes: sizes.sort(keylambda x: x[1]) median sizes[len(sizes) // 2][1] # 小于中位数 30% 的多半是白图或图层没加载 for fn, sz in sizes: if sz median * 0.3: print suspect: %s %d bytes % (fn, sz)这段代码不需要看懂图像内容靠文件体积的分布就能筛出问题图。一张正常加载了图斑、注记和图例的 A4 300dpi JPG 通常在两三兆纯白图只有一两百 K差一个数量级一眼就能筛出来。筛出来的文件名再回到日志里对页码定位到具体图斑查数据。需要看像素尺寸的话把 PIL 那段接上Image.open(p).size和预期值对不上就说明导出参数被改过。从那以后我每次跑批量出图都强制走一遍「先干跑打印名称、再小样本试出三张、最后全量加断点续跑」这三步哪怕图斑只有二十个也不例外。省下的不是跑图时间是返工时间。希望帮到你。本文还有配套的精品资源点击获取