Python で PDF アノテーションを操作する方法

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: 必要なクラスをインポート

PDF を保持するために Document をインポートし、アノテーションの作成と検査に使用するアノテーションクラスもインポートします:

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)を列挙しているので、生の文字列の代わりに enum メンバーを渡すことができます。型固有のデータ(例えばポリゴンの頂点など)は 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 Table 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) を呼び出して位置で 1 つのアノテーションを削除するか、page.annotations.clear() を呼び出してページ上のすべてのアノテーションを削除します。

末尾に追加するのではなく、特定の位置にアノテーションを挿入できますか?

はい — AnnotationCollection.insert(index, subtype, rect, contents, title, appearance_normal, properties) は add() と同じ引数に加えて、対象の index を取ります。

アノテーションの色はどのように表現されますか?

Annotation 上の color プロパティ(およびそのサブクラス)は、PDF /C エントリのコンポーネント数に一致する tuple[float, ...] であり(色が設定されていない場合は空です)— 専用の色オブジェクトではありません。

参照

 日本語