Cómo trabajar con anotaciones PDF en C++
Aspose.PDF FOSS para C++ representa cada anotación PDF como una subclase de la clase base común Annotation, y expone las anotaciones en una página a través del AnnotationCollection devuelto por Page::Annotations(). Esta guía agrega una anotación de nota de texto plano y una anotación con estilo a una página con TextAnnotation, guarda el documento, luego lo vuelve a abrir para leer las anotaciones y eliminar una. La biblioteca está integrada en un proyecto CMake como una dependencia de subdirectorio — no hay paso de instalación mediante registro de paquetes.
Guía paso a paso
Paso 1: Instalar el paquete
Agregue la biblioteca como un subdirectorio CMake y enlace el objetivo de biblioteca estática:
add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)Verifique que la cadena de herramientas y el paso de enlace se resuelvan correctamente con un programa mínimo:
#include <aspose/pdf/document.hpp>
#include <iostream>
int main() {
Aspose::Pdf::Document doc;
std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}Una compilación exitosa que imprime pages: 0 confirma que la biblioteca está enlazada.
Paso 2: Importar las clases requeridas
#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;Paso 3: Crear un documento y agregar una página
Cree un nuevo documento y agregue una página a él. PageCollection::Add() devuelve el Page recién añadido:
Document doc;
Page page = doc.Pages().Add();Paso 4: Añadir una anotación de texto a la página
TextAnnotation se muestra como un comentario tipo nota adhesiva. Constrúyalo a partir del Document propietario, establezca su posición con Rect() y su mensaje con Contents(), luego agréguelo al AnnotationCollection de la página:
TextAnnotation note{doc};
note.Rect(Rectangle(100.0, 700.0, 200.0, 720.0, false));
note.Contents("Reviewed and approved.");
page.Annotations().Add(note);Paso 5: Dar estilo a una segunda anotación con color, un borde y banderas
Annotation también expone Color(), Border() y Flags(). Flags() recibe un campo de bits AnnotationFlags — combine valores con OR a nivel de bits para establecer más de una bandera a la vez:
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);Paso 6: Guardar el documento
No se escribe nada en el disco hasta que Save() se ejecute:
doc.Save("annotated.pdf");Paso 7: Reabrir el PDF y leer sus anotaciones
Reabre el archivo guardado y lee de vuelta el AnnotationCollection de la primera página. AnnotationCollection es basado en 0, y Count() indica cuántas anotaciones tiene la página:
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";
}
}Paso 8: Eliminar una anotación y volver a guardar
AnnotationCollection::Delete(index) elimina una anotación por su posición basada en 0. Elimina la primera anotación y guarda el resultado en un archivo nuevo:
annots.Delete(0);
reopened.Save("annotated-cleaned.pdf");Problemas comunes y soluciones
Nada cambia en el PDF guardado después de llamar Annotations().Add()
Dos cosas suelen fallar aquí. Primero, PageCollection es basado en 1 (doc.Pages()[1] es la primera página) mientras que AnnotationCollection es basado en 0 (annots[0] es la primera anotación) — confundir los dos esquemas de indexación lleva a operar sobre el objeto incorrecto. Segundo, confirma que Document::Save() realmente se ejecute después de que se añada la anotación; nada se escribe en disco hasta entonces.
AnnotationCollection indexación o Delete(index) throws std::out_of_range
Los índices válidos van desde 0 hasta Count() - 1. Pasar un índice negativo o un índice igual o mayor que Count() lanza std::out_of_range por diseño. Llama a Count() primero para delimitar cualquier bucle o búsqueda.
Remove() returns false la segunda vez que lo llamo sobre la misma anotación
Esto no es un error. Remove() informa si la anotación fue encontrada y eliminada como un bool; llamarlo de nuevo sobre una anotación que ya no existe es una operación nula que devuelve false. Verifica el valor de retorno en lugar de asumir que Remove() siempre tiene éxito.
Establecer un nuevo AnnotationFlags valor borra banderas que ya había configurado
Flags(value) reemplaza todo el conjunto de banderas — no combina con el valor anterior. Para añadir o eliminar una sola bandera, lee primero las banderas actuales y combínalas con operadores bit a bit, por ejemplo a.Flags(a.Flags() | AnnotationFlags::Print) para añadir una bandera, o a.Flags(a.Flags() & ~AnnotationFlags::Print) para eliminar una bandera mientras dejas el resto intacto.
Preguntas Frecuentes
¿Cuál es la relación entre Annotation, TextAnnotation y los demás subtipos de anotación?
Annotation es la clase base común. TextAnnotation y los demás tipos de anotación concretos la especializan para un subtipo de anotación PDF, mientras comparten los accesores Rect(), Contents(), Color(), Flags() y Border() de la clase base.
¿Las anotaciones están limitadas al documento completo o a una sola página?
Cada página tiene su propio AnnotationCollection, devuelto por el método Annotations() de esa página. Las anotaciones siempre están limitadas a la página a la que se añadieron, no al documento completo.
¿Cómo cuento cuántas anotaciones hay en una página?
Llame a Count() sobre el AnnotationCollection devuelto por Page::Annotations().
¿Puede una anotación ser imprimible y de solo lectura al mismo tiempo?
Sí. AnnotationFlags es un campo de bits, por lo que se combinan los valores con OR a nivel de bits, por ejemplo AnnotationFlags::Print | AnnotationFlags::ReadOnly.
¿Eliminar una anotación de AnnotationCollection la elimina del archivo PDF en el disco?
Solo después de que Document::Save() se ejecute. Delete(), Remove() y Clear() solo modifican la colección en memoria — el PDF en el disco no cambia hasta que el documento se guarde.