Как работать с аннотациями PDF в C++

Как работать с аннотациями PDF в C++

Aspose.PDF FOSS for C++ представляет каждую PDF-аннотацию как подкласс общего базового класса Annotation, и предоставляет аннотации на странице через AnnotationCollection, возвращаемый Page::Annotations(). Это руководство добавляет простую текстовую заметку-аннотацию и стилизованную аннотацию на страницу с помощью TextAnnotation, сохраняет документ, затем открывает его снова, чтобы прочитать аннотации и удалить одну из них. Библиотека интегрирована в проект CMake как зависимость-подкаталог — шаг установки через реестр пакетов не требуется.

Пошаговое руководство

Шаг 1: Установить пакет

Добавьте библиотеку как подкаталог CMake и свяжите цель статической библиотеки:

add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)

Проверьте, что набор инструментов и шаг линковки корректно разрешаются с минимальной программой:

#include <aspose/pdf/document.hpp>
#include <iostream>

int main() {
    Aspose::Pdf::Document doc;
    std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}

Успешная сборка, выводящая pages: 0, подтверждает, что библиотека связана.


Шаг 2: Импортировать необходимые классы

#include <aspose/pdf/document.hpp>
#include <aspose/pdf/page_collection.hpp>
#include <aspose/pdf/rectangle.hpp>
#include <aspose/pdf/color.hpp>
#include <aspose/pdf/annotations/annotation.hpp>
#include <aspose/pdf/annotations/annotation_collection.hpp>
#include <aspose/pdf/annotations/annotation_type.hpp>
#include <aspose/pdf/annotations/annotation_flags.hpp>
#include <aspose/pdf/annotations/border.hpp>
#include <aspose/pdf/annotations/border_style.hpp>
#include <aspose/pdf/annotations/text_annotation.hpp>

using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Annotations;

Шаг 3: Создать документ и добавить страницу

Создайте новый документ и добавьте в него страницу. PageCollection::Add() возвращает только что добавленный Page:

Document doc;
Page page = doc.Pages().Add();

Шаг 4: Добавить текстовую аннотацию на страницу

TextAnnotation отображается как комментарий в стиле стикер-ноты. Сконструируйте его из владеющего Document, задайте его позицию с помощью Rect() и сообщение с помощью Contents(), затем добавьте его в AnnotationCollection страницы:

TextAnnotation note{doc};
note.Rect(Rectangle(100.0, 700.0, 200.0, 720.0, false));
note.Contents("Reviewed and approved.");

page.Annotations().Add(note);

Шаг 5: Оформить вторую аннотацию цветом, границей и флагами

Annotation также предоставляет Color(), Border() и Flags(). Flags() принимает битовое поле AnnotationFlags — объединяйте значения побитовым ИЛИ, чтобы установить более одного флага одновременно:

TextAnnotation flagged{doc};
flagged.Rect(Rectangle(100.0, 600.0, 300.0, 650.0, false));
flagged.Contents("Needs follow-up");
flagged.Color(Color::FromRgb(220, 20, 20));
flagged.Flags(AnnotationFlags::Print | AnnotationFlags::ReadOnly);
flagged.Border().Width(2);
flagged.Border().Style(BorderStyle::Dashed);

page.Annotations().Add(flagged);

Шаг 6: Сохранить документ

Ничего не записывается на диск, пока не выполнится Save():

doc.Save("annotated.pdf");

Шаг 7: Откройте PDF повторно и прочитайте его аннотации

Повторно откройте сохранённый файл и прочитайте обратно AnnotationCollection первой страницы. AnnotationCollection начинается с нуля, а Count() сообщает, сколько аннотаций содержит страница:

Document reopened("annotated.pdf");
auto& annots = reopened.Pages()[1].Annotations();

std::cout << "Annotation count: " << annots.Count() << "\n";

for (int i = 0; i < annots.Count(); ++i) {
    const auto& a = annots[i];
    if (a.AnnotationType() == AnnotationType::Text) {
        std::cout << "Text annotation: " << a.Contents() << "\n";
    }
}

Шаг 8: Удалить аннотацию и пересохранить

AnnotationCollection::Delete(index) удаляет аннотацию по её 0-базовой позиции. Удалите первую аннотацию и сохраните результат в новый файл:

annots.Delete(0);
reopened.Save("annotated-cleaned.pdf");

Распространённые проблемы и решения

Ничего не меняется в сохранённом PDF после вызова Annotations().Add()

Здесь обычно происходит две ошибки. Во-первых, PageCollection начинается с 1 (doc.Pages()[1] — первая страница), тогда как AnnotationCollection начинается с 0 (annots[0] — первая аннотация) — путаница в схемах индексации приводит к работе с неправильным объектом. Во-вторых, убедитесь, что Document::Save() действительно выполняется после добавления аннотации; до этого ничего не записывается на диск.

AnnotationCollection индексации или Delete(index) throws std::out_of_range

Допустимые индексы находятся в диапазоне от 0 до Count() - 1. Передача отрицательного индекса или индекса, равного или превышающего Count(), по замыслу бросает std::out_of_range. Сначала вызовите Count(), чтобы ограничить любой цикл или поиск.

Remove() returns false второй раз, когда я вызываю её на той же аннотации

Это не ошибка. Remove() сообщает, была ли аннотация найдена и удалена как bool; повторный вызов для уже удалённой аннотации ничего не делает и возвращает false. Проверяйте возвращаемое значение, а не предполагаете, что Remove() всегда успешно завершается.

Установка нового AnnotationFlags значение сбрасывает флаги, которые я уже установил

Flags(value) заменяет весь набор флагов — он не объединяется с предыдущим значением. Чтобы добавить или очистить отдельный флаг, сначала прочитайте текущие флаги и объедините их побитовыми операторами, например a.Flags(a.Flags() | AnnotationFlags::Print) для добавления флага или a.Flags(a.Flags() & ~AnnotationFlags::Print) для очистки одного флага, оставив остальные нетронутыми.

Часто задаваемые вопросы

Какова связь между Annotation, TextAnnotation и другими подтипами аннотаций?

Annotation — общий базовый класс. TextAnnotation и другие конкретные типы аннотаций каждый специализируют его для одного подтипа PDF-аннотации, при этом используют аксессоры Rect(), Contents(), Color(), Flags() и Border() базового класса.

Аннотации привязаны к всему документу или к отдельной странице?

У каждой страницы есть свой AnnotationCollection, который возвращается методом Annotations() этой страницы. Аннотации всегда привязаны к странице, на которой они были добавлены, а не к документу в целом.

Как подсчитать количество аннотаций на странице?

Вызовите Count() у AnnotationCollection, возвращаемого Page::Annotations().

Может ли аннотация одновременно быть печатаемой и только для чтения?

Да. AnnotationFlags — это битовое поле, поэтому значения комбинируются побитовым OR, например AnnotationFlags::Print | AnnotationFlags::ReadOnly.

Удаляет ли удаление аннотации из AnnotationCollection её из PDF-файла на диске?

Только после выполнения Document::Save(). Delete(), Remove() и Clear() лишь изменяют коллекцию в памяти — PDF на диске остаётся без изменений, пока документ не будет сохранён.

См. также:

 Русский