如何使用 Python 给 PDF 添加附件:文档附件与附件注释

如何使用 Python 给 PDF 添加附件:文档附件与附件注释 在处理 PDF 文档时我们经常需要附带一些补充文件。例如项目报告中需要包含生成图表的原始 Excel 表格发票中需要附带行程凭证或者技术文档中需要提供 JSON 配置文件和日志。如果将这些文件单独分发不仅管理起来比较繁琐接收方也容易遗漏。将补充文件直接嵌入 PDF是解决这一问题的一种常用方式。在 PDF 中添加附件主要有两种形式文档级附件附件注释本文将演示如何使用 Python 实现这两种附件嵌入方式。两种附件形式的区别与适用场景在开始编写代码之前可以先根据附件与正文之间的关系判断应该使用哪一种方式文档级附件Document-Level Attachment属于整个 PDF 文档不会改变页面原有的版面。用户使用 PDF 阅读器打开文档时可以通过“附件”面板查看和导出这些文件。这种方式适用于与整份文档相关的补充材料如数据表、附录、环境配置文件等。附件注释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并传入需要嵌入的文件数据流Streamfrom 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但在文档结构和阅读方式上各有侧重。实际使用时只需要判断附件属于整份文档还是与某个具体页面内容相关再选择相应的实现方式即可。