Работа с аннотациями PDF
Работа с PDF-аннотациями
PDF-аннотации в Aspose.PDF FOSS для C++ представлены базовым классом Annotation и его конкретными подклассами (TextAnnotation, LinkAnnotation, HighlightAnnotation, FreeTextAnnotation, CircleAnnotation, WatermarkAnnotation, WidgetAnnotation и другими). Каждая страница предоставляет свои аннотации через Page.Annotations(), который возвращает AnnotationCollection. В этом руководстве рассматриваются добавление аннотаций на страницу, их перебор и удаление, чтение аннотаций из существующего документа, привязка действий ссылок, настройка внешнего вида и уплощение аннотаций.
Добавление аннотаций на страницу
Создайте конкретный экземпляр аннотации, разместите его с помощью Rectangle и добавьте в коллекцию страницы с помощью AnnotationCollection.Add(). TextAnnotation представляет собой комментарий в стиле стикер-заметки, привязанный к точке на странице:
#include <aspose/pdf/document.hpp>
#include <aspose/pdf/annotations/text_annotation.hpp>
#include <aspose/pdf/rectangle.hpp>
int main() {
Aspose::Pdf::Document doc("input.pdf");
auto& page = doc.Pages()[1];
Aspose::Pdf::Annotations::TextAnnotation note(doc);
note.Rect(Aspose::Pdf::Rectangle(100.0, 700.0, 200.0, 720.0, false));
note.Contents("Reviewed and approved");
page.Annotations().Add(note);
doc.Save("annotated.pdf");
}Annotation.Contents() / Contents(value) получают и задают текст заметки, а Annotation.Rect() / Rect(value) позиционируют аннотацию на странице.
Перебор и удаление аннотаций
AnnotationCollection поддерживает подсчёт, доступ по индексу, проверку принадлежности и удаление по значению или по индексу:
#include <aspose/pdf/document.hpp>
int main() {
Aspose::Pdf::Document doc("input.pdf");
auto& annotations = doc.Pages()[1].Annotations();
std::cout << "Annotation count: " << annotations.Count() << "\n";
for (int i = 0; i < annotations.Count(); ++i) {
std::cout << "Contents: " << annotations[i].Contents() << "\n";
}
if (annotations.Count() > 0) {
annotations.Delete(0); // remove by index
}
annotations.Clear(); // remove everything
}AnnotationCollection.Contains(annotation) и Remove(annotation) работают с конкретной ссылкой на аннотацию; Delete(index) удаляет по позиции, а Delete(annotation) удаляет конкретную аннотацию без необходимости её индекса. IsReadOnly() сообщает, можно ли модифицировать коллекцию.
Чтение аннотаций из существующего документа
Когда документ загружается, его аннотации уже заполнены и их можно просматривать без добавления чего-либо. Annotation.AnnotationType() сообщает подтип (AnnotationType::Text, AnnotationType::Highlight, AnnotationType::Link, AnnotationType::FreeText, AnnotationType::FileAttachment, AnnotationType::Watermark и другие):
#include <aspose/pdf/document.hpp>
#include <aspose/pdf/annotations/annotation_type.hpp>
int main() {
Aspose::Pdf::Document doc("annotated.pdf");
auto& annotations = doc.Pages()[1].Annotations();
for (int i = 0; i < annotations.Count(); ++i) {
auto& a = annotations[i];
if (a.AnnotationType() == Aspose::Pdf::Annotations::AnnotationType::Text) {
std::cout << "Note: " << a.Contents() << "\n";
}
}
}Порядок аннотаций и их подтип сохраняются при сохранении/перезагрузке, поэтому код, который индексирует Annotations() после загрузки документа, видит ту же последовательность, которая была при записи файла.
Ссылочные аннотации и действия
LinkAnnotation прикрепляет к странице кликабельную область и инициирует PdfAction при активации. NamedAction переходит к предопределённой цели навигации, JavascriptAction выполняет строку ECMAScript, а SubmitFormAction отправляет данные формы на URL через FileSpecification:
#include <aspose/pdf/document.hpp>
#include <aspose/pdf/annotations/link_annotation.hpp>
#include <aspose/pdf/annotations/named_action.hpp>
#include <aspose/pdf/annotations/predefined_action.hpp>
#include <aspose/pdf/rectangle.hpp>
int main() {
Aspose::Pdf::Document doc;
auto page = doc.Pages().Add();
Aspose::Pdf::Annotations::LinkAnnotation link(
page, Aspose::Pdf::Rectangle(0.0, 0.0, 100.0, 20.0, false));
link.Action(Aspose::Pdf::Annotations::NamedAction(
Aspose::Pdf::Annotations::PredefinedAction::LastPage));
page.Annotations().Add(link);
doc.Save("linked.pdf");
}LinkAnnotation.Action(value) принимает любой подтип PdfAction и клонирует его внутри, поэтому аннотация сохраняет собственную копию действия. LinkAnnotation.Destination() / Destination(value) задают явную цель навигации вместо действия, а Highlighting() / Highlighting(value) управляют визуальной обратной связью, отображаемой при нажатии на ссылку.
Внешний вид аннотации: граница, флаги и цвет
Каждый Annotation раскрывает Border, битовое поле AnnotationFlags, и Color, используемое для отрисовки его внешнего вида:
#include <aspose/pdf/annotations/border_style.hpp>
#include <aspose/pdf/annotations/annotation_flags.hpp>
#include <aspose/pdf/color.hpp>
// 'note' is an existing Annotation reference, e.g. from AnnotationCollection.
note.Border().Width(2);
note.Border().Style(Aspose::Pdf::Annotations::BorderStyle::Dashed);
note.Flags(Aspose::Pdf::Annotations::AnnotationFlags::Print);
note.Color(Aspose::Pdf::Color::Red());Border.Style() принимает BorderStyle::Solid, Dashed, Beveled, Inset или Underline. Border.Effect() дополнительно поддерживает BorderEffect::Cloudy контур с EffectIntensity(), определяющим, насколько он выражен. AnnotationFlags — это битовое поле — комбинируйте значения, такие как Print, NoZoom, ReadOnly и LockedContents, чтобы управлять поведением аннотации в просмотрщике без изменения её видимого содержимого.
Сведение аннотаций
Одинарную аннотацию можно «сплющить» — объединить с содержимым страницы и сделать неинтерактивной — вызвав Annotation.Flatten() напрямую:
#include <aspose/pdf/document.hpp>
int main() {
Aspose::Pdf::Document doc("annotated.pdf");
auto& annotations = doc.Pages()[1].Annotations();
for (int i = 0; i < annotations.Count(); ++i) {
annotations[i].Flatten();
}
doc.Save("flattened.pdf");
}Для операций с аннотациями на уровне всего документа PdfAnnotationEditor следует общему шаблону Facade, используемому во всей API: привязать исходный документ с помощью BindPdf(), выполнить одну или несколько операций с аннотациями, затем записать результат с помощью Save():
#include <aspose/pdf/facades/pdf_annotation_editor.hpp>
int main() {
Aspose::Pdf::Facades::PdfAnnotationEditor editor;
editor.BindPdf("annotated.pdf");
editor.FlatteningAnnotations();
editor.Save("flattened.pdf");
}PdfAnnotationEditor.DeleteAnnotations() удаляет все аннотации из привязанного документа; DeleteAnnotations(annotType) ограничивает удаление одной AnnotationType. ImportAnnotationsFromXfdf(xfdfFile) и ImportAnnotationsFromFdf(fdfFile) загружают данные аннотаций, экспортированные из другого PDF-просмотрщика.
Советы и лучшие практики
- Всегда добавляйте только что созданную аннотацию в
Page.Annotations()перед вызовомDocument.Save()— аннотация, которая никогда не была добавлена в коллекцию, не будет записана в выходной файл. - Используйте
AnnotationCollection.Contains(annotation)перед вызовомRemove(), если вы не уверены, что аннотация всё ещё присутствует;Remove()возвращаетfalse, а не бросает исключение, когда аннотация отсутствует. - Проверьте
Annotation.AnnotationType()перед приведением типа или ветвлением по поведению подтипа при итерации аннотаций, загруженных из ненадёжного или стороннего PDF-файла. - Уплощайте аннотации с помощью
Annotation.Flatten()(илиPdfAnnotationEditor.FlatteningAnnotations()для всего документа) перед архивированием документа, чтобы рецензенты в других инструментах видели тот же внешний вид, который вы создали. AnnotationFlagsпредставляет собой битовое поле — объединяйте флаги с базовыми целочисленными значениями перечисления, а не полагайтесь на то, что одновременно может быть активен только один флаг.
Распространённые проблемы
| Проблема | Причина | Исправление |
|---|---|---|
| Аннотация не видна после сохранения | Аннотация была построена, но никогда не была добавлена в Page.Annotations() | Вызовите page.Annotations().Add(annotation) перед doc.Save() |
Remove() возвращает false | Переданная ссылка на аннотацию не совпадает с записью, присутствующей в текущей коллекции | Сначала используйте Contains(), либо удалите по индексу с помощью Delete(index) |
| Неправильный тип аннотации после перезагрузки | Код предполагал определённый подтип, не проверяя AnnotationType() | Проверьте Annotation.AnnotationType() перед тем как рассматривать объект как определённый подтип |
| Действие ссылки кажется неустановленным после присваивания | Локальная переменная PdfAction вышла из области видимости; LinkAnnotation.Action() возвращает клонированную копию аннотации, а не исходный объект | Считывайте действие через link.Action(), а не удерживая оригинальную локальную переменную |
Операция PdfAnnotationEditor не имеет эффекта | BindPdf() не был вызван, или был вызван с путем, который не существует | Убедитесь, что BindPdf() завершилось успешно, прежде чем вызывать FlatteningAnnotations() или DeleteAnnotations() |
FAQ
Как добавить аннотацию в виде комментария на страницу PDF?
Создайте TextAnnotation с целевым Document, установите его Rect() и Contents(), затем добавьте его в page.Annotations() перед сохранением.
Как узнать, какой тип аннотации я рассматриваю?
Вызовите Annotation.AnnotationType(), который возвращает значение перечисления AnnotationType, например Text, Link, Highlight, FreeText, FileAttachment или Watermark.
Может ли одна аннотация содержать более одного флага?
Да. AnnotationFlags представляет собой битовое поле (Default, Invisible, Hidden, Print, NoZoom, ReadOnly, LockedContents и другие), поэтому несколько флагов могут быть объединены в одной аннотации.
В чём разница между «уплощением» одной аннотации и «уплощением» документа?
Annotation.Flatten() объединяет одну аннотацию с содержимым её страницы. PdfAnnotationEditor.FlatteningAnnotations() (опционально ограниченный диапазоном страниц и AnnotationType через перегрузку, принимающую start, end и annotType) уплощает весь связанный документ за один вызов.
Как удалить из документа все аннотации одного типа?
Свяжите документ с помощью PdfAnnotationEditor.BindPdf(), вызовите DeleteAnnotations(annotType) с целевым AnnotationType, затем Save() результат.
API Reference Сводка
| Класс/Метод | Описание: |
|---|---|
Annotation | Абстрактный базовый класс для всех подтипов аннотаций PDF |
Annotation.Rect() / Rect(value) | Получить или установить ограничивающий прямоугольник аннотации |
Annotation.Contents() / Contents(value) | Получить или задать текстовое содержимое аннотации |
Annotation.AnnotationType() | Возвращает значение перечисления AnnotationType для этой аннотации |
Annotation.Flags() / Flags(value) | Получить или установить битовое поле AnnotationFlags |
Annotation.Border() / Border(value) | Получить или установить Border аннотации |
Annotation.Color() / Color(value) | Получить или установить отображение аннотации Color |
Annotation.Flatten() | Объединяет эту аннотацию с содержимым страницы, делая её неинтерактивной |
AnnotationCollection | Упорядоченная коллекция аннотаций на странице, возвращаемая Page.Annotations() |
AnnotationCollection.Add(annotation) / Add(annotation, considerRotation) | Добавляет аннотацию в коллекцию |
AnnotationCollection.Count() | Возвращает количество аннотаций в коллекции |
AnnotationCollection.Contains(annotation) | Сообщает, содержит ли коллекция данную аннотацию |
AnnotationCollection.Remove(annotation) | Удаляет конкретную аннотацию; возвращает false, если не найдено |
AnnotationCollection.Delete(index) / Delete(annotation) | Удаляет аннотацию по индексу или по ссылке |
AnnotationCollection.Clear() | Удаляет все аннотации из коллекции |
TextAnnotation | Аннотация в стиле стикера с Open() и Icon() (TextIcon) |
LinkAnnotation | Кликабельный регион, отправляющий PdfAction через Action() / Action(value) |
LinkAnnotation.Destination() / Destination(value) | Получить или установить явную цель навигации |
HighlightAnnotation | Отмечает фрагмент текста цветом выделения |
FreeTextAnnotation | Отображает текстовую выноску; настроено через Justification(), DefaultAppearanceObject(), Callout() |
CircleAnnotation | Рисует эллипс внутри прямоугольника аннотации |
WatermarkAnnotation | Наложить аннотацию с помощью аксессора Opacity() / Opacity(value) |
WidgetAnnotation | Аннотация внешнего вида поля формы с ReadOnly(), Required(), Exportable(), DefaultAppearance() |
NamedAction | Предопределённое действие навигации (PredefinedAction enum), которое можно привязать к LinkAnnotation |
JavascriptAction | Выполняет строку ECMAScript через Script() / GetECMAScriptString() |
SubmitFormAction | Отправляет данные формы на FileSpecification URL через Url() / Url(value) |
Border | Граница аннотации с Width(), Style() (BorderStyle), Effect() (BorderEffect) |
PdfAnnotationEditor | Фасад для импорта, модификации, уплощения и удаления аннотаций по всему документу |
PdfAnnotationEditor.FlatteningAnnotations() | Уплощает аннотации по всему связанному документу |
PdfAnnotationEditor.DeleteAnnotations(annotType) | Удаляет все аннотации заданного AnnotationType |
PdfAnnotationEditor.ImportAnnotationsFromXfdf(xfdfFile) | Импортирует аннотации из файла XFDF |