「Python实用秘技04」为pdf文件批量添加文字水印
本文完整示例代码及文件已上传至我的
Github仓库https://github.com/CNFeffery/PythonPracticalSkills
这是我的系列文章「Python实用秘技」的第4期,本系列立足于笔者日常工作中使用Python积累的心得体会,每一期为大家带来一个3分钟即可学会的简单小技巧。
作为系列第4期,我们即将学习的是:为pdf文件批量添加文字水印。

有些情况下我们需要为单个或多个pdf文件添加文字水印,尤其是那种需要在每一页按照一定间距铺满的文字水印。而借助reportlab和pikepdf这两个实用的pdf文件操作库,我们就可以很方便地实现批量文字水印添加工作。
利用pip install reportlab pikepdf 完成安装后,我们就可以按照步骤来实现需要的功能:
- 生成指定的文本水印pdf文件
为了向目标pdf文件添加水印,我们首先需要有单独的pdf格式的文本水印文件,我用reportlab编写了一个方便易用的函数来生成水印文件,你可以通过注释来仔细学习其中的步骤,也可以直接调用即可:
from typing import Union, Tuple
from reportlab.lib import units
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# 注册字体,这里的字体是我从windows的字体目录下复制过来的
pdfmetrics.registerFont(TTFont('msyh', r'./msyh.ttc'))
def create_watermark(content: str,
filename: str,
width: Union[int, float],
height: Union[int, float],
font: str,
fontsize: int,
angle: Union[int, float] = 45,
text_stroke_color_rgb: Tuple[int, int, int] = (0, 0, 0),
text_fill_color_rgb: Tuple[int, int, int] = (0, 0, 0),
text_fill_alpha: Union[int, float] = 1) -> None:
'''
用于生成包含content文字内容的水印pdf文件
content: 水印文本内容
filename: 导出的水印文件名
width: 画布宽度,单位:mm
height: 画布高度,单位:mm
font: 对应注册的字体代号
fontsize: 字号大小
angle: 旋转角度
text_stroke_color_rgb: 文字轮廓rgb色
text_fill_color_rgb: 文字填充rgb色
text_fill_alpha: 文字透明度
'''
# 创建pdf文件,指定文件名及尺寸,这里以像素单位为例
c = canvas.Canvas(f"{filename}.pdf", pagesize = (width*units.mm, height*units.mm))
# 进行轻微的画布平移保证文字的完整
c.translate(0.1*width*units.mm, 0.1*height*units.mm)
# 设置旋转角度
c.rotate(angle)
# 设置字体及字号大小
c.setFont(font, fontsize)
# 设置文字轮廓色彩
c.setStrokeColorRGB(*text_stroke_color_rgb)
# 设置文字填充色
c.setFillColorRGB(*text_fill_color_rgb)
# 设置文字填充色透明度
c.setFillAlpha(text_fill_alpha)
# 绘制文字内容
c.drawString(0, 0, content)
# 保存水印pdf文件
c.save()
下面我们就利用这个函数来生成水印文件:
# 制造示例文字水印pdf文件
create_watermark(content='公众号【Python大数据分析】作者:费弗里',
filename='水印示例',
width=200,
height=200,
font='msyh',
fontsize=35,
text_fill_alpha=0.3)
看看效果,非常的不错,具体使用时,你可以自己动手调参以找到大小以及画幅都令你满意的水印导出结果:

- 将水印文件批量覆盖到目标pdf文件中
搞定了文本水印文件的生成之后,接下来我们就可以把现成的水印文件插入到目标pdf文件中,这里我们使用pikepdf中的相关功能就可以轻松实现,我写了一个简单的函数,大家在调用时只需要传入几个必要参数即可:
from typing import List
from pikepdf import Pdf, Page, Rectangle
def add_watermark(target_pdf_path: str,
watermark_pdf_path: str,
nrow: int,
ncol: int,
skip_pages: List[int] = []) -> None:
'''
向目标pdf文件中添加平铺水印
target_pdf_path: 目标pdf文件的路径+文件名
watermark_pdf_path: 水印pdf文件的路径+文件名
nrow: 水印平铺的行数
ncol:水印平铺的列数
skip_pages: 需要跳过不添加水印的页面序号(从0开始)
'''
# 读入需要添加水印的pdf文件
target_pdf = Pdf.open(target_pdf_path)
# 读入水印pdf文件并提取水印页
watermark_pdf = Pdf.open(watermark_pdf_path)
watermark_page = watermark_pdf.pages[0]
# 遍历目标pdf文件中的所有页(排除skip_pages指定的若干页)
for idx, target_page in enumerate(target_pdf.pages):
if idx not in skip_pages:
for x in range(ncol):
for y in range(nrow):
# 向目标页指定范围添加水印
target_page.add_overlay(watermark_page, Rectangle(target_page.trimbox[2] * x / ncol,
target_page.trimbox[3] * y / nrow,
target_page.trimbox[2] * (x + 1) / ncol,
target_page.trimbox[3] * (y + 1) / nrow))
# 将添加完水印后的结果保存为新的pdf
target_pdf.save(target_pdf_path[:-4]+'_已添加水印.pdf')
下面我们直接调用这个函数,对示例文件【吴恩达】机器学习训练秘籍-中文版.pdf中除了封面以外的每一页,按照3行2列的平铺密度,添加上我们的示例水印:
add_watermark(target_pdf_path='./【吴恩达】机器学习训练秘籍-中文版.pdf',
watermark_pdf_path='./水印示例.pdf',
nrow=3,
ncol=2,
skip_pages=[0])
效果杠杠的,读者朋友们可以自己多试试,得到更多心得体会~

本期分享结束,咱们下回见~
「Python实用秘技04」为pdf文件批量添加文字水印的更多相关文章
- 「Python实用秘技01」复杂zip文件的解压
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的新系列文章「Python实用秘技」的第1 ...
- 「Python实用秘技02」给Python函数定“闹钟”
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第2期 ...
- 「Python实用秘技03」导出项目的极简环境依赖
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第3期 ...
- 「Python实用秘技05」在Python中妙用短路机制
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第5期 ...
- 「Python实用秘技06」逐行监听Python程序的内存消耗
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第6期 ...
- 「Python实用秘技07」pandas中鲜为人知的隐藏排序技巧
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第7期 ...
- 「Python实用秘技08」一行代码解析地址信息
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第8期 ...
- 「Python实用秘技09」更好用的函数运算缓存
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第9期 ...
- 「Python实用秘技10」深度比较Python对象间差异
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第10 ...
随机推荐
- 如何下载哔哩哔哩、爱奇艺、腾讯视频、优酷、斗鱼、TED、YouTube网页视频
这里使用you-get工具进行下载 github地址:https://github.com/soimort/you-get/ github项目文档:https://github.com/soimort ...
- num_duilib之TabBox用法(21)
介绍 本文将介绍 使用 TabBox的用法 更多用法,请参考源码 TabBox.h 文件 文件中定义了公有接口,其中包括,添加tab页下的控件,删除.设置TabBox的属性 其中,我常用的有:GetC ...
- 【LeetCode】919. Complete Binary Tree Inserter 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址: https://leetcode. ...
- 小白自制Linux开发板(第二季 V3s篇) 一. 换个核心再来一次
1.前言 大家心心念念(个人认为)的小白自制开发板全新系列正式来了,之前我们使用全志的F1C200s芯片制作了一个小电脑,众所周知,调试很艰难,坑也很多,以至于墨云到现在还是没找到对应的补救方案,为了 ...
- 动态规划题 HDU-1024
http://acm.hdu.edu.cn/showproblem.php?pid=1024 Now I think you have got an AC in Ignatius.L's " ...
- 如何在HTML中添加表格标题?(HTML中table添加标题的2种方法)
第一种:通过 fieldset 添加标题框 示例代码: <html> <body> <fieldset> <legend>fieldset添加框标题&l ...
- 【MySQL作业】多字段分组和 having 子句——美和易思分组查询应用习题
点击打开所使用到的数据库>>> 1.按照商品类型和销售地区分组统计商品数量和平均单价,并按平均单价升序显示. -- 按照商品类型和销售地区分组统计商品数量和平均单价,并按平均单价升序 ...
- 如何使用NiFi等构建IIoT系统
您认为构建一个先进的工业物联网原型需要多长时间: 从传感器收集数据到每个工厂的网关 将传感器数据从一个或多个工厂移至云或数据中心 自动热部署新配置到所有边缘设备 支持大规模数据量和端到端安全性 使用正 ...
- Maven常用参数说明
缩写 全名 说明 -h --help 显示帮助信息 -am --also-make 构建指定模块,同时构建指定模块依赖的其他模块 -amd --also-make-dependents 构建指定模块, ...
- APP自动化,怎样让应用不重置?
noReset =True产生的背景: 在编写APP自动化代码时,除了登录用例需要填写账号和密码外,其余很多用例都是需要先登录再操作的,如果每一个用例都从头开始到具体的操作,这样将会耗费很多时间,此时 ...