Cómo trabajar con documentos PDF en C++
Aspose.PDF FOSS para C++ es una biblioteca C++20 con licencia MIT, sin dependencias, construida y enlazada con CMake — no hay importación de gestor de paquetes que agregar. Esta guía recorre el flujo de trabajo centralizado en Document: abrir un PDF existente, inspeccionar sus páginas y metadatos, extraer texto y renderizar una página a una imagen raster.
Guía paso a paso
Paso 1: Instalar el paquete
Clona el repositorio y añádelo a tu proyecto CMake como subdirectorio:
git clone https://github.com/aspose-pdf-foss/Aspose.PDF-FOSS-for-Cpp.gitadd_subdirectory(Aspose.PDF-FOSS-for-Cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)O configúralo y compílalo de forma independiente:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build buildVerifica que la cadena de herramientas se resuelva compilando un programa mínimo contra los encabezados:
#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 para el Document recién construido y vacío confirma que la biblioteca está enlazada correctamente.
Paso 2: Importar clases requeridas
#include <aspose/pdf/document.hpp>
#include <aspose/pdf/document_info.hpp>
#include <aspose/pdf/page.hpp>
#include <aspose/pdf/page_collection.hpp>
#include <aspose/pdf/text_absorber.hpp>
#include <aspose/pdf/bmp_device.hpp>
#include <aspose/pdf/resolution.hpp>
#include <fstream>
#include <iostream>Paso 3: Abrir un documento PDF y contar sus páginas
Construya un Document a partir de una ruta de archivo para abrir un PDF existente. Document::Pages() devuelve el PageCollection, y Count() informa cuántas páginas contiene:
Aspose::Pdf::Document doc("input.pdf");
std::cout << "Page count: " << doc.Pages().Count() << "\n";Paso 4: Leer los metadatos del documento
Document::Info() devuelve un objeto DocumentInfo con accesores de lectura/escritura tipados para las entradas estándar del diccionario /Info:
auto& info = doc.Info();
std::cout << "Title: " << info.Title() << "\n";
std::cout << "Author: " << info.Author() << "\n";
std::cout << "Producer: " << info.Producer() << "\n";Paso 5: Extraer texto de una página
Aspose::Pdf::Text::TextAbsorber recorre un Document o un solo Page y acumula el texto que encuentra; Text() devuelve el resultado después. PageCollection está indexado a partir de 1, por lo que Pages()[1] es la primera página:
auto page = doc.Pages()[1];
Aspose::Pdf::Text::TextAbsorber absorber;
absorber.Visit(page);
std::cout << absorber.Text() << "\n";Visit() también acepta todo el Document directamente (absorber.Visit(doc)) cuando deseas que el texto de todas las páginas se concatene en lugar de una sola página.
Paso 6: Renderizar la página a una imagen raster
BmpDevice renderiza un Page a una imagen BMP sin comprimir. Su constructor recibe un Resolution que controla los DPI de salida, y Process() escribe los bytes renderizados a cualquier std::ostream:
Aspose::Pdf::Devices::BmpDevice device(Aspose::Pdf::Devices::Resolution(150));
std::ofstream imageOut("page1.bmp", std::ios::binary);
device.Process(page, imageOut);Paso 7: Actualizar los metadatos y guardar el documento
Los setters en DocumentInfo preparan cambios que se aplican la próxima vez que Save() se ejecuta en el Document propietario:
doc.Info().Title("Processed by Aspose.PDF FOSS for C++");
doc.Save("output.pdf");Problemas comunes y soluciones
Accessing Pages()[0] throws std::out_of_range
PageCollection está indexado desde 1, coincidiendo con la semántica canónica de Aspose.PDF — la primera página es Pages()[1]. Un índice menor que 1 o mayor que Count() lanza una excepción.
TextAbsorber::Text() devuelve una cadena vacía
Text() devuelve lo que se haya acumulado en la llamada más reciente a Visit(). Confirma que Visit() se haya llamado realmente antes de leer Text(), y que la página o documento que visitaste contenga texto extraíble y no solo imágenes escaneadas.
El archivo BMP renderizado es inesperadamente pequeño o parece en blanco
Un valor bajo de Resolution produce una imagen raster pequeña. Aumenta los DPI pasados a Resolution — por ejemplo, Resolution(300) para una salida de calidad de impresión — y confirma que el índice de página pasado a Process() sea el que pretendías.
DocumentInfo los campos se leen como cadenas vacías
No todos los productores de PDF escriben entradas estándar de /Info. Verifica Producer() y Creator() en busca de valores en blanco antes de asumir que la extracción de metadatos falló — una cadena vacía es el resultado definido para una clave ausente.
Cambios realizados con Info().Title(...) no aparecen en el archivo guardado
Las mutaciones de DocumentInfo se preparan en memoria y solo se persisten la próxima vez que Save() se ejecuta en la misma instancia de Document. Asegúrese de que la edición de los metadatos ocurra antes de Save(), no después.
Preguntas frecuentes
¿El indexado de páginas es basado en cero o en uno en Aspose.PDF FOSS para C++?
Basado en uno. doc.Pages()[1] es siempre la primera página.
¿Puede TextAbsorber extraer texto de una sola página en lugar de todo el documento?
Sí. Visit() está sobrecargado para aceptar ya sea un Document — que extrae el texto de cada página — o un único Page, que extrae solo el texto de esa página.
¿Necesito llamar a Save() si solo leo datos del documento?
No. Save() solo se requiere después de cambios que deben guardarse en un archivo, como editar campos DocumentInfo. Leer el recuento de páginas, extraer texto o renderizar una página no modifica el documento.
¿Cómo controlo la resolución de una página renderizada?
Pase un valor Resolution al constructor del dispositivo — por ejemplo, Resolution(150) para 150 DPI. Los valores más altos producen imágenes raster más grandes y de mayor fidelidad.
¿Qué formato produce BmpDevice?
Una imagen BMP sin comprimir escrita directamente al std::ostream pasado a Process().