搜「PDF 不能复制 不能打印」时底下的回答大多一句话带过,说文件设了权限密码。我一直没想通的是这种文件打开根本不要密码,工具却偏说它已加密。它到底锁在哪里、拦住复制的又是谁?我平时写内部小工具常跟 PDF 打交道,就干脆自己生成了七份测试 PDF 挨个去试。内容是标题写着「示例合同(占位文字,仅供测试)」的两页占位文字。甲方乙方都是「某某公司」「某某工作室」,看着还挺像那么回事。我的结论是限制拦不拦要看打开它的那个软件,同一份文件换个地方结果就不一样。
打开不要密码的文件也带着加密
七份样本里一份完全没加密、一份设了打开密码。剩下五份只设了权限密码(打开密码留空、只填所有者密码)。这五份我换了几种加密算法和几种限制组合,有全禁的、只禁复制的也有只禁打印的。这五份在 Chromium 149 开源构建和 Firefox 151 自带的阅读器里都直接显示出来,而且界面上连一句限制提示都没有。只有设了打开密码的那份会被拦在门口,Chromium 弹出「需要密码」的框。Firefox 英文界面写的是「Enter the password to open this PDF file.」。
可它们每一份都带着完整的加密字典,内容也真用 AES 或 RC4 加密过。只是用户密码为空,阅读器会自己拿空密码解开所以你完全感觉不到。工具提示的「已加密」指的就是这个字典。顺手还踩到一个小坑。同一份只设权限密码的文件在 PyMuPDF 里 is_encrypted 是 False,在 pypdf 里是 True。这个词在两个库里意思不同,前者指现在还锁着没解开,后者指文件有没有加密字典。自己写脚本判断时只看其中一个布尔值就会判错。
同一份文件在各处拦法不一样
真正让我意外的是执行这一步。我把打印、复制文字、编辑批注三项放到五个地方分别试。五个地方是 Chromium 自带阅读器、Firefox 默认设置、Firefox 打开权限执行开关之后、pdf.js 当页面库,还有 PyMuPDF 当处理库。
这张表横向是三项操作、纵向是五个处理方。绿色是拦住了、橙色是照常可用、灰色是只把权限位报出来自己不管。同样一份打开不要密码的全禁文件在五行里没有两行结果完全一样。最底下两行全灰是因为库本身不替谁执行限制,执不执行由用它的应用自己决定。
先说 Chromium。复制我是在正文上拖选四行按 Cmd+C 再到另一个页面的文本框里粘贴。测之前先往剪贴板写一段哨兵字符串免得读到上一次的残留。禁复制的文件照样能拖选、蓝色高亮一点不少,粘贴出来却是空的。打印按钮也照常显示在工具栏上,允许打印的文件点了会进打印流程,禁打印的点了没有任何反应。编辑这一项它没拦。七份样本全都能进「绘制」画出笔迹,撤销按钮也跟着亮了起来。连声明了禁止注释的那几份也一样。画完我没有保存,这一笔能不能留在文件里我也不知道。
左右两边是同一段正文。左边来自没加密的文件,右边来自只设了权限密码、禁止复制的文件。上半部分两边拖出的蓝色高亮看不出任何区别。下半部分的粘贴框里左边贴出了甲方乙方和两条条款,右边红框里还是「粘贴到这里」的占位字。
Firefox 默认设置下打印、复制和编辑三样都不拦。七份样本的打印按钮都在并且都能调起打印。它其实有个默认关着的权限执行开关叫 pdfjs.enablePermissions。打开之后禁打印的文件打印按钮直接消失,禁编辑的文件编辑按钮全部变灰。复制却还是没拦住。连只禁复制的那份也照样复制出了正文这件事我来回确认了好几遍。
上下两排是同一份全禁文件的 Firefox 工具栏。上排默认设置里批注、签名、高亮、文字、绘图和图片几个编辑按钮都能点,再往右是打印和下载。到了下排权限执行开关一打开,红框里那排编辑按钮就都成了灰色。下载按钮左边本该有的打印按钮也跟着消失了。
换了加密算法结果也没变
我原本还猜加密算法会影响阅读器,比如老一点的 RC4 会不会更容易被放过去。试下来一点不影响,全禁的三份分别用 AES-256、RC4-128 和 RC4-40 加密,在 Chromium 和 Firefox 两种设置下表现一模一样。只禁复制的那份用 AES-128、只禁打印的用 AES-256,也都只按各自声明的限制来。决定结果的只有权限位。打开密码那份我输入密码打开后也看了一眼,Chromium 照样拦复制和打印。Firefox 两种设置下也跟全禁那份表现相同。打开密码只管能不能打开,打开以后的限制照旧。
压缩工具遇到它直接拒绝
阅读器各拦各的,那处理工具又怎么对待这类文件?为了看这一点我试的是图映 ImgIng(imging.cn/)的 PDF 压缩,测试条件还是那几份自己生成的 PDF。我挑了没加密的一份、只设权限密码的三份和带打开密码的一份,档位选电子书。没加密的那份正常压完,从 66 KB 到 49 KB 省了 25.7%。四份加密的导入时都不报错,可一点开始压缩就全部标成了失败。失败那一行底下跟着「这份 PDF 有加密或权限保护,需要先解除保护」这句提示。只禁复制、允许修改和组合的那份也一样被拒,带打开密码的那份也没有弹出密码框。处理是在本机做的。我数了一下这回页面发出的 46 个请求里非 GET 的一个都没有。还有个小地方对不上。失败之后右侧进度卡写的仍是「全部完成」,下面一行写着「0 个文件已压缩完成,可以逐个保存。」。
它为什么一律拒绝界面没说。我猜是因为压缩要重写整份文件,重写就绕不开所有者当初设的限制,干脆就不碰了。这纯属我的推测。
收到受限文件时该找谁
回到开头那个问题。打开时不要密码、工具却说已加密的基本就是只设了权限密码。它限制的是阅读软件愿不愿意配合你打印、复制和编辑,这份配合各家给得不一样。Chromium 确实拦住了复制和打印,这点得认。可 Firefox 默认三样都放行,开了开关也照样能复制。各家执行得这么不齐,它在我这里算不上一道靠得住的防线。发文件的一方要是真不想让人看到内容就得靠打开密码。权限密码写进文件的只是一份要求,谁来执行、执行到哪一步都由对面的软件说了算。收到这种文件又确实要改的时候我现在都是直接找原作者要一份不带限制的版本。文件是自己的、还记得所有者密码的就用当初生成它的软件输入所有者密码重新导出一份。
还有几块我没测到。Acrobat Reader、macOS 预览、Safari 正式版和手机上的阅读器都没试。WebKit 26.5 只测了 pdf.js 页面库这一种用法。判断 Chromium 打印拦没拦我看的是点击后有没有进入打印流程。这是个间接信号,真实的打印对话框我没见到。这些等我手上有了对应的环境再接着测。