C++でPDF注釈を操作する方法
Aspose.PDF FOSS for C++ は、すべての PDF 注釈を共通の Annotation 基底クラスのサブクラスとして表現し、Page::Annotations() が返す AnnotationCollection を介してページ上の注釈を公開します。このガイドでは、TextAnnotation を使ってプレーンテキストノート注釈とスタイル付き注釈をページに追加し、ドキュメントを保存した後、再度開いて注釈を読み取り、1つを削除します。ライブラリは 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: 2 番目の注釈を色、枠線、フラグでスタイル設定する
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()
ここで一般的に起こる問題は2つあります。まず、PageCollectionは1ベース(doc.Pages()[1]が最初のページ)で、AnnotationCollectionは0ベース(annots[0]が最初のアノテーション)です——この2つのインデックス方式を混同すると、誤ったオブジェクトを操作してしまいます。次に、Document::Save()がアノテーションが追加された後に実際に実行されていることを確認してください;それまでディスクへの書き込みは行われません。
AnnotationCollection インデックス作成または Delete(index) throws std::out_of_range
有効なインデックスは 0 から Count() - 1 までです。負のインデックスや Count() 以上のインデックスを渡すと、設計上 std::out_of_range がスローされます。ループや検索を行う前に、まず Count() を呼び出して範囲を限定してください。
Remove() returns false 同じアノテーションで2回目に呼び出すと
これはエラーではありません。Remove() はアノテーションが見つかり削除されたかどうかを bool として報告します;既に削除されたアノテーションに対して再度呼び出すと、何もしない操作となり false を返します。Remove() が常に成功すると仮定せず、戻り値を確認してください。
新しい設定 AnnotationFlags 値を設定すると、すでに設定したフラグがクリアされます
Flags(value) はフラグ全体を置き換えます — 以前の値とマージされません。単一のフラグを追加またはクリアするには、まず現在のフラグを読み取り、ビット演算子で組み合わせます。例えばフラグを追加するには a.Flags(a.Flags() | AnnotationFlags::Print)、他のフラグはそのままにして1つのフラグだけをクリアするには a.Flags(a.Flags() & ~AnnotationFlags::Print) を使用します。
よくある質問
Annotation、TextAnnotation、および他のアノテーションサブタイプ間の関係は何ですか?
Annotation は共通の基底クラスです。TextAnnotation と他の具体的なアノテーションタイプはそれぞれ、1つの PDF アノテーションサブタイプに対してこれを特殊化し、基底クラスの Rect()、Contents()、Color()、Flags()、Border() アクセサを共有します。
アノテーションは文書全体にスコープされますか、それとも 1 ページにスコープされますか?
各ページはそれぞれの AnnotationCollection を持ち、Annotations() メソッドで取得できます。アノテーションは常に追加されたページに対してスコープされ、文書全体にはスコープされません。
ページ上のアノテーションの数をどうやって数えますか?
Page::Annotations() が返す AnnotationCollection に対して Count() を呼び出します。
アノテーションは印刷可能でありながら読み取り専用であることはできますか?
はい。AnnotationFlags はビットフィールドであるため、ビット単位の OR で値を組み合わせます。例として AnnotationFlags::Print | AnnotationFlags::ReadOnly があります。
AnnotationCollection から注釈を削除すると、ディスク上の PDF ファイルからも削除されますか?
Document::Save() が実行された後だけです。Delete()、Remove()、および Clear() はメモリ内のコレクションのみを変更し、ディスク上の PDF はドキュメントが保存されるまで変更されません。