PDF 合并+添加页码 相关库、类、函数

PDF 合并加页码代码一共使用 PyPDF2、reportlab 两个第三方库,搭配 Python 内置io内存流、os文件库。

1 库总览

表格

|-------------------------|-------------------------------------|
| 库 | 作用 |
| PyPDF2 | PDF 读取、合并、页面叠加、写出 PDF 文件,处理已有 PDF |
| reportlab.pdfgen.canvas | 生成全新 PDF 图层(页码图层),绘制文字、字体,用来生成页码水印页 |
| io.BytesIO | 内存字节流,全部 PDF 操作在内存完成,不生成临时磁盘 PDF 文件 |
| os | 文件夹遍历、拼接文件路径、判断文件是否存在 |
| re | 文件名数字排序正则,和 PDF 编辑无关 |


2 PyPDF2 核心类 & 函数解析

① PdfMerger()

merger = PdfMerger()

merger.append(file)

merger.write(temp_memory)

merger.close()

PdfMerger:专门用于 PDF 合并的工具类

.append(file):追加一个 PDF 文件,按调用顺序把 PDF 全部拼在一起;支持磁盘路径 / 内存 BytesIO 对象

.write(temp_memory):将合并完成的完整 PDF 写入字节流(这里没有写磁盘,写到内存)

.close():关闭 merger,释放文件资源

② PdfReader()

merged_pdf = PdfReader(temp_memory)

num_layer = PdfReader(buf)

src_page = merged_pdf.pagesindex

PdfReader:读取 PDF 对象,可以读磁盘文件,也可以直接读 BytesIO 内存流

.pagesindex:PDF 所有页面列表,下标从 0 开始,获取第 index 页页面对象

src_page.mediabox:页面画布边界对象,.width、.height获取 PDF 页面宽高(新版本返回 Decimal,代码中强制float()转换)

③ PdfWriter()

pdf_writer = PdfWriter()

pdf_writer.add_page(src_page)

pdf_writer.write(f)

PdfWriter:用来组装、输出最终 PDF 的写入器

.add_page(src_page):把处理完成的一页加入输出队列

.write(f):把全部页面写入打开的磁盘二进制文件句柄,生成最终 pdf

④ 关键函数 src_page.merge_page(num_layer.pages0)

实现页码叠加的核心函数

src_page.merge_page(num_layer.pages0)

作用:把一个 PDF 页面图层叠加到当前页面上

逻辑:reportlab 生成只有页码的空白 PDF 页num_layer.pages0,叠加到原始 PDF 页面src_page底部,实现页码水印效果。

⚠注意:是图层叠加,不是修改原 PDF 文本;页码是画上去的图形文字。


3 reportlab 库(生成页码图层)

from reportlab.pdfgen import canvas

c = canvas.Canvas(buf, pagesize=(w, h))

c.setFont("Helvetica", font_size)

c.drawCentredString(w / 2, page_bottom_margin, page_text)

c.save()

canvas.Canvas(buf, pagesize=(w, h))

创建一个 PDF 画布对象,输出目标是内存buf(BytesIO),设置页面尺寸和原 PDF 页面宽高保持一致

.font("Helvetica", font_size)

设置画布绘制文字的字体、字号;你后续改成 Times New Roman 就修改这里字体名

.drawCentredString(x, y, text)

绘制居中文字

x:水平坐标;w/2就是页面水平中点

y:垂直坐标,PDF 坐标原点在页面左下角!! y=0 就是最底边;page_bottom_margin=20就是距离底边 20pt 的位置画页码

.save()

将画布内容输出到 BytesIO,完成页码图层 PDF 生成。

PDF 坐标关键点:

原点 (0,0):页面左下角

单位:pt(磅),1 英寸 = 72pt

4 io.BytesIO 内存流(非常关键)

temp_memory = io.BytesIO()

buf = io.BytesIO()

temp_memory.seek(0)

buf.seek(0)

BytesIO:内存里面的二进制文件,完全不读写磁盘

流程:

PdfMerger 合并 PDF → 写入temp_memory内存

seek(0):指针移动回到字节流开头,后面PdfReader才能从头读取内容

reportlab 生成页码图层写入buf内存流,再 seek (0) 供 PdfReader 读取

好处:全程无临时中间 PDF 文件,速度快;缺点大文件会占用内存。

5 整体完整数据流

磁盘多个PDF文件 → PdfMerger合并 → BytesIO内存合并PDF

→ PdfReader读取合并好的PDF,循环每一页

reportlab Canvas(内存buf)生成只有页码的透明图层

merge_page() 将页码图层叠加原始PDF页面

PdfWriter收集全部叠加完页码的页面

→ write()写入磁盘输出文件【合并带页码.pdf】

补充:代码中两个模式说明

custom_file_list != None:手动指定文件名列表,严格按照列表顺序合并,只合并列表中写的 PDF;会校验文件是否存在。

custom_file_list = None:扫描文件夹全部.pdf文件,使用 sort_key 自定义排序。

常见坑总结

PyPDF2 新版本mediabox.width返回 Decimal 类型,和 reportlab float 运算报错,所以代码用float()强制转换。

reportlab 画布坐标原点左下角,y 值越小越靠近底边,太小会被 PDF 阅读器裁切。

merge_page是图层叠加,页码属于图形对象,不是 PDF 文本对象,不能复制选中页码文字。

reportlab 默认字体 Helvetica 不支持中文,需要注册 TTF 字体(Times New Roman / 中文字体)。

相关推荐
不正经学生15 小时前
C语言预处理详解:编译器真正动手之前的那些事
c语言·开发语言·算法·面试·bug
门思科技15 小时前
LoRaWAN 设备类别:Class A、B、C 对比与选型指南
c语言·开发语言·php
ℋᙚᵐⁱᒻᵉ鲸落17 小时前
移动端滑动手势冲突:overflow: auto导致外层横向滑动失效
前端·javascript·css·vue.js·html
恋恋西风18 小时前
C++ 理解 std::thread 在单核和多核上的行为差异
开发语言·c++
Brilliantwxx18 小时前
【Linux】 进程(9)程序与进程地址空间(基础+进阶+面试题)
linux·运维·服务器·开发语言·c++
BizzZ_18 小时前
C++(22)——类型转换和IO流
开发语言·c++
默_笙18 小时前
🎃 前端学了 Next.js,后端该学啥?NestJS 就是 Node 版的蜜雪冰城
前端·javascript
小范同学_18 小时前
JDK1.7 与 JDK1.8 HashMap 底层原理对比 + 数组并发扩容死循环详解
java·开发语言
geovindu19 小时前
CSharp: 万年历
开发语言·后端·c#·.net
傲笑风19 小时前
【openvino】tinybert基于openvino服务化部署(四)
人工智能·python·自然语言处理·nlp·bert·openvino