PDF Аннотации

PDF Аннотации

PDF-аннотации

Page.annotations предоставляет AnnotationCollection — изменяемый, похожий на последовательность просмотр всех аннотаций на странице. Каждый элемент является Annotation (или подклассами MarkupAnnotation / LinkAnnotation), а данные, специфичные для подтипа, такие как квадратичные точки, списки чернил или цвета, читаются и записываются через get_property() / set_property(), а не через отдельные атрибуты.


Добавление аннотаций

AnnotationCollection.add(subtype, rect, contents, title, appearance_normal, properties) создает новую аннотацию и добавляет её к странице. subtype принимает либо обычную строку ("Text", "Square", "Highlight"), либо член перечисления AnnotationType.

import aspose_pdf
from aspose_pdf import Document, AnnotationType

doc = Document()
doc.pages.add()
page = doc.pages[0]

# Plain string subtype
page.annotations.add("Text", (100, 100, 200, 200), "Hello")

# AnnotationType enum, with subtype-specific properties
page.annotations.add(
    AnnotationType.POLYGON,
    (0, 0, 10, 10),
    "",
    properties={"Vertices": [0, 0, 10, 0, 5, 10]},
)

Чтение и обновление свойств

get_property(name, default) читает значение, специфичное для подтипа; set_property(name, value) записывает его, а установка свойства в значение None удаляет его из словаря properties аннотации.

doc = Document()
doc.pages.add()
page = doc.pages[0]

ann = page.annotations.add(
    "Square", (0, 0, 50, 50), "x", properties={"C": [1, 0, 0]},
)
ann.set_property("IC", [0, 0, 1])
print(page.annotations[0].get_property("IC"))  # [0, 0, 1]

ann.set_property("C", None)  # removes the "C" entry entirely
print("C" in page.annotations[0].properties)  # False

Назначение имён аннотациям с помощью AnnotationName

Имена PDF (например, запись Stamp аннотации Name) отмечаются отличным образом от обычных строк с помощью AnnotationName, подкласса str от aspose_pdf.engine.cos. Значение, сохранённое таким способом, всё равно сравнивается как равное обычной строке.

from aspose_pdf.engine.cos import AnnotationName

doc = Document()
doc.pages.add()
page = doc.pages[0]

page.annotations.add(
    "Stamp", (10, 10, 110, 60), "",
    properties={"Name": AnnotationName("Approved")},
)

Вставка, удаление и очистка

insert(index, subtype, rect, contents, title, appearance_normal, properties) размещает новую аннотацию в определённой позиции; delete(index) удаляет её по индексу (вызывая IndexError при выходе индекса за пределы); clear() удаляет все аннотации со страницы.

doc = Document()
doc.pages.add()
page = doc.pages[0]

page.annotations.add("Text", (0, 0, 100, 100), "A")
page.annotations.add("Text", (200, 200, 300, 300), "C")
page.annotations.insert(1, "Text", (100, 100, 200, 200), "B")
# order is now: A, B, C

page.annotations.delete(1)   # removes "B"
page.annotations.clear()     # removes everything remaining

Генерация внешнего вида аннотаций

Annotation.generate_appearance(force) создаёт поток внешнего вида /AP /N для одной аннотации и возвращает True, когда существует рендерер для этого подтипа; AnnotationCollection.generate_appearances(force) делает то же самое для каждой аннотации на странице одним вызовом и возвращает количество аннотаций, действительно сгенерированных (неподдерживаемые подподы пропускаются).

doc = Document()
doc.pages.add()
page = doc.pages[0]

page.annotations.add("Square", (0, 0, 50, 50), "")
page.annotations.add("Circle", (60, 0, 110, 50), "")
page.annotations.add("Text", (0, 60, 20, 80), "")  # unsupported subtype -> skipped

generated = page.annotations.generate_appearances()
print(generated)  # 2

Подтипы аннотаций и флаги

AnnotationType перечисляет стандартные имена подтипов PDF 32000-1:2008 (Таблица 169): TEXT, LINK, FREE_TEXT, LINE, SQUARE, CIRCLE, POLYGON, POLY_LINE, HIGHLIGHT, UNDERLINE, SQUIGGLY, STRIKE_OUT, STAMP, CARET, INK, POPUP, FILE_ATTACHMENT, SOUND, MOVIE, WIDGET, SCREEN, PRINTER_MARK, TRAP_NET, WATERMARK и REDACT.

AnnotationFlags — это IntFlag, охватывающий поведение отображения/взаимодействия аннотации: DEFAULT, INVISIBLE, HIDDEN, PRINT, NO_ZOOM, NO_ROTATE, NO_VIEW, READ_ONLY, LOCKED и TOGGLE_NO_VIEW.


Предрелиз: 3D аннотации

PDF3DAnnotation, PDF3DArtwork, PDF3DContent и PDF3DView моделируют 3D-арт, прикреплённый к странице — у PDF3DAnnotation есть rect: Rectangle, artwork: PDF3DArtwork и необязательный background_color: Color. PDF3DArtwork.add_view() регистрирует PDF3DView, каждый из которых несёт render_mode (PDF3DRenderMode: SOLID, WIREFRAME, TRANSPARENT) и lighting_scheme (PDF3DLightingScheme: HEADLAMP, WHITE, GRAY, DARK, CUSTOM). Строка документации библиотеки отмечает PDF3DAnnotation как «минимальный обёртка аннотации для предрелизных импортов» — рассматривайте эту поверхность как раннюю стадию, а не как полностью проработанную 3D-авторскую API.


Советы и лучшие практики

  • Предпочитайте члены перечисления AnnotationType вместо необработанных строк подтипов, когда значение также нужно сравнивать или использовать в ветвлениях в другом месте вашего кода.
  • Вызовите set_property(name, None), чтобы полностью удалить свойство, а не оставлять устаревшее значение на месте — запись полностью исчезает из properties.
  • Генерируйте внешние виды пакетно с помощью AnnotationCollection.generate_appearances вместо перебора generate_appearance() для каждой аннотации; он возвращает фактическое количество сгенерированных элементов, что позволяет обнаруживать пропущенные/неподдерживаемые подтипы.
  • delete() и индексация в page.annotations обе начинаются с 0; проверьте индекс перед вызовом delete(), если он поступает от пользователя, поскольку индекс вне диапазона вызывает IndexError.
  • Оборачивайте значения имён PDF (например, Stamp’s Name) в AnnotationName, чтобы они передавались как имена PDF, а не как обычные текстовые строки.

Общие проблемы

ПроблемаПричинаИсправление
generate_appearances() возвращает меньше, чем количество добавленных аннотацийДля одного или нескольких подтипов отсутствует встроенный рендерер внешнего видаСравните количество возвращаемых элементов с len(page.annotations); неподдерживаемые подтипы пропускаются без сообщения об ошибке
delete(index) вызывает IndexErrorИндекс отрицательный или выходит за пределы текущего количества аннотацийПроверьте len(page.annotations) перед вызовом delete()
Свойство, установленное с помощью set_property(), не появляется после перезагрузкиСвойство было установлено в None, что удаляет его вместо сохраненияИспользуйте реальное значение, а не None, когда свойство должно сохраняться
Вставленная аннотация оказывается в неправильном местеИндекс insert(index, ...) считается от состояния коллекции до вставкиПовторно проверяйте индексы после каждого вызова insert() в цикле

FAQ

Как добавить аннотацию комментария простым текстом?

Вызовите page.annotations.add("Text", (x0, y0, x1, y1), "comment text"). Четырёхчисловый кортеж — это прямоугольник аннотации на странице.

В чём разница между Annotation, MarkupAnnotation и LinkAnnotation?

Annotation — это живый вид, возвращаемый для любой аннотации на странице. MarkupAnnotation является базой для подтипов в стиле разметки (выделения, текстовые заметки, формы), а LinkAnnotation сохраняется для аннотаций в виде ссылок; оба в настоящее время предоставляют одинаковый набор методов/свойств, как Annotation.

Можно ли удалить отдельное свойство, не удаляя всю аннотацию?

Да — вызовите annotation.set_property(name, None); сама аннотация остаётся нетронутой, удаляется только эта запись из properties.

Возникает ли ошибка у AnnotationCollection.generate_appearances, если подкласс не поддерживается?

Нет. Он пропускает подклассы без встроенного рендерера внешнего вида и возвращает количество аннотаций, для которых действительно был сгенерирован внешний вид.

Являются ли классы 3D-аннотаций готовыми к использованию в продакшене?

PDF3DAnnotation и связанные типы задокументированы как минимальная оболочка для предварительных импортов — проверьте их поведение в целевом PDF-просмотрщике, прежде чем полагаться на них для 3D-контента в продакшн.


API Reference Сводка

Класс/МетодОписание:
AnnotationCollection.addСоздать и добавить новую аннотацию на страницу
AnnotationCollection.insertСоздать и вставить новую аннотацию в определённый индекс
AnnotationCollection.deleteУдалить аннотацию по индексу (вызывает IndexError, если индекс вне диапазона)
AnnotationCollection.clearУдалить все аннотации со страницы
AnnotationCollection.generate_appearancesСоздать потоки отображения /AP /N для каждой поддерживаемой аннотации на странице
Annotation.get_property / set_propertyЧитать или записать значение свойства, специфичного для подтипа
Annotation.update_propertiesПересчитать производное состояние после непосредственного изменения свойств
Annotation.generate_appearanceСоздать поток отображения /AP /N для одной аннотации
AnnotationTypeПеречисление стандартных названий подтипов аннотаций PDF
AnnotationFlagsIntFlag поведения отображения/взаимодействия аннотации
AnnotationNamestr подкласс, помечающий значение для сериализации как имя PDF
PDF3DAnnotation / PDF3DArtwork / PDF3DContent / PDF3DViewПредрелизная 3D-аннотация и модель произведения искусства
PDF3DRenderMode / PDF3DLightingSchemeПеречисления для режима рендеринга 3D-вида и схемы освещения

См. также:

 Русский