Python批量实现为PDF添加文字水印和图片印章

 更新时间:2026年09月22日 08:30:31   作者:大丸子  
本文将教你用Python配合FreeSpire.PDF批量处理PDF文件,实现文字水印平铺和图片印章叠加,样式统一又高效,包含详细代码和参数调优,轻松搞定内部资料禁止外传标识

文档在对外发送前加盖密级标识,是很多团队的例行动作:技术方案、报价单、合同附件发给客户或供应商之前,一般要加上"内部资料 禁止外传"一类的水印,或者盖上公司标识。一两份文件手工处理没有难度,文件一多就很难保证标识样式统一、每页覆盖完整。

用 Python 配合 Free Spire.PDF for Python 可以把这套 动作固化成脚本:文字水印用 PdfTilingBrush 在整页平铺,配合图形变换控制角度与透明度;图片印章叠加到页面画布上,以正片叠底混合压住正文而不影响阅读;批量处理则是在外层套一个文件循环。下面用一份 4 页的技术方案书和一份 1 页的报价单,把整套流程实现一遍。

本文使用的方法需要用到 Free Spire.PDF for Python,可通过 pip 安装:

pip install spire.pdf.free

Free 版单份文档以 10 页为限,加载与创建均适用。

1. 准备示例文档

先准备两份贴近实际业务的文档作为处理对象:一份技术方案书(每页一个小节,共 4 页),一份报价单(明细表格与合计,共 1 页)。两份文档均使用 Microsoft YaHei 并开启字体嵌入,保证在任何 PDF 阅读器中显示一致。

from spire.pdf.common import *
from spire.pdf import *

TITLE = PdfTrueTypeFont("Microsoft YaHei", 21.0, PdfFontStyle.Bold, True)
META = PdfTrueTypeFont("Microsoft YaHei", 10.5, PdfFontStyle.Regular, True)
HEAD = PdfTrueTypeFont("Microsoft YaHei", 14.0, PdfFontStyle.Bold, True)
BODY = PdfTrueTypeFont("Microsoft YaHei", 11.0, PdfFontStyle.Regular, True)

BLACK = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
GRAY = PdfSolidBrush(PdfRGBColor(Color.get_Gray()))
RULE = PdfSolidBrush(PdfRGBColor(Color.get_Silver()))
MARGIN = 60.0

def wrap(text, per_line=38):
    return [text[i:i + per_line] for i in range(0, len(text), per_line)]

def draw_para(page, text, y, leading=20.0):
    for line in wrap(text):
        page.Canvas.DrawString(line, BODY, BLACK, MARGIN, y)
        y += leading
    return y + 8.0

SECTIONS = [
    ("一、项目背景", [
        "本方案书面向星河集团数字化转型项目,围绕业务系统上云与统一运维平台建设提出整体技术设计。项目覆盖华东、华北、华南三个区域的数据中心,计划分三个阶段实施。",
        "现有系统采用分散部署模式,各业务线独立采购服务器与存储资源,资源利用率长期低于 40%,跨系统数据交换依赖人工导表,运维成本居高不下。本项目通过统一云平台实现资源集中管理、弹性调度与自动化运维。"]),
    ("二、总体架构", [
        "平台采用两地三中心部署架构:生产中心与同城灾备中心之间通过双活链路互联,异地灾备中心承担数据归档与灾难恢复职能。核心组件包括资源调度引擎、统一存储网关与运维监控平台。",
        "资源调度引擎负责容器化业务的编排与弹性伸缩;统一存储网关对接现有 SAN 存储与对象存储,向业务系统提供统一的存储接口;运维监控平台采集主机、网络与应用的运行指标,支持自定义告警规则与值班编排。"]),
    ("三、实施计划", [
        "第一阶段完成基础环境搭建与试点业务迁移,周期三个月;第二阶段完成核心业务系统迁移与数据同步机制建设,周期六个月;第三阶段开展全量业务迁移与运维体系交接,周期三个月。",
        "各阶段均设置里程碑评审点,由项目组与业务部门共同确认迁移范围与回退方案。关键路径上的资源采购与机房改造需在项目启动前完成招标流程,避免影响整体进度。"]),
    ("四、服务保障", [
        "项目交付后提供为期一年的运维支持,包含 7×24 小时故障响应、季度巡检与配置优化服务。运维团队常驻现场两名工程师,负责日常变更操作与事件处理。",
        "平台上线后按季度出具运行报告,内容涵盖资源使用率、故障统计与容量预测,作为后续扩容决策的依据。"]),
]

# 技术方案书:首页含标题与第一节,其余小节各占一页
doc = PdfDocument()
page = doc.Pages.Add()
page.Canvas.DrawString("星河云平台技术方案书", TITLE, BLACK, MARGIN, 90.0)
page.Canvas.DrawString("文档编号:XH-2026-014    编制日期:2026-09-21    密级:内部", META, GRAY, MARGIN, 132.0)
page.Canvas.DrawRectangle(RULE, RectangleF(PointF(MARGIN, 152.0), SizeF(page.Canvas.ClientSize.Width - 2 * MARGIN, 1.2)))
y = 190.0
head, paras = SECTIONS[0]
page.Canvas.DrawString(head, HEAD, BLACK, MARGIN, y)
y += 30.0
for p in paras:
    y = draw_para(page, p, y)
for head, paras in SECTIONS[1:]:
    page = doc.Pages.Add()
    y = 90.0
    page.Canvas.DrawString(head, HEAD, BLACK, MARGIN, y)
    y += 30.0
    for p in paras:
        y = draw_para(page, p, y)
doc.SaveToFile("技术方案书.pdf")
doc.Close()

# 报价单:标题、明细表与合计
doc2 = PdfDocument()
page = doc2.Pages.Add()
page.Canvas.DrawString("项目报价单", TITLE, BLACK, MARGIN, 90.0)
page.Canvas.DrawString("报价单号:XH-QT-2026-021    日期:2026-09-21", META, GRAY, MARGIN, 132.0)
page.Canvas.DrawRectangle(RULE, RectangleF(PointF(MARGIN, 152.0), SizeF(page.Canvas.ClientSize.Width - 2 * MARGIN, 1.2)))

cols = [60.0, 115.0, 340.0, 400.0, 480.0]
headers = ["序号", "设备名称", "数量", "单价(元)", "金额(元)"]
rows = [
    ("1", "云平台管理节点", "2", "86,000", "172,000"),
    ("2", "计算节点", "12", "58,000", "696,000"),
    ("3", "分布式存储节点", "6", "92,000", "552,000"),
    ("4", "网络交换机", "8", "23,000", "184,000"),
]
TH = PdfTrueTypeFont("Microsoft YaHei", 11.0, PdfFontStyle.Bold, True)
y = 195.0
for x, h in zip(cols, headers):
    page.Canvas.DrawString(h, TH, BLACK, x, y)
page.Canvas.DrawRectangle(RULE, RectangleF(PointF(MARGIN, y + 18.0), SizeF(page.Canvas.ClientSize.Width - 2 * MARGIN, 1.2)))
y += 36.0
for row in rows:
    for x, v in zip(cols, row):
        page.Canvas.DrawString(v, BODY, BLACK, x, y)
    y += 28.0
page.Canvas.DrawRectangle(RULE, RectangleF(PointF(MARGIN, y + 2.0), SizeF(page.Canvas.ClientSize.Width - 2 * MARGIN, 1.2)))
y += 20.0
page.Canvas.DrawString("合计金额", TH, BLACK, 400.0, y)
page.Canvas.DrawString("1,604,000", TH, BLACK, 480.0, y)
y += 48.0
page.Canvas.DrawString("本报价含三年原厂质保,报价有效期 30 天。", META, GRAY, MARGIN, y)
doc2.SaveToFile("报价单.pdf")
doc2.Close()

画布坐标以页面左上角为原点,页面可用宽度通过 page.Canvas.ClientSize.Width 获取,正文左右各留 60pt 边距。DrawString 不自动换行,段落需要先按每行 38 个字符折行(wrap 函数),再逐行递增 y 坐标输出;小节之间的分隔线用高 1.2pt 的浅色矩形绘制。

生成的技术方案书(第 1 页)如下,报价单的结构与明细在批量处理一节中展示:

Python 生成的示例文档:技术方案书第 1 页

2. 全页文字水印

平铺水印的核心是 PdfTilingBrush——一块尺寸固定的"画刷 单元",会被重复填充到目标区域。单元尺寸决定水印密度:设为页宽的一半、页高的三分之一,整页大约落入 6 处完整的文字。文字不直接画在页面上,而是先画在单元的图形对象上:把原点平移到单元中心并旋转 -30°,再以居中对齐输出文字,最后让整块单元作为画刷铺满整个页面。透明度取 0.22,屏幕上清晰可见,同时不干扰正文阅读。

PHRASE = "内部资料 禁止外传"
FONT = PdfTrueTypeFont("Microsoft YaHei", 22.0, PdfFontStyle.Regular, True)
BRUSH = PdfSolidBrush(PdfRGBColor(Color.get_DarkRed()))
def add_text_watermark(pdf_path, out_path, phrase, font, brush, opacity=0.22, angle=-30.0):
    doc = PdfDocument()
    doc.LoadFromFile(pdf_path)
    for i in range(doc.Pages.Count):
        page = doc.Pages[i]
        tile = PdfTilingBrush(SizeF(page.Canvas.ClientSize.Width / 2.0, page.Canvas.ClientSize.Height / 3.0))
        g = tile.Graphics
        g.SetTransparency(opacity)
        g.Save()
        g.TranslateTransform(tile.Size.Width / 2.0, tile.Size.Height / 2.0)
        g.RotateTransform(angle)
        g.DrawString(phrase, font, brush, 0.0, 0.0, PdfStringFormat(PdfTextAlignment.Center))
        g.Restore()
        g.SetTransparency(1.0)
        page.Canvas.DrawRectangle(tile, RectangleF(PointF(0.0, 0.0), page.Canvas.ClientSize))
    n = doc.Pages.Count
    doc.SaveToFile(out_path)
    doc.Close()
    return n
add_text_watermark("技术方案书.pdf", "技术方案书_文字水印.pdf", PHRASE, FONT, BRUSH)

函数对文档的每一页执行同样的填充,多页文档的水印角度、间距、透明度因此完全一致,页与页之间不会错位。文案、字体、颜色都通过参数传入,同一方法可以换成其他密级表述,例如"样品 请勿传播"或"仅供评审使用"。

处理后的效果(以第 2 页为例):

Python 为 PDF 添加文字平铺水印的效果

3. 图片印章

图片印章用于加盖公司标识一类的图形。做法很直接:加载 PNG 标识,等比缩放到页宽的 62% 并居中,叠加绘制到每一页上。关键在于透明度与混合方式——以正片叠底(Multiply)和 0.16 的透明度绘制时,标识图片中的白色区域相当于"透明",只有笔画把页面像素加深,因此印章压在正文上时两侧都保持可读,不会出现一块突兀的底色。

LOGO = "水印素材_星河科技.png"

doc = PdfDocument()
doc.LoadFromFile("技术方案书.pdf")
pdf_image = PdfImage.FromFile(LOGO)
for i in range(doc.Pages.Count):
    page = doc.Pages[i]
    w = page.Canvas.ClientSize.Width * 0.62
    h = w * pdf_image.Height / pdf_image.Width
    x = (page.Canvas.ClientSize.Width - w) / 2.0
    y = (page.Canvas.ClientSize.Height - h) / 2.0
    page.Canvas.Save()
    page.Canvas.SetTransparency(0.16, 0.16, PdfBlendMode.Multiply)
    page.Canvas.DrawImage(pdf_image, x, y, w, h)
    page.Canvas.Restore()
doc.SaveToFile("技术方案书_图片印章.pdf")
doc.Close()

Save / Restore 把混合设置的作用范围限制在印章绘制之内,不影响画布上的其他内容。示例标识是一张白底的 1200×420 PNG,替换成公司实际图片时只需调整缩放比例,其余代码不用改动。

叠加印章后的效果:

Python 为 PDF 添加图片印章水印的效果

4. 批量处理

把单个文件的处理逻辑放进循环,即可批量处理一批文档。下面的脚本复用前面的 add_text_watermark 函数,将结果统一输出到"批量输出"目录,原始文件保持不变:

import os

OUT_DIR = "批量输出"
os.makedirs(OUT_DIR, exist_ok=True)

FILES = ["技术方案书.pdf", "报价单.pdf"]

for name in FILES:
    n = add_text_watermark(name, os.path.join(OUT_DIR, name), PHRASE, FONT, BRUSH)
    print("已处理: %s -> 批量输出/(%d 页)" % (name, n))

print("批量处理完成,共 %d 个文件。" % len(FILES))

运行输出:

已处理: 技术方案书.pdf -> 批量输出/(4 页)
已处理: 报价单.pdf -> 批量输出/(1 页)
批量处理完成,共 2 个文件。

批量输出目录中的报价单——明细表格、合计金额与有效期说明均保持原样,水印覆盖每一页:

Python 批量加水印后的报价单

5. 参数与说明

透明度与颜色按实际场景微调:文字水印 0.2–0.3、图片印章 0.12–0.2 是兼顾清晰度与可读性的区间,颜色建议选深红、灰蓝一类的低饱和色,打印成黑白稿时仍有足够对比度。

字体方面,示例使用系统字体家族名加载(Microsoft YaHei),第四个参数 embed=True 会把字体子集嵌入 PDF,不受目标机器字体环境影响。改用字体文件路径加载时,需指向单体 .ttf 文件——.ttc 字体集合文件不被支持。

批量处理前建议先用 doc.Pages.Count 检查页数;超过 Free 版 10 页上限的文档需要商业版支持。

最后一点是定位问题:水印解决的是"标识与溯源",本身不提供防篡改能力。对文档真实性有要求的场景(合同、投标文件),可以在水印之外叠加数字签名与访问权限控制,两者并不冲突。

至此,从文档生成、文字水印、图片印章到批量输出已成一条完整流程,脚本除 Spire.PDF 外没有其他依赖,可以直接嵌入文件发送前或归档时的处理环节。

以上就是Python批量实现为PDF添加文字水印和图片印章的详细内容,更多关于Python PDF添加水印的资料请关注脚本之家其它相关文章!

相关文章

  • Python爬虫回测股票的实例讲解

    Python爬虫回测股票的实例讲解

    在本篇文章里小编给大家整理的是一篇关于Python爬虫回测股票的实例讲解内容,有兴趣的朋友们可以学习下。
    2021-01-01
  • python中delattr删除对象方法的代码分析

    python中delattr删除对象方法的代码分析

    在本篇文章里小编给大家分享了一篇关于python中delattr删除对象方法的代码分析内容,有兴趣的朋友们可以学习下。
    2020-12-12
  • 用Python将PDF文件转存为图片的实现方法

    用Python将PDF文件转存为图片的实现方法

    在Python中,将PDF文件转换为图片格式使用专门的库来处理PDF文档,并将其每一页导出为常见的图像格式,这可以通过PyMuPDF库中的fitz模块或pdf2image库实现,本文给大家介绍了用Python将PDF文件转存为图片的方法,需要的朋友可以参考下
    2024-04-04
  • Python办公自动化之批量将PDF转换为图片文件

    Python办公自动化之批量将PDF转换为图片文件

    在日常办公中,我们经常需要批量将PDF转换为图片文件,本文教你用Python的PyMuPDF库一键批量将PDF转为高清PNG图片,让你轻松搞定办公自动化
    2026-08-08
  • OpenCV-Python实现人脸磨皮算法

    OpenCV-Python实现人脸磨皮算法

    人脸磨皮是最基础的人脸美颜效果。本文介绍了OpenCV-Python实现人脸磨皮算法,主要包括图像滤波,图像融合和图像锐化,感兴趣的可以了解一下
    2021-06-06
  • 小白学Python之实现OCR识别

    小白学Python之实现OCR识别

    将图片翻译成文字一般被称为光学文字识别(Optical Character Recognition,OCR),这篇文章主要给大家介绍了关于Python实现OCR识别的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-08-08
  • Python轻松读写TOML文件实现示例

    Python轻松读写TOML文件实现示例

    这篇文章主要介绍了Python轻松读写TOML文件实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Selenium鼠标与键盘事件常用操作方法示例

    Selenium鼠标与键盘事件常用操作方法示例

    这篇文章主要介绍了Selenium鼠标与键盘事件常用操作方法,结合实例形式分析了Selenium鼠标事件与键盘事件常见方法与相关使用技巧,需要的朋友可以参考下
    2018-08-08
  • python 实时遍历日志文件

    python 实时遍历日志文件

    这篇文章主要介绍了python 实时遍历日志文件 的相关资料,需要的朋友可以参考下
    2016-04-04
  • Python Ast抽象语法树的介绍及应用详解

    Python Ast抽象语法树的介绍及应用详解

    这篇文章主要为大家介绍了Python Ast抽象语法树的介绍及应用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07

最新评论