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’sName) в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 |
AnnotationFlags | IntFlag поведения отображения/взаимодействия аннотации |
AnnotationName | str подкласс, помечающий значение для сериализации как имя PDF |
PDF3DAnnotation / PDF3DArtwork / PDF3DContent / PDF3DView | Предрелизная 3D-аннотация и модель произведения искусства |
PDF3DRenderMode / PDF3DLightingScheme | Перечисления для режима рендеринга 3D-вида и схемы освещения |