Як працювати з анотаціями PDF у Python

Як працювати з анотаціями PDF у Python

Aspose.PDF FOSS для Python відкриває кожну анотацію на сторінці як живий об’єкт Annotation через AnnotationCollection сторінки, тому ви можете додавати розмітку, посилання та 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: Створити анотації з підтипів enum

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), доки його не згенерувати. Викличте generate_appearance(force) для окремого Annotation або generate_appearances(force) для всього AnnotationCollection, щоб одночасно синтезувати всі відсутні потоки вигляду на сторінці:

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" та подібні) — помилка в написанні або неправильний регістр ігнорується без повідомлення. Передайте аргумент default у get_property(name, default) і перевірте його явно під час налагодження нового підтипу.

generate_appearance() returns False

Не кожна комбінація підтипу та властивості може бути синтезована у потік вигляду вбудованим генератором. Перевірте has_appearance перед тим, як припускати, що виклик успішний, і надайте попередньо відрендерений appearance_normal (bytes) безпосередньо на add() для підтипів, які генератор не охоплює.

Неочікуваний підклас анотації після add()

Рядок підтипу (або член AnnotationType), який ви передаєте, визначає повернутий клас: підтипи розмітки повертаються як MarkupAnnotation, "Link" повертається як LinkAnnotation, а будь-який інший розпізнаний підтип повертається як базовий Annotation. Використовуйте isinstance() проти MarkupAnnotation/LinkAnnotation, а не припускайте конкретний рядок підтипу.

AnnotationFlags значення, схоже, не змінюють відображення

AnnotationFlags (PRINT, HIDDEN, NO_ZOOM, READ_ONLY та подібні) — це стандартний Python IntFlag enum для складання та інтерпретації бітів поведінки анотації за допомогою оператора | — це тип значення, а не властивість, яку Annotation.add() записує автоматично. Об’єднайте необхідні прапорці і передайте їх через той самий типово-специфічний механізм properties, який використовується для інших даних, специфічних для підтипу.

Робота зі сторінкою, на якій ще немає анотацій

page.annotations завжди є дійсним (можливо порожнім) AnnotationCollection — вам ніколи не потрібно перевіряти None перед викликом add(), ітерацією або викликом clear().

Поширені запитання

Які підтипи анотацій підтримує Aspose.PDF FOSS для Python?

AnnotationType перераховує усі 25 стандартних підтипів PDF 32000-1:2008 Таблиці 169, включаючи 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.

Як представлено колір анотації?

Властивість color у Annotation (та її підкласах) є tuple[float, ...], що відповідає кількості компонентів запису PDF /C (порожня, коли колір не встановлено) — а не окремим об’єктом кольору.

Дивіться також

 Українська