使用Python为PDF文件批量添加水印的方法及进一步思考

感谢中国传媒大学胡凤国老师的分享!

============

问题描述:

想用Python把WORD文件转成PDF文件并加上水印。网上搜了一下资料,没发现有现成的解决方案。于是决定自己写一个Python程序。思路是分两步:第一步,将WORD文件转成PDF,第二步将生成的PDF文件添加水印。但是做的过程中出现了一些问题,解决的过程对我来说又十分困难,这里把我的思路、方法和经验教训总结一下,分享给需要的朋友。

系统环境:

32位Win7 + Python 3.6.4 + Office2010。

材料准备:

1、网上下载《千字文》全文,放入WORD文件中,每页25行,每行5列,每列4字,设定大小合适以填满两页,保存为“test.docx”。

2、另准备一个用来充当水印的图片“water.jpg”,用其他方法把它变成一个图案半透明的PDF文件“water.pdf”。

3、用WPS加载“test.docx”导出的PDF文件“testwps.pdf”。

4、用Acrobat加载WORD2010做成的“testword2010.pdf”导出的图片,保存目录是“testacrobat”。

第一步:将“test.docx”变成“testword2010.pdf”。

为适应批处理需要,这里不考虑手动用WORD2010另存为的办法得到PDF文件。

这一步,参考网上资料,直接写出Python程序word2pdf.py:

第二步:为PDF文件加水印

将“testword2010.pdf”变成“rword2010.pdf”。网上资料也很多,思路是使用PyPDF2扩展包,参考网址http://www.blog.pythonlibrary.org/2018/06/07/an-intro-to-pypdf2/给出的代码,写出Python程序addwatermark1.py:

运行程序发现出错。出错信息如下:

Traceback (most recent call last):

File "C:\Python364\lib\site-packages\PyPDF2\generic.py", line 484, in readFromStream

return NameObject(name.decode('utf-8'))

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xcb in position 8: invalid continuation byte

During handling of the above exception, another exception occurred:

这后面还跟着数十行出错信息。生成的PDF文件“rword2010.pdf”自然是打不开的。网上搜一圈,发现没有相关帖子。看来我这是小众问题,小概率事件发生在我身上,我怎么这么幸运呢?强忍住到世界杯去赌球的冲动,继续思考我的问题的解决办法。

第三步:寻求问题的原因

首先,我看出错信息有“decode('utf-8')”之类的字样,难道是PyPDF2不支持中文?

于是我又做了一个纯英文的WORD文件,用WORD2010手动导出成PDF,加水印也是失败的。这就排除了编码的问题,看来这个问题PDF文件是不是中文内容关系不是太大。

到目前为止,我也怀疑这事儿跟所谓的PDF版本有关,但查不到相关资料,不知道word2010和wps文字导出的PDF到底是哪个版本的PDF。或许从这里突破还真有希望找到为PDF加水印的简单办法,但目前没太多精力,无奈放下,继续寻找为PDF加水印的成功办法。

于是继续上网搜,另外一个网友在贴子https://blog.csdn.net/Leafage_M/article/details/79705731里面提到一个奇怪的思路:

pdf = PdfFileReader(input_pdf)

改为

pdf = PdfFileReader(input_pdf, strict=False)

我按照这个思路去修改代码,程序运行不报错了,会在输出警告信息后生成“rword2010.pdf”,警告信息如下:

PdfReadWarning: Illegal character in Name Object [generic.py:489]

随后查看这个加水印后的PDF文件,发现只能看见水印,完全看不到中文内容。又做了一下英文PDF的实验,发现水印有,看不到英文内容。

现在,问题原因找到了:我们用PyPDF2扩展包为PDF文件添加水印之所以失败,是因为PDF是通过WORD2010将WORD文件转换来的。

那么,问题似乎解决了,用WPS文字把WORD文件做成PDF文件似乎是个好办法,然后再用我们第二步的代码就能为WPS生成的PDF文件加水印。但为现存的PDF文件加水印的问题还没有解决,因为我们的现存PDF文件总有很多是用WORD2010做成的。所以,还得继续寻找为PDF文件加水印的办法。

第四步:探求PDF加水印的通用办法

看来Python的扩展包PyPDF2的添加水印功能还是有很大缺点的,在它自身的版本升级之前,是不能考虑它了。本着吃不成鱼肉吃猪肉也行的原则,我们坚决抛开PyPDF2,另觅它途。既然一步到位不了,我们可以继续把整个任务分成两个子任务:

任务一:将PDF文件拆成图片,一页PDF文件变成一张图片。

任务二:将一张张的图片加上水印合并成PDF。

这两步似乎都不难。现分别实现之。

任务一:将PDF文件拆成图片

这个任务需要用到PyPDF2、PythonMagick和ghostscript三个扩展包,这里使用PyPDF2的其它功能。参考资料是

废话少说,直接上代码,函数如下:

任务二:将图片加上水印合并成PDF

这一个任务主要是用扩展包reportlab。代码也很简单,直接给出函数:

有了这两个函数,我们就好办了。将源PDF文件转成图片保存到中间目录,然后将中间目录的图片加上水印合并成目标PDF文件,最后删掉中间目录。调用函数的代码如下:

运行一下,一切OK。

结语

虽然实现了为PDF文件添加水印的通用算法,为批量将WORD文件直接转换为带水印的PDF文件扫清了障碍。但是,还存在着如下的问题

第一、用本文的办法生成的图片质量不是太高,如果不删除中间结果目录的话,我们会看到,程序自动生成的图片远不如用Acrobat手动打开“testword2010.pdf”用菜单导出的图片清楚。所以,如何自动从PDF文件导出质量更高的图片,值得进一步研究。为了对比,本文在研究过程中将Acrobat导出的图片保存在“testacrobat”目录,用如下语句生成加水印的PDF文件:my_create_pdf_from_pictures_and_add_watermark("testacrobat", "r.pdf", waterfn)

第三、本文的思路和算法可能存在缺点和不足,请广大朋友批评指正。希望抛砖引玉,能找到更好的PDF添加水印的办法。

致谢

特别感谢Python界的大咖董付国老师,作为Python的小白,我在用Python处理WORD、PDF和图片的过程中得到董老师很多帮助。

也感谢我参考资料里面列出网址的帖子的楼主,他们给了我启发。

测试文件与代码下载地址:

链接: https://pan.baidu.com/s/1967jzOb3hFi-e5zSoboQwQ 密码: c8hw

中国传媒大学,胡凤国,2018年6月30日

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20180701B0EB2400?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券