在处理 pdf 文档时,我们经常需要附带一些补充文件。例如,项目报告中需要包含生成图表的原始 excel 表格,发票中需要附带行程凭证,或者技术文档中需要提供 json 配置文件和日志。如果将这些文件单独分发,不仅管理起来比较繁琐,接收方也容易遗漏。
将补充文件直接嵌入 pdf,是解决这一问题的一种常用方式。
在 pdf 中,添加附件主要有两种形式:
- 文档级附件
- 附件注释
本文将演示如何使用 python 实现这两种附件嵌入方式。
两种附件形式的区别与适用场景
在开始编写代码之前,可以先根据附件与正文之间的关系判断应该使用哪一种方式:
1.文档级附件(document-level attachment)
属于整个 pdf 文档,不会改变页面原有的版面。用户使用 pdf 阅读器打开文档时,可以通过“附件”面板查看和导出这些文件。这种方式适用于与整份文档相关的补充材料,如数据表、附录、环境配置文件等。
2.附件注释(attachment annotation)
与页面上的特定位置关联,并以可视、可点击的附件图标显示。这种方式适用于与具体正文内容直接相关的材料。例如,在分析图表旁放置对应的数据源,或者在某段内容旁提供相关的原始文件。
选择原则:不需要在页面中体现位置关系的补充文件,可以使用文档级附件;需要与特定段落、图片或图表建立上下文对应关系时,则更适合使用附件注释。
环境设置
要运行下面的代码示例,需要先安装 pdf 处理所需的 python 模块:
pip install spire.pdf
然后导入示例中需要使用的类:
from spire.pdf import * from spire.pdf.common import *
方法一:添加文档级附件
将文件添加为文档级附件时,文件会被加入 pdf 的文档附件集合中,不会修改任何页面内容。
1. 添加单个附件
下例演示如何将 excel 数据文件嵌入一份 pdf 报告中:
from spire.pdf import *
from spire.pdf.common import *
# 创建 pdfdocument 对象并加载源文档
pdf = pdfdocument()
pdf.loadfromfile("report.pdf")
# 创建附件对象
attachment = pdfattachment("source-data.xlsx")
# 将附件添加到文档附件集合中
pdf.attachments.add(attachment)
# 保存更新后的 pdf 文档
pdf.savetofile("report-with-attachment.pdf")
pdfattachment 用于根据外部文件创建附件对象,然后通过 attachments.add() 将其加入 pdf 的附件集合。
保存后的 pdf 页面不会发生变化。使用支持 pdf 附件的阅读器打开文件后,可以从附件面板中查看并打开 source-data.xlsx。
2. 添加多个附件
如果需要将多个相关文件随 pdf 一起发布,可以分别创建 pdfattachment 对象并添加到文档中:
# 创建多个附件
attachment1 = pdfattachment("source-data.xlsx")
attachment2 = pdfattachment("meeting-notes.docx")
attachment3 = pdfattachment("architecture.png")
# 添加到文档附件集合
pdf.attachments.add(attachment1)
pdf.attachments.add(attachment2)
pdf.attachments.add(attachment3)
如果附件数量较多,也可以通过列表和循环处理:
attachment_files = [ "source-data.xlsx", "meeting-notes.docx", "architecture.png"]
for file in attachment_files:
pdf.attachments.add(pdfattachment(file))
这样可以把 pdf 和相关资料统一保存在同一个文件中,同时不会改变正文页面原有的布局。
需要注意的是,附件文件会实际写入 pdf,因此附件越大、数量越多,最终生成的 pdf 文件体积也会相应增加。
方法二:在指定页面添加附件注释
当附件需要与页面中的某个具体元素,例如表格、图片、图表或段落对应时,可以使用附件注释。
1. 基本实现代码
创建附件注释时,需要指定它在页面中的位置区域(rectanglef),并传入需要嵌入的文件数据流(stream):
from spire.pdf import *
from spire.pdf.common import *
pdf = pdfdocument()
pdf.loadfromfile("report.pdf")
# 获取目标页面(这里为第 1 页,索引从 0 开始)
page = pdf.pages.get_item(0)
# 读取附件文件
data_stream = stream("source-data.xlsx")
# 设置图标在页面上的位置和尺寸
# 参数依次为:x 坐标、y 坐标、宽度、高度
bounds = rectanglef(50.0, 100.0, 16.0, 16.0)
# 创建附件注释
annotation = pdfattachmentannotation(
bounds,
"source-data.xlsx",
data_stream
)
# 设置外观和提示文字
annotation.color = pdfrgbcolor(color.get_blue())
annotation.flags = pdfannotationflags.default
annotation.icon = pdfattachmenticon.graph
annotation.text = "双击打开原始数据表格"
# 将附件注释添加到页面
page.annotationswidget.add(annotation)
pdf.savetofile("report-with-page-attachment.pdf")
这里最关键的是:
bounds = rectanglef(50.0, 100.0, 16.0, 16.0)
四个参数分别表示附件图标的 x 坐标、y 坐标、宽度和高度。
另外:
page = pdf.pages.get_item(0)
获取的是 pdf 的第一页,因为页面索引从 0 开始。如果要把附件添加到其他页面,需要根据实际页码调整索引值。
2. 常见的附件图标样式
pdfattachmenticon 提供了多种附件注释的内置图标样式。
这些枚举值只影响附件图标的显示形式,并不会限制附件实际可以使用的文件类型。
| 枚举值 | 图标样式 |
|---|---|
pdfattachmenticon.graph | 图表样式 |
pdfattachmenticon.paperclip | 回形针样式 |
pdfattachmenticon.pushpin | 图钉样式 |
pdfattachmenticon.tag | 标签样式 |
可以根据页面内容和附件用途选择合适的图标。例如:
annotation.icon = pdfattachmenticon.paperclip
进阶运用:为附件图标配上文字说明
孤零零放一个 16x16 像素的附件小图标,读者可能不知道干嘛用的。我们可以在画布上直接画一行引导文字,再根据文字宽度将附件图标放置在文字后面:
# 1. 在页面 canvas 上绘制提示文字
label_text = "附件:生成该图表对应的原始数据"
font = pdftruetypefont("arial", 10.0, pdffontstyle.regular, true)
x_pos = 50.0
y_pos = 150.0
page.canvas.drawstring(
label_text,
font,
pdfbrushes.get_black(),
x_pos,
y_pos
)
# 2. 获取文字实际宽度
text_width = font.measurestring(label_text).width
# 3. 将附件图标放在文字右侧 5 点的位置
icon_bounds = rectanglef(
x_pos + text_width + 5.0,
y_pos,
16.0,
16.0
)
# 4. 创建并添加附件注释
annotation = pdfattachmentannotation(
icon_bounds,
"source-data.xlsx",
data_stream
)
annotation.icon = pdfattachmenticon.paperclip
page.annotationswidget.add(annotation)
最终页面上的效果可以理解为:
附件:生成该图表对应的原始数据 📎
这里没有直接写死附件图标的 x 坐标,而是先通过:
font.measurestring(label_text).width
获取文字实际占用的宽度,再计算图标的位置。如果提示文字发生变化,图标仍然可以自动保持在文字后方。这种方式比固定坐标更适合动态生成的 pdf 文档。
补充操作:提取 pdf 中的文档级附件
在自动化处理流程中,除了向 pdf 中写入附件,有时还需要读取已经存在的文档级附件,并将它们保存到本地。
from spire.pdf import *
from spire.pdf.common import *
pdf = pdfdocument()
pdf.loadfromfile("report-with-attachment.pdf")
# 遍历文档级附件
for i in range(pdf.attachments.count):
attachment = pdf.attachments.get_item(i)
# 将附件保存到本地
with open(attachment.filename, "wb") as f:
f.write(attachment.data)
pdf.close()
这里访问的 pdf.attachments 是 pdf 的文档级附件集合。
需要注意的是,通过附件注释嵌入的文件属于页面注释,并不包含在这个集合中。如果需要读取页面上的附件注释,则需要进一步遍历相应页面的注释集合。
阅读器兼容性说明
附件成功写入 pdf 后,实际的查看和交互体验还会受到 pdf 阅读器的影响。
- 桌面端 pdf 阅读器,如 adobe acrobat reader、foxit pdf reader 等:一般能够较完整地显示文档级附件面板,并支持页面上的附件注释。
- 浏览器内置 pdf 查看器,如 chrome、edge、firefox 等:主要用于显示 pdf 页面内容,对附件面板和附件注释等交互功能的支持可能有所不同。有些情况下,用户可能无法像在桌面阅读器中一样直接访问附件。
因此,如果附件属于业务流程中的关键文件,例如财务凭证、合同附件、审计资料或项目交付文件,最好在正式交付前使用接收方实际可能使用的 pdf 阅读器进行测试。
总结
使用 python 给 pdf 添加附件时,主要需要根据附件与正文内容之间的关系选择合适的方式:
- 如果文件与整份 pdf 相关,并且不需要在页面中体现具体位置,可以使用 文档级附件;
- 如果文件与正文中的某个图表、图片或段落直接相关,可以使用 附件注释,并将附件图标放在对应内容附近。
两种方式都可以将外部文件直接嵌入 pdf,但在文档结构和阅读方式上各有侧重。实际使用时,只需要判断附件属于整份文档,还是与某个具体页面内容相关,再选择相应的实现方式即可。
到此这篇关于python给pdf添加文档附件与附件注释的详细教程的文章就介绍到这了,更多相关python pdf添加附件内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论