详解Python如何实现批量为PDF添加水印
作者:kingname 发布时间:2022-06-20 23:33:58
我们有时候需要把一些 * 发给多个客户,为了避免客户泄露文件,会在 * 中添加水印。每个客户收到的文件内容相同,但是水印都不相同。这样一来,如果资料泄露了,通过水印就知道是从谁手上泄露的。
今天,一个做市场的朋友找我咨询PDF加水印的问题,如下图所示:
他有一个Excel文件,文件里面有10000个经销商的名字,他要把价目表PDF发给这些经销商,每个经销商收到的PDF文件上面的水印都是这个经销商自己的名字。
这个需求手动操作肯定要累死人。但是如果用Python来做,就非常简单。代码不超过30行。
准备环境
要完成这个需求,需要安装两个模块,分别叫做reportlab
和pikepdf
。使用Pip安装就可以了:
python3 -m pip install reportlab pikepdf
然后,需要找到一个.ttf
或者.ttc
格式的中文字体。你可以直接从网上下载中文字体文件。也可以使用系统自带的中文字体。这里以寻找macOS系统默认的宋体为例。
macOS系统字体在/System/Library/Fonts
,宋体对应的.ttc
文件地址是/System/Library/Fonts/Supplemental/Songti.ttc
。对于系统默认的字体,我们只需要知道它的对应的文件名叫做Songti.ttc
就可以了。如果是从网上下载的第三方字体,需要使用绝对路径或者相对于项目代码的相对路径。
获得经销商名字对应的列表
由于这位朋友不会使用pandas,那么我们就尽量使用Python原生的方法来获得经销商名字列表。假设经销商信息对应的Excel如下图所示:
我们首先把这个Excel文件导出成csv文件:
然后,我们用Python读取这个csv文件,获得经销商名字列表:
import csv
with open('经销商信息.csv') as f:
reader = csv.DictReader(f)
name_list = [x['经销商名字'] for x in reader]
print(name_list)
运行效果如下图所示:
生成水印PDF
一般来说,我们不能直接把一段文字作为水印添加到另一个PDF文件中。我们只有先把这段文字生成图片或者生成水印PDF文件,然后把这个图片或者水印PDF作为『图层』覆盖到目标PDF上面。
因此,现在需要给每一个经销商生成对应的水印PDF文件。这个PDF中只含有水印文字。效果如下图所示:
对应的代码create_watermark.py如下:
import csv
from pathlib import Path
from reportlab.lib import units
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
with open('经销商信息.csv') as f:
reader = csv.DictReader(f)
name_list = [x['经销商名字'] for x in reader]
pdfmetrics.registerFont(TTFont('Songti', 'Songti.ttc')) # 加载中文字体
water_mark_folder = Path('water_pdf') # 用一个文件夹存放所有的水印PDF
water_mark_folder.mkdir(exist_ok=True)
for name in name_list:
path = str(water_mark_folder / Path(f'{name}.pdf'))
c = canvas.Canvas(path, pagesize=(200 * units.mm, 200 * units.mm)) # 生成画布,长宽都是200毫米
c.translate(0.1 * 200 * units.mm, 0.1 * 200 * units.mm)
c.rotate(45) # 把水印文字旋转45°
c.setFont('Songti', 35) # 字体大小
c.setStrokeColorRGB(0, 0, 0) # 设置字体颜色
c.setFillColorRGB(0, 0, 0) # 设置填充颜色
c.setFillAlpha(0.3) # 设置透明度,越小越透明
c.drawString(0, 0, f'{name}专用价目表,严禁泄露!')
c.save()
代码的具体作用,已经写到注释中了。运行以后会在当前项目根目录生成water_pdf
文件夹,里面就是生成的水印PDF。
合并水印与目标PDF
最后一步,把每一个经销商的水印PDF与目标PDF进行合并。水印PDF作为一个图层覆盖到目标PDF上面。
使用pikepdf
完成这个工作非常简单,编写一个combine.py文件,代码如下:
import glob
from pathlib import Path
from pikepdf import Pdf, Page, Rectangle
water_pdf_list = glob.glob('water_pdf/*.pdf')
result = Path('result')
result.mkdir(exist_ok=True)
col = 2 # 每页多少列水印
row = 3 # 每页多少行水印
for path in water_pdf_list:
target = Pdf.open('./PythonisinstanceGolang.pdf') # 必须每次重新打开PDF,因为添加水印是inplace的操作
file = Path(path)
name = file.stem
water_mark_pdf = Pdf.open(path)
water_mark = water_mark_pdf.pages[0]
for page in target.pages:
for x in range(col): # 每一行显示多少列水印
for y in range(row): # 每一页显示多少行PDF
page.add_overlay(water_mark,
Rectangle(page.trimbox[2] * x / col,
page.trimbox[3] * y / row,
page.trimbox[2] * (x + 1) / col,
page.trimbox[3] * (y + 1) / row))
result_name = Path('result', f'{name}_添加水印.pdf')
target.save(str(result_name))
运行以后,会在项目根目录生成一个result
文件夹,里面就是添加了水印的PDF文件了,如下图所示:
这里有必要对代码中的一些地方进行解释。带上行号的代码如下图所示:
代码第21行和22行,有两个for
循环,他们的作用是给一个页面上添加多个水印。请大家注意下图我画圈的地方:
每一页都有6个水印,分成3行2列。其中的3行对应了变量row
的值。2列对应了变量col的值。大家也可以根据自己的需要修改这两个数字。甚至每一页的水印随机变换位置,防止被去水印的程序移除。
page.trimbox[2]
是PDF页面的宽度,page.trimbox[3]
是PDF页面的高度。
来源:https://mp.weixin.qq.com/s/EsvQzJqxXfty-zAe_fGc1A
猜你喜欢
- 大家好,今天来学习用Flask API创建Python后台任务。在Python中,有若干解决方案可以实现后台任务,比如Celery或Redi
- CREATE TABLE `category` ( `Id` binary(1
- Django 开发项目是很快的,有多快?看完本篇文章,你就知道了。安装 Django前提条件:已安装 Python。Django 使用 pi
- Python是支持可视化编程,即编写gui程序,你可以用它来编写自己喜欢的桌面程序。使用wxPython来做界面非常的简单,只是不能像C#一
- 微博如火如荼,大家都选择用微博带来社会化流量,顺便推广产品和网站,几乎所有的网站都有分享到代码,但是还有一种更快捷的分享方式,javascr
- 这篇文字讲述如何使用Python把一张完整的大图切割成9份小图片,制作朋友圈九宫格图文分享。原图如下: 我们想要利用这张图制作高逼
- 1、检测登录状态base.pydef checkLogin(func):""" 查看session
- 列表(List) 的三种遍历(序号和值)方法if __name__ == '__main__':
- 实例如下:#!/usr/bin/env python# -*- coding: utf-8 -*-import socket#创建一个soc
- 目录1、设定答题卡模板2、读取答题卡图像并对图像进行灰度化处理3、高斯模糊图像去噪点4、使用大津法二值分割图像5、使用开运算去噪点6、使用c
- 前言博主参与过大大小小十次数学建模比赛,也获得了不少建模奖项。对于一些小批量样本数据去做预测或者是评估其规律性的话,比较适合的模型一般都是选
- 前言回调函数是我们在python编程中经常会遇到的一个问题,而想在将来某一时刻进行函数回调,可以使用call_later()函数来实现,第一
- 本篇博客参考:1)DEM generation from laser scanner data using adaptive TIN mod
- 1.用phpmyadmin创建数据库和数据表 创建数据库的时候,请将“整理”设置为:“utf8_general_ci” 或执行语句:CREA
- 当您想要描述一个链接的时候,工具提示(Tooltip)就显得非常有用。工具提示(Tooltip)插件是受 Jason Frame 写的 jQ
- <P><html><head><meta http-equiv="Content-Typ
- 学生信息系统提示:python编写的学生成绩管理系统,包括8个功能和打包教程一、功能界面 def menum():
- Redis通常被认为是一种持久化的存储器关键字-值型存储,可以用于几台机子之间的数据共享平台。连接数据库 注意:假设现有几台在同一局域网内的
- 如图所示,我们要计算任意两个向量之间的夹角。(图中的坐标数字是估计值,随手给定)python代码如下import math AB = [1,
- 在Firefox推出3.5后,他增加了许多新的支持,今天抽空将他们整理一下。属性image-renderingtext-renderingi