如何在 C++ 中使用 PDF 注释

如何在 C++ 中使用 PDF 注释

Aspose.PDF FOSS for C++ 将每个 PDF 注释表示为通用 Annotation 基类的子类,并通过 Page::Annotations() 返回的 AnnotationCollection 在页面上公开这些注释。本指南使用 TextAnnotation 向页面添加纯文本注释和样式化注释,保存文档,然后重新打开以读取注释并移除其中一个。该库作为子目录依赖集成到 CMake 项目中——没有包注册表安装步骤。

分步指南

步骤 1:安装包

将库添加为 CMake 子目录并链接静态库目标:

add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)

验证工具链和链接步骤在最小程序中正确解析:

#include <aspose/pdf/document.hpp>
#include <iostream>

int main() {
    Aspose::Pdf::Document doc;
    std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}

成功构建并打印 pages: 0 表明库已链接。


步骤 2:导入必需的类

#include <aspose/pdf/document.hpp>
#include <aspose/pdf/page_collection.hpp>
#include <aspose/pdf/rectangle.hpp>
#include <aspose/pdf/color.hpp>
#include <aspose/pdf/annotations/annotation.hpp>
#include <aspose/pdf/annotations/annotation_collection.hpp>
#include <aspose/pdf/annotations/annotation_type.hpp>
#include <aspose/pdf/annotations/annotation_flags.hpp>
#include <aspose/pdf/annotations/border.hpp>
#include <aspose/pdf/annotations/border_style.hpp>
#include <aspose/pdf/annotations/text_annotation.hpp>

using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Annotations;

步骤 3:创建文档并添加页面

创建一个新文档并向其添加页面。PageCollection::Add() 返回新添加的 Page:

Document doc;
Page page = doc.Pages().Add();

步骤 4:向页面添加文本注释

TextAnnotation 以便利贴样式的评论呈现。从所属的 Document 构造它,使用 Rect() 设置位置,使用 Contents() 设置消息,然后将其添加到页面的 AnnotationCollection:

TextAnnotation note{doc};
note.Rect(Rectangle(100.0, 700.0, 200.0, 720.0, false));
note.Contents("Reviewed and approved.");

page.Annotations().Add(note);

步骤 5:为第二个注释设置颜色、边框和标志样式

Annotation 还公开了 Color()、Border() 和 Flags()。Flags() 接受一个 AnnotationFlags 位字段——使用按位或 (OR) 组合值,以一次设置多个标志:

TextAnnotation flagged{doc};
flagged.Rect(Rectangle(100.0, 600.0, 300.0, 650.0, false));
flagged.Contents("Needs follow-up");
flagged.Color(Color::FromRgb(220, 20, 20));
flagged.Flags(AnnotationFlags::Print | AnnotationFlags::ReadOnly);
flagged.Border().Width(2);
flagged.Border().Style(BorderStyle::Dashed);

page.Annotations().Add(flagged);

步骤 6:保存文档

在 Save() 运行之前,任何内容都不会写入磁盘:

doc.Save("annotated.pdf");

步骤 7:重新打开 PDF 并读取其批注

重新打开已保存的文件,并读取其首页的 AnnotationCollection。AnnotationCollection 为从 0 开始计数,Count() 报告该页包含的批注数量:

Document reopened("annotated.pdf");
auto& annots = reopened.Pages()[1].Annotations();

std::cout << "Annotation count: " << annots.Count() << "\n";

for (int i = 0; i < annots.Count(); ++i) {
    const auto& a = annots[i];
    if (a.AnnotationType() == AnnotationType::Text) {
        std::cout << "Text annotation: " << a.Contents() << "\n";
    }
}

步骤 8:删除批注并重新保存

AnnotationCollection::Delete(index) 按 0 基位置删除批注。删除第一个批注并将结果保存到新文件中:

annots.Delete(0);
reopened.Save("annotated-cleaned.pdf");

常见问题与解决方案

调用后保存的 PDF 没有任何变化 Annotations().Add()

这里常见的两个错误。首先,PageCollection是基于1的(doc.Pages()[1]是第一页),而AnnotationCollection是基于0的(annots[0]是第一条注释)——混淆这两种索引方式会导致操作错误的对象。其次,确认Document::Save()确实在注释添加后才运行;在此之前不会有任何内容写入磁盘。

AnnotationCollection 索引或 Delete(index) throws std::out_of_range

有效索引范围是从 0 到 Count() - 1。传入负数索引或等于或大于 Count() 的索引会按照设计抛出 std::out_of_range。请先调用 Count() 来限定任何循环或查找。

Remove() returns false 第二次在同一注释上调用时

这不是错误。Remove() 报告注释是否已被找到并作为 bool 删除;在已经不存在的注释上再次调用它是一个无操作,返回 false。请检查返回值,而不要假设 Remove() 总是成功。

设置一个新的 AnnotationFlags 值会清除我已经设置的标志

Flags(value) 会替换整个标志集合——它不会与之前的值合并。要添加或清除单个标志,请先读取当前标志并使用位运算符进行组合,例如使用 a.Flags(a.Flags() | AnnotationFlags::Print) 来添加标志,或使用 a.Flags(a.Flags() & ~AnnotationFlags::Print) 来清除某个标志而保持其余不变。

常见问题

在 Annotation、TextAnnotation 与其他注释子类型之间是什么关系?

Annotation 是通用基类。TextAnnotation 和其他具体的注释类型各自针对一种 PDF 注释子类型进行专化,同时共享基类的 Rect()、Contents()、Color()、Flags() 和 Border() 访问器。

注释的作用范围是整个文档还是单个页面?

每个页面都有自己的 AnnotationCollection,由该页面的 Annotations() 方法返回。注释始终作用于其所在的页面,而不是整个文档。

我该如何统计页面上有多少注释?

对 Page::Annotations() 返回的 AnnotationCollection 调用 Count()。

注释能同时是可打印且只读吗?

是的。AnnotationFlags 是位字段,可以使用按位或组合值,例如 AnnotationFlags::Print | AnnotationFlags::ReadOnly。

从 AnnotationCollection 删除注释会从磁盘上的 PDF 文件中移除它吗?

只有在 Document::Save() 运行后。Delete()、Remove() 和 Clear() 仅修改内存中的集合 — 磁盘上的 PDF 在文档保存之前保持不变。

另请参阅

 中文