Как работать с аннотациями 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 на диске остаётся без изменений, пока документ не будет сохранён.