Работа с аннотациями PDF

Работа с аннотациями 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

См. также:

 Русский