DEVTOOLBOX / GUIDES 本篇

PDF 处理流程决策指南:页面操作、内容操作与不可逆点的先后

PDF 的坑集中在两处:把看起来一样的操作当成同一件事(裁剪与脱敏、压平与压缩、写页标签与盖章页码),以及在错误的顺序上动手。这篇给出每一步的判据和代价,说明哪些操作永久丢信息、哪些默认值会害人,并给出一条从定源到签名的操作顺序。

内容复核 10 分钟阅读

先分清两类 PDF:文本型与扫描型,决定了后面每一步

打开一份文件,第一个判断不是选哪个工具,而是它属于哪一类。文本型 PDF 的内容流里放的是文字绘制指令:在 BT 与 ET 之间用 Tj、TJ 输出字形,页字典的 Resources 里至少有一个可用字体,复制一段能得到字符,搜索能命中词。扫描型 PDF 每页只有一个铺满页面的图像 XObject,Resources 里没有 Font 项,文字只是像素。判据可以用一次抽取试出结果:取一页跑文本提取,得到可读文字就是文本型,得到空串或成片乱码就是扫描型。

扫描型一旦确认,后面每一步都要先付 OCR 的代价。OCR 会把像素猜成字符,数字与形近字符最容易错:0 与 O、l 与 1、5 与 S 是稳定的错误集中区。时间成本按页计,一份两百页的扫描件在普通机器上要跑十几分钟。体积成本同样明显:OCR 之后同一页既有图像又有文本层,文件比原扫描件更大,而正确率只由最初的渲染分辨率决定,后期任何处理都补不回来。

最容易踩空的是混合型:同一份文件前几页是数字排版,后几页是扫描件。按整份文件下结论,必有一半判断是错的,只能逐页抽样确认。另一个不可逆点藏在「转成小体积 PDF」这一步:为了让文件变小,工具常把页面按低 DPI 重新采样成新图像,原始扫描件的分辨率被永久替换,之后既做不出更清晰的 OCR,也回不到原始像素。判断动作只有一个:处理前先留原始文件。

判据文本型扫描型
每页内容文字绘制指令(BT / ET)整页图像 XObject
字体资源至少一个可嵌入字体无 Font 项
复制与搜索可选中、可命中词选不中或只能整页选中
提取结果可读文字空串或成片乱码
后续成本可直接处理先 OCR,再谈处理

五行判据里任意两行一致就能定性,提取测试是最省事的一行

页面操作与内容操作:各自重写了什么

页面操作改页面树,内容操作改内容流,这是两条互不重叠的路。删除、重排、旋转、复制、拆分、合并属于前者:工具改的是 /Pages 树里的 /Kids 顺序、页字典里的 /Rotate 值,或者把整段内容流原样搬到新文件;页面里的字符、图像、字体字节通常不动,文字还能选中,字体不会跑版。内容操作必须重写或追加:页码与水印是往内容流末尾追加绘制指令,压平是把注释与表单域外观并入内容流,转图片则放弃矢量只留像素。

判据是「要不要保住内容本身可编辑」。只是顺序或方向错了,用页面操作,代价接近零,能返工;要改的是页面里印什么,只能走内容操作,代价是内容流被改写,此后再没有原始指令序列可回退。

旋转是最典型的默认值陷阱。/Rotate 是页字典里的整数,只能取 0、90、180、270,默认 0,改回来就复原。但很多工具在「旋转并保存」时把旋转烤进内容:变换矩阵被乘进当前变换矩阵,页面尺寸与坐标系一起转,之后把 /Rotate 改回 0 只会得到横过来的版面。判断方法朴素:旋转后再提取一次文字,坐标或顺序变了就已烤进内容。

页面操作也有不可逆的一面。删页之后若只做增量保存,被删页的对象与资源仍留在文件里,因为增量更新只追加不覆盖,换个工具就可能找回内容。完整重写才真正删掉,但同时丢掉结构树、命名目标与表单域,无法只留其一。

操作类型改动的对象能否返工常见副作用
删页、重排页面树 /Kids 与顺序可能残留对象大纲与内部链接悬空
旋转(写 /Rotate)页字典一个整数可逆阅读器缓存时显示旧方向
旋转(烤进内容)内容流变换矩阵不可逆文字坐标与提取顺序改变
加页码、加水印追加内容流只能重做原内容仍在其下,可被剥离
压平注释外观并入内容流不可逆表单域与注释不再可交互

同名操作的两条实现路径:写入元数据与写进内容,后果完全不同

裁剪不是脱敏,压平不是压缩

裁剪只回答一个问题:这一页显示哪一块矩形。页字典里有几个盒子,MediaBox 是介质尺寸,CropBox 是显示区域,BleedBox、TrimBox、ArtBox 服务于印刷,而 CropBox 的默认值就是 MediaBox。改 CropBox 等于换一个视口:被裁掉的文字、图像、注释仍完整留在文件里,提取器能读出,把 CropBox 改回去就直接显示。所以「用裁剪盖住身份证号」不是脱敏,只是把敏感信息挪出视口。

真脱敏只有一条路:把字符从内容流里删掉。PDF 32000-1 在 12.5.6.23 定义了 redaction 注释,处理器应用时移除标记区域内的文字与图像,而不是盖一层黑矩形。画黑框是最常见的误用,打印出来一模一样,但复制粘贴、文本提取、改回视口都能读出原文。判断动作:脱敏后自己跑一次提取,还能搜到原字符串就是没成功。

压平与压缩是另一对同名不同事的操作。压平把注释、表单域、图层的外观固定进内容流,之后不再是可交互对象:签名域不能签,表单域不能填,复选框的勾只剩一个图形。它常被当成减小体积的手段,实际收益很小,体积由图像决定。压缩才是减体积:FlateDecode 用 RFC 1950 的 zlib 容器,底层是 RFC 1951 的 deflate 数据格式,与 RFC 1952 的 gzip 是不同容器。

图像压缩的代价要单独算。把无损图转成 JPEG 有损,文字边缘出现振铃与块状伪影;扫描正文在 200 DPI 以下用 JPEG 质量 75 重压,笔画粘连,OCR 错误率明显上升。顺序上还有两处雷:先压平再改,改不动;先裁剪再脱敏,会误以为已经脱敏。

目的正确做法常见误用结果
遮蔽敏感内容redaction:删除区域内字符画黑框或改 CropBox字符仍在,可被提取
只调整显示范围改 CropBox当成删除操作内容完整保留
固定表单与注释压平进内容流当作压缩手段体积几乎不变,交互消失
减小体积FlateDecode、降采样、重编码一律转 JPEG有损,文字边缘出伪影

四个目的一一对应四种做法,混用是这一节全部的误用来源

合并与拆分:书签、表单与页标签会丢什么

一次合并要处理五类结构:大纲、页标签、表单域、命名目标与内部链接、数字签名。它们归属不同,丢失方式也不同。大纲是文档级的树,节点用 /Dest 或动作指向具体页面对象;合并时按文档逐棵树拼接,但指向被删页面的条目会变成悬空目标,点了没反应也不报错。

页标签回答「第 1 页为什么显示为封面、第 4 页为什么显示为 iv」。它是文档级的单一数值树,合并后通常只剩第一份文件的标签,或者整份回退到物理页序——阅读器页码于是从 1、2、3 重新开始,印在页面上的号码却没变。页标签是结构,印上去的号码是内容,两者从不联动。

表单域按完全限定名索引。两份文件都有名为 name 的域时,同名域被当成同一域的多个外观,在一处填写会同步出现在另一处,且不报错,这是数据串页的经典事故。还有一类失败工具不会提示:字体子集名形如 ABCDEF+Arial,前缀由生成器给出,两份来源不同的文件恰好同前缀时,字形映射可能串位,个别字变成方块,只能逐页目视抽查。

拆分是对称的。按页范围拆开后,后半段的页标签从头起算或直接消失,跨页的表单域与链接被截断,指向另一半的命名目标悬空。任何改动还会让已存在的数字签名失效——签名覆盖除签名值以外的整个文件字节,改一个字节即告失效,这就是签名的定义。

结构合并时拆分时补救
大纲逐棵树拼接,悬空目标不报错目标落在另一半则失效合并后人工校验
页标签通常只留第一份或全丢后半段重新起算重写一次页标签
表单域同名域被合并成一个跨页域被截断合并前加前缀
数字签名原签名必然失效原签名必然失效签名放在最后一步
字体子集前缀冲突可能串字形无影响合并后目视抽查

五类文档级结构在合并与拆分下的行为差异

转成图片再转回来:分辨率到底付出了什么代价

PDF 用 PDF 点作单位,1 pt 等于 1/72 英寸,1 英寸是 25.4 毫米,所以 A4 的 210 乘 297 毫米换算成 595.276 乘 841.89 pt。渲染成位图时像素数由 DPI 唯一决定:像素等于 pt 除以 72 再乘 DPI。A4 在 72 DPI 下是 595 乘 842 像素,150 DPI 是 1240 乘 1754,300 DPI 是 2480 乘 3508,600 DPI 是 4961 乘 7016。体积大致随 DPI 的平方增长:DPI 翻倍,像素变四倍;一页彩色 A4 存成 PNG,300 DPI 常常到 8 至 15 MB。

代价不止体积。光栅化那一刻页面失去文本层:文字不可选中、不可搜索、不能复制,屏幕阅读器读到的是无标签图像,PDF/UA 要求的结构树也随之作废。矢量细节在低于 1 像素时消失:72 DPI 下 0.5 pt 的表格线正好半个像素,多数渲染器直接抹掉。链接注释与书签里的内部目标一并失效,跨页跳转全部变成死链。

转回 PDF 只是把一张图塞进页面容器,要恢复可用性必须 OCR,而 OCR 的质量上限由最初渲染的 DPI 决定。字符高度不到 20 像素时,形近字形的区分度不足;常用下限是正文 300 DPI,小字与表格 400 到 600 DPI。这里藏着最常见的重复编码事故:先 300 DPI 转成 JPEG,转回 PDF 后为减小体积又重压成 150 DPI,两次有损压缩叠加,再 OCR 时错误率远高于从原始矢量直接渲染。

不可逆点要分清层次。光栅化本身丢的是文本与矢量,只要原始 PDF 还在,从原文件重新渲染就能回退;真正不可逆的是原文件被覆盖,或者中间那次有损重采样成了唯一副本。所以判断动作很具体:任何一次转图片都保留原始 PDF,中间产物只当缓存,不在缓存上继续加工。

DPIA4 像素适用主要代价
72595 × 842缩略图、快速预览细线消失,文字不可读
1501240 × 1754屏幕阅读、邮件附件常低于可用 OCR 阈值
3002480 × 3508归档、OCR、打印体积约为 150 DPI 的四倍
6004961 × 7016小字、精细表格、图纸体积再翻四倍,处理变慢

像素等于 pt 除以 72 再乘 DPI,体积按 DPI 的平方走

提取文本:为什么顺序会乱

PDF 没有阅读顺序。内容流是一串绘制指令,提取器只能按指令出现顺序输出文字,而排版软件写入指令的顺序取决于它的内部布局,与人的阅读路径无关。两栏排版最典型:生成器按左栏第一行、右栏第一行、左栏第二行交错写入,提取结果是两句一换栏,句子被从中间劈开。

文字定位有两种写法,绝对定位用 Tm 设置文本矩阵,相对位移用 Td 与 TD。提取器拿到的是一组文字与坐标的对应关系,要靠启发式聚成行与块。判据分两条:画面上连续、提取后被切成多段且顺序错乱,问题在写入顺序,可按坐标重排;字符残缺、缺空格或出现方块,是字体缺少到 Unicode 的映射(ToUnicode 表不完整),重排救不回来。

几个具体的坑。连字:排版软件把 fi 合成一个字形,编码成 U+FB01,提取得到兼容字符而不是 f 加 i,搜索 fi 命中不了;UAX #15 的 NFKC 归一化会把它映射回 f 与 i。软连字符 U+00AD 用来标记可选断点,肉眼不可见,存进文本会污染搜索与比对。

加密文件的限制也要看清。PDF 32000-1 的权限位里,允许复制对应第 5 位(值 16),它只是建议值而非强制机制;AES-256 加密要到 PDF 2.0(ISO 32000-2)才成为标准。不少提取器根本不理权限位,只要能用空口令打开就照抽不误。把它当访问控制是误用,真正的控制只能靠不交出文件。

现象原因处理方向
两栏文字逐行交错内容流按生成器布局顺序写入按坐标分区后重排
fi 变成连字搜不到字形映射到 U+FB01NFKC 归一化
文本里混入看不见的字符软连字符 U+00AD 等格式字符过滤 Cf 类字符
整页只有一张图扫描型,没有文本层先 OCR 再提取
禁止复制却仍能抽出权限位只是建议值不能当访问控制

先分清是顺序问题还是字体问题,两者的修复手段没有交集

一套避免重复编码的操作顺序

顺序的目标只有一个:让不可逆的步骤尽量靠后,让可能返工的步骤尽量靠前。每保存一次就重写一次文件,重写次数越少越好,因为很多损失就发生在保存动作本身。

第一步定源。区分文本型与扫描型,混合文件逐页标注,这决定能否直接提取、要不要先 OCR;扫描件越晚做 OCR,后面每一步都在拿像素猜。第二步做页面级整理:删页、重排、旋转、合并、拆分,它们只改页面树,返工成本接近零,所以全部前置。

第三步处理文档级结构:页标签、大纲、元数据。它们是文档级的单一结构,任何一次合并或拆分都会重写,所以在页面结构稳定之后、内容加工之前一次写完。要彻底删除的元数据必须靠完整重写,增量保存只追加新对象,旧字符串仍留在文件里。

第四步才做内容层加工:页码、水印、裁剪、脱敏,它们要么追加内容流,要么改写内容流。页码尤其要分清:写 /PageLabels 是文档级编号映射,删页后自动顺延;把数字盖进内容流是永久烘焙,删掉一页就出现 1、2、4。

最后才是压平、光栅化、有损压缩与签名。压平与光栅化不可逆,一旦保存,表单域、文本层、矢量线条都不再存在;数字签名覆盖整个文件字节,任何后续修改都让它失效,所以签名必须压在最后。顺序倒着做是最常见的返工来源:先加页码再删页,先签名再改内容。

步骤为什么在这个位置做错后的返工
定源决定后续是否要 OCR整条流程从头再来
页面级整理只动页面树,返工近零重排一次即可
文档级结构合并拆分都会重写它编号与书签全丢
内容层加工追加或改写内容流需找回原始文件重做
压平与压缩不可逆且覆盖原结构原始信息已不存在
签名覆盖全文件字节只能重新签

六步顺序的判据:越靠后的步骤越难回退

常见问题

裁剪掉敏感区域再发出去,安全吗?
不安全。裁剪只改 CropBox 这个显示矩形,被裁掉的文字与图像仍在文件里,改回视口或提取都能拿回来。要真删,必须用按区域移除字符的 redaction。
合并后阅读器页码为什么对不上?
页面上的数字是内容,页标签是文档级结构,两者从不联动。合并通常只留第一份标签,或整份回退到物理页序,于是显示编号变了、印上的号码没变。合并后重写页标签即可。
转成图片再转回 PDF,文字还能搜索吗?
不能。光栅化后页面只剩像素,没有文本层,必须 OCR 才能得到可搜索文字。OCR 上限由渲染分辨率决定,正文建议不低于 300 DPI,也不要叠加多次有损压缩。
压平表单能减小文件体积吗?
几乎不能。压平去掉的是字段结构与外观对象的重复,减掉的只是很小的结构开销,体积主要由图像决定。压平的真正后果是表单不可填、注释不可编辑,而且无法还原。
为什么提取出来的文字顺序和看到的不一样?
PDF 没有阅读顺序,提取顺序就是内容流里指令的顺序,两栏与表格会交错输出。若是个别字符残缺而非顺序错乱,那是字体缺 ToUnicode 映射,重排无法修复。

动手试试