如何在 Python 中处理 PDF 注释
Aspose.PDF FOSS for Python 将页面上的每个注释通过页面的 AnnotationCollection 公开为实时的 Annotation 对象,因而您可以添加标记、链接和 3D 注释,检查它们的特定类型属性,并生成 PDF 查看器渲染所需的外观流——全部使用纯 Python。本指南展示了如何安装库、添加注释、读取注释以及生成它们的外观流。
分步指南
步骤 1:安装包
安装 Aspose.PDF FOSS 包:
git clone https://github.com/aspose-pdf-foss/Aspose-PDF-FOSS-for-Python.git
cd Aspose-PDF-FOSS-for-Python
pip install -e .通过导入顶层的 aspose_pdf 模块来验证安装,该模块公开了下面步骤中使用的 Document 类。导入成功时,代码片段会打印 aspose_pdf OK;如果出现 ModuleNotFoundError,通常意味着该包被安装在与运行脚本的 Python 环境不同的环境中:
import aspose_pdf
print("aspose_pdf OK")步骤 2:导入所需类
导入 Document 以保存 PDF,并导入您将用于创建和检查批注的批注类:
from aspose_pdf import Document
from aspose_pdf.annotations import (
Annotation,
AnnotationType,
AnnotationFlags,
MarkupAnnotation,
LinkAnnotation,
)步骤 3:向页面添加批注
每个 Page 都通过 annotations 属性(一个 AnnotationCollection)公开其批注。调用 add(subtype, rect, contents) 时提供子类型名称、一个 (left, bottom, right, top) 矩形以及批注的文本内容。诸如 "Highlight" 等标准标记子类型将作为 MarkupAnnotation 实例返回:
from aspose_pdf import Document
document = Document()
document.pages.add()
page = document.pages[0]
annotation = page.annotations.add(
"Highlight",
(100, 700, 300, 720),
"Key clause",
)
print(type(annotation).__name__) # MarkupAnnotation
print(annotation.contents) # Key clause步骤 4:从枚举子类型创建批注
AnnotationType 枚举了所有标准 PDF 批注子类型(PDF 32000-1:2008,表 169),因此您可以传递枚举成员而不是原始字符串。特定类型的数据——例如多边形的顶点——放在 properties 字典中,并通过 get_property 读取回:
from aspose_pdf import Document
from aspose_pdf.annotations import AnnotationType
document = Document()
document.pages.add()
page = document.pages[0]
annotation = page.annotations.add(
AnnotationType.POLYGON,
(0, 0, 10, 10),
"",
properties={"Vertices": [0, 0, 10, 0, 5, 10]},
)
print(annotation.subtype) # Polygon
print(annotation.get_property("Vertices")) # [0, 0, 10, 0, 5, 10]步骤 5:读取并遍历现有批注
AnnotationCollection 是可迭代的,因此您可以遍历页面上已有的每个批注——包括从现有 PDF 加载的批注——并读取每个 Annotation 所公开的通用属性(subtype、contents、rect、title、author、color):
from aspose_pdf import Document
document = Document()
document.pages.add()
page = document.pages[0]
page.annotations.add("Text", (50, 50, 70, 70), "First note")
page.annotations.add("Text", (80, 80, 100, 100), "Second note")
for annotation in page.annotations:
print(annotation.subtype, "-", annotation.contents)步骤 6:生成注释外观流
未显式提供 appearance_normal 的注释在生成之前没有可见的渲染(/AP /N)。对单个 Annotation 调用 generate_appearance(force),或对整个 AnnotationCollection 调用 generate_appearances(force),即可一次性合成页面上所有缺失的外观流:
from aspose_pdf import Document
from aspose_pdf.engine.cos import AnnotationName
document = Document()
document.pages.add()
page = document.pages[0]
stamp = page.annotations.add(
"Stamp",
(100, 100, 260, 150),
"",
properties={"Name": AnnotationName("Approved")},
)
if stamp.generate_appearance():
print(f"Appearance stream: {len(stamp.appearance_normal)} byte(s)")
# Regenerate every missing appearance stream on the page in one call:
count = page.annotations.generate_appearances(force=True)
print(f"Regenerated {count} appearance stream(s)")步骤 7:区分注释子类
AnnotationCollection.add() 根据子类型分派到特定子类:标记式子类型(Highlight、Square、Stamp 等)返回为 MarkupAnnotation,而 "Link" 返回为 LinkAnnotation。两者都继承自 Annotation 的所有方法和属性,因此 isinstance 检查允许你在不直接检查 subtype 字符串的情况下,根据注释类型进行分支:
from aspose_pdf import Document
from aspose_pdf.annotations import LinkAnnotation, MarkupAnnotation
document = Document()
document.pages.add()
page = document.pages[0]
link = page.annotations.add("Link", (50, 750, 200, 770), "")
highlight = page.annotations.add("Highlight", (50, 700, 200, 720), "")
print(isinstance(link, LinkAnnotation)) # True
print(isinstance(highlight, MarkupAnnotation)) # True常见问题与解决方案
get_property returns None 对于我刚刚设置的属性
properties 键必须完全匹配,区分大小写的 PDF 字段名("Vertices"、"Name" 等)——拼写错误或大小写不对会被静默忽略,而不会抛出错误。向 get_property(name, default) 传入 default 参数,并在调试新子类型时显式检查它。
generate_appearance() returns False
并非所有子类型和属性的组合都能由内置生成器合成为外观流。在假设调用成功之前请检查 has_appearance,并为生成器未覆盖的子类型直接在 add() 上提供预渲染的 appearance_normal(bytes)。
意外的注释子类之后 add()
您传入的子类型字符串(或 AnnotationType 成员)决定返回的类:标记子类型返回为 MarkupAnnotation,"Link" 返回为 LinkAnnotation,其他任何已识别的子类型返回为基础的 Annotation。请对 MarkupAnnotation/LinkAnnotation 使用 isinstance(),而不要假设特定的子类型字符串。
AnnotationFlags 值似乎没有改变渲染
AnnotationFlags(PRINT、HIDDEN、NO_ZOOM、READ_ONLY 等)是一个标准的 Python IntFlag 枚举,用于通过 | 运算符组合和解释注释的行为位——它是值类型,而不是 Annotation.add() 自动写入的属性。将所需的标志组合起来,并通过用于其他子类型特定数据的相同类型特定 properties 机制传递它们。
处理尚未有注释的页面
page.annotations 始终是有效的(可能为空的)AnnotationCollection——在调用 add()、遍历或调用 clear() 之前,您永不需要检查 None。
常见问题
Aspose.PDF FOSS for Python 支持哪些注释子类型?
AnnotationType 枚举了 PDF 32000-1:2008 表 169 中的全部 25 种标准子类型,包括 TEXT、LINK、FREE_TEXT、LINE、SQUARE、CIRCLE、POLYGON、HIGHLIGHT、STAMP、INK、FILE_ATTACHMENT、REDACT,以及更多。
这个库支持 3D 注释吗?
是的。 PDF3DAnnotation,以及 PDF3DArtwork, PDF3DContent, PDF3DView, PDF3DLightingScheme,并且 PDF3DRenderMode,为预发布 PDF 3D 工作流建模了一个最小的 PDF 3D 注释表面(一个矩形、嵌入式艺术作品和命名视图)。参见 PDF3DAnnotation 参考 用于其完整属性集。
如何从页面中删除注释?
调用 page.annotations.delete(index) 按位置删除单个注释,或调用 page.annotations.clear() 删除页面上的所有注释。
我可以在特定位置插入注释,而不是追加吗?
是的 — AnnotationCollection.insert(index, subtype, rect, contents, title, appearance_normal, properties) 接受与 add() 相同的参数,并额外接受目标 index。
注释的颜色是如何表示的?
在 Annotation(及其子类)上的 color 属性是一个 tuple[float, ...],其匹配 PDF /C 条目的组件计数(当颜色未设置时为空)——而不是专用的颜色对象。