夜雨聆风学习资料网

ARTICLE · 1189426

Python批量给PDF加水印,再也不用一个个手动加了!

Python批量给PDF加水印,再也不用一个个手动加了!

工作中经常遇到需要给PDF加水印的情况:合同要标“机密”,简历要加姓名,教程要注版权……如果只有一两个文件,手动加还能忍;但要是几十上百个,那真是点到手抽筋。

今天就教大家用Python写一个批量PDF加水印脚本,一次运行,全部搞定,效率直接起飞!


一、准备工作

这次我们用两个库:

  • reportlab:生成水印PDF(支持中文、旋转、透明度)

  • pypdf:合并水印和原PDF(PyPDF2的升级版,维护更活跃)

安装命令:

pip install reportlab pypdf

如果之前装过PyPDF2,建议换成pypdf,接口基本兼容,但性能更好。


二、核心思路

PDF加水印的本质是:做一个只有水印的透明页面,然后把它“盖”到原PDF的每一页上。

步骤拆解:

  1. 读取原PDF,获取每一页的宽高

  2. 用reportlab生成一个同样大小的水印页(文字可旋转、半透明)

  3. 把水印页和原页面合并

  4. 保存为新PDF


三、完整代码

import osimport iofrom reportlab.pdfgen import canvasfrom reportlab.pdfbase import pdfmetricsfrom reportlab.pdfbase.ttfonts import TTFontfrom pypdf import PdfReader, PdfWriter# ============ 配置区 ============INPUT_DIR = "./pdfs"           # 原PDF文件夹OUTPUT_DIR = "./output"        # 输出文件夹WATERMARK_TEXT = "机密文件 请勿外传"  # 水印文字FONT_PATH = "C:/Windows/Fonts/simhei.ttf"  # 中文字体路径FONT_SIZE = 40                 # 字号OPACITY = 0.15                 # 透明度(0-1,越小越淡)ANGLE = 45                     # 旋转角度# ================================# 注册中文字体pdfmetrics.registerFont(TTFont("SimHei", FONT_PATH))def create_watermark_page(width, height, text):    """生成水印PDF页面,返回BytesIO"""    packet = io.BytesIO()    can = canvas.Canvas(packet, pagesize=(width, height))    can.setFont("SimHei", FONT_SIZE)    can.setFillAlpha(OPACITY)    can.setFillColorRGB(0.5, 0.5, 0.5)  # 灰色    # 平移到页面中心并旋转    can.translate(width / 2, height / 2)    can.rotate(ANGLE)    # 文字居中    text_width = pdfmetrics.stringWidth(text, "SimHei", FONT_SIZE)    can.drawString(-text_width / 2, 0, text)    can.save()    packet.seek(0)    return packetdef add_watermark(input_path, output_path, text):    """给单个PDF添加水印"""    reader = PdfReader(input_path)    writer = PdfWriter()    for page in reader.pages:        width = float(page.mediabox.width)        height = float(page.mediabox.height)        # 生成水印页        watermark_packet = create_watermark_page(width, height, text)        watermark_page = PdfReader(watermark_packet).pages[0]        # 合并        page.merge_page(watermark_page)        writer.add_page(page)    with open(output_path, "wb") as f:        writer.write(f)def batch_process():    """批量处理文件夹下所有PDF"""    if not os.path.exists(OUTPUT_DIR):        os.makedirs(OUTPUT_DIR)    pdf_files = [f for f in os.listdir(INPUT_DIR) if f.lower().endswith(".pdf")]    if not pdf_files:        print(f"❌ 在 {INPUT_DIR} 中没有找到PDF文件")        return    print(f"📄 共找到 {len(pdf_files)} 个PDF文件\n")    for i, filename in enumerate(pdf_files, 1):        input_path = os.path.join(INPUT_DIR, filename)        output_path = os.path.join(OUTPUT_DIR, filename)        try:            add_watermark(input_path, output_path, WATERMARK_TEXT)            print(f"✅ [{i}/{len(pdf_files)}] {filename} 处理成功")        except Exception as e:            print(f"❌ [{i}/{len(pdf_files)}] {filename} 处理失败:{e}")    print(f"\n🎉 全部完成!输出目录:{os.path.abspath(OUTPUT_DIR)}")if __name__ == "__main__":    batch_process()

四、效果展示

把需要处理的PDF丢进 ./pdfs 文件夹,运行脚本:

📄 共找到 5 个PDF文件✅ [1/5] 报告A.pdf 处理成功✅ [2/5] 报告B.pdf 处理成功✅ [3/5] 合同C.pdf 处理成功✅ [4/5] 简历D.pdf 处理成功✅ [5/5] 说明E.pdf 处理成功🎉 全部完成!输出目录:/Users/xxx/output

打开输出文件,每页都会带上倾斜45度的灰色半透明水印,既不影响阅读,又能起到标识作用。


五、进阶玩法

1. 平铺水印(铺满整页)

把 create_watermark_page 改成循环绘制:

def create_watermark_page(width, height, text):    packet = io.BytesIO()    can = canvas.Canvas(packet, pagesize=(width, height))    can.setFont("SimHei", FONT_SIZE)    can.setFillAlpha(OPACITY)    can.setFillColorRGB(0.5, 0.5, 0.5)    step_x, step_y = 250, 180  # 间距    for x in range(0, int(width) + step_x, step_x):        for y in range(0, int(height) + step_y, step_y):            can.saveState()            can.translate(x, y)            can.rotate(ANGLE)            can.drawString(0, 0, text)            can.restoreState()    can.save()    packet.seek(0)    return packet

2. 添加日期水印

from datetime import datetimetext = f"机密文件 {datetime.now().strftime('%Y-%m-%d')}"

3. 图片水印

用 drawImage 代替 drawString,即可插入Logo图片。


六、常见问题

Q1:中文显示成方框?

字体路径不对。Windows 用 C:/Windows/Fonts/simhei.ttf,Mac 用 /System/Library/Fonts/PingFang.ttc,Linux 可下载 simhei.ttf 放项目目录。

Q2:水印太深/太浅?

调整 OPACITY,建议 0.1~0.3。

Q3:加密PDF能处理吗?

先解密:reader.decrypt("密码")。

Q4:文件很大处理慢?

pypdf 比 PyPDF2 快,但超大文件建议用 pikepdf。


七、总结

今天我们用不到80行代码,实现了批量PDF加水印。核心就是生成水印页 + 合并页面,思路简单,效果拔群。

同样的方法还能扩展:

  • 批量加页码

  • 批量合并/拆分PDF

  • 批量提取文字

  • PDF转图片

把重复的事交给代码,把时间留给更重要的事。

相关学习资料