使用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文件是不是中文内容关系不是太大。

仍然是上网狂搜,变换各种关键词狂搜。终于搜到一篇相关的 https://blog.csdn.net/Li_Jiaqian/article/details/80299026 该帖子想用程序合并PDF文件,遇到跟本文一样的错误,贴文的作者说原来的pdf是1.5版本,合并出错。他将pdf转化为word,再在wps中将word输出为pdf,这时的pdf是1.7版本,合并就不再报错。 于是用WPS文字打开“test.docx”,用菜单“输出为PDF”生成PDF文件“testwps.pdf”,用上面的代码(当然得改一下文件名)加水印,成功。 用的WPS文字的版本是“WPS 文字 10.1.0.7400”,20180629官网下载。

到目前为止,我也怀疑这事儿跟所谓的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的其它功能。参考资料是

https://blog.csdn.net/sqlserverdiscovery/article/details/51425543

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

任务二:将图片加上水印合并成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)

第二、不相信PyPDF2的开发者比我们笨,所以说不定PyPDF2还有一些隐藏功能我们没发掘出来,因此寻求PyPDF2为PDF文件添加水印的完美解决办法还是有希望的。

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

致谢

特别感谢Python界的大咖董付国老师,作为Python的小白,我在用Python处理WORD、PDF和图片的过程中得到董老师很多帮助。 也感谢我参考资料里面列出网址的帖子的楼主,他们给了我启发。

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

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

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

原文发布于微信公众号 - Python小屋(Python_xiaowu)

原文发表时间:2018-07-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Fundebug

微信小程序开发BUG经验总结

小程序开发越来越热,开发中遇到各种各样的bug,在此总结了一些比较容易掉进去的坑分享给大家。

567120
来自专栏Android开发指南

安卓模拟器

50790
来自专栏前端布道

前端开发必备之Chrome开发者工具(下篇)

本文介绍的 Chrome 开发者工具基于 Chrome 65版本,如果你的 Chrome 开发者工具没有下文提到的那些内容,请检查下 Chrome 的版本 本文...

361110
来自专栏Material Design组件

Human Interface Guidelines —— Edit Menus

14160
来自专栏程序员的碎碎念

JavaGUI编程之·引用类库Beautyeye改变外观

上一期讲到JavaGUI默认界面在win7上显示得比较粗糙,小编在原来的基础上对各种组件的属性进行大量修改才得以让原界面扁平化。上期推文发出后,就有大神提供建议...

1.3K90
来自专栏小白课代表

更新 | 给你的Windows加一个 「文件快速预览」功能

13920
来自专栏菩提树下的杨过

flex中使用swc实现更好的界面代码分离

前几天写过一篇"flash开发中如何实现界面代码分离",评论中 小-G 同学给出了更好的建议:swc ,今天试用了一下,果然比较embed swf来得更爽!同时...

22160
来自专栏AI星球

看我玩 Mac--有趣的软件

近几天,在 Mac 上捣鼓了一些有趣的东西,分享给 Mac 新手们,一起装逼一起飞,我们友谊的小船可不能说翻就翻奥!哈哈。

76420
来自专栏葡萄城控件技术团队

作为JavaScript开发人员,这些必备的VS Code插件你都用过吗?

如今,Visual Studio Code无疑是最流行的轻量级代码编辑器。它确实从其他代码编辑器那借鉴了很多,最主要是从Sublime和Atom那里。然而它的成...

36910
来自专栏程序员宝库

主流浏览器图片反防盗链方法总结

还记得之前写的那个无聊的插件,前一段时间由于豆瓣读书增加了防盗链策略使得我们无法直接引用他们的图片,使得我这个小插件无法工作。本以为是一个很简单的问题,但是没想...

15250

扫码关注云+社区

领取腾讯云代金券