Gestión de documentos
Gestión de Documentos
La clase Document es el punto de entrada para casi todas las operaciones en Aspose.PDF FOSS para Python: crear un nuevo PDF, cargar uno existente, editar sus páginas y escribir el resultado de nuevo. Esta guía recorre el ciclo de vida del documento, las operaciones de colección de páginas, la optimización, los flujos de trabajo multi-archivo, el cifrado y las excepciones que deberías esperar manejar.
Ciclo de Vida del Documento: Crear, Abrir y Guardar
Document() sin argumentos crea un documento vacío en memoria. Pasa una ruta de archivo, bytes crudo, o cualquier flujo binario legible como primer argumento (o llama a load_from() explícitamente) para cargar un PDF existente en su lugar. save() acepta una ruta o un flujo binario escribible como io.BytesIO.
from aspose_pdf import Document
# Create a new, empty document and add a blank page
doc = Document()
doc.pages.add()
doc.save("hello.pdf")
# Re-open it — a path, bytes, or a binary stream all work
reopened = Document("hello.pdf")
print(reopened.page_count) # 1
# ...or load explicitly onto an existing instance
another = Document()
another.load_from("hello.pdf")
reopened.close()
another.dispose()
doc.dispose()save() genera FileExistsError si la ruta de destino ya existe, a menos que pases overwrite=True. close() es un alias de dispose(); ambos son idempotentes, por lo que llamarlos más de una vez es seguro.
Solo PDF está implementado como objetivo de guardado — esta es la función central de la biblioteca, completamente operativa. Pasar un valor de exportación como SaveFormat.PPTX o DocFormat.HTML a save() genera UnsupportedFeatureException en lugar de escribir un archivo con etiqueta incorrecta, por lo que una exportación fallida siempre es ruidosa en lugar de silenciosa.
Gestionando la Colección de Páginas
doc.pages es un PageCollection. Soporta len(), iteración y indexación basada en cero (doc.pages[0]), además de add(), insert(index, page) y delete(index) para ediciones estructurales. Cada Page expone index, rect (el MediaBox) y rotation.
from aspose_pdf import Document
doc = Document()
doc.pages.add() # page 0
doc.pages.add() # page 1
doc.pages.insert(1, None) # insert a blank page at index 1
print(doc.page_count) # 3
first_page = doc.pages[0]
print(first_page.rect) # (0, 0, 612, 792)
for page in doc.pages:
print(page.index, page.rotation)
doc.pages.delete(1) # remove the page we inserted
doc.save("pages_demo.pdf", overwrite=True)pages.add(page=None) agrega una página en blanco cuando se llama sin argumentos. pages.insert() ajusta un índice fuera de rango a la posición válida más cercana en lugar de lanzar una excepción.
Optimización y compresión de documentos
Document.optimize ejecuta deduplicación de imágenes/streams, recolección de basura de objetos no usados y compresión de streams en una sola llamada. Pasa una instancia de OptimizationOptions para controlar qué técnicas se ejecutan; omítela para usar el perfil de limpieza estándar.
from aspose_pdf import Document, OptimizationOptions
doc = Document("large_report.pdf")
options = OptimizationOptions()
options.remove_unused_objects = True
options.link_duplicate_streams = True
options.image_compression_quality = 60
options.subset_fonts = True
doc.optimize(options)
doc.save("large_report_optimized.pdf", overwrite=True)optimize_resources() es un alias de optimize(). Si solo deseas compresión de streams sin la pasada de limpieza estructural, llama a doc.compress_streams() directamente.
Fusión, división y edición de archivos
Para los documentos que ya tienes abiertos, Document.merge() agrega otras instancias de Document al actual:
from aspose_pdf import Document
base = Document("part1.pdf")
extra = Document("part2.pdf")
base.merge(extra)
base.save("combined.pdf", overwrite=True)Para flujos de trabajo de archivo a archivo sin abrir un Document tú mismo, los complementos de bajo código Merger y Splitter aceptan un objeto MergeOptions/SplitOptions construido a partir de entradas y salidas de FileDataSource:
from aspose_pdf import Merger, MergeOptions, Splitter, SplitOptions, FileDataSource
# Merge two files into one
merge_options = MergeOptions()
merge_options.add_input(FileDataSource("part1.pdf"))
merge_options.add_input(FileDataSource("part2.pdf"))
merge_options.add_output(FileDataSource("combined.pdf"))
Merger().process(merge_options)
# Split the result into one file per page
split_options = SplitOptions()
split_options.add_input(FileDataSource("combined.pdf"))
split_options.add_output(FileDataSource("combined_page1.pdf"))
split_options.add_output(FileDataSource("combined_page2.pdf"))
Splitter().process(split_options)PdfFileEditor ofrece la misma familia de operaciones como una fachada que devuelve True/False en lugar de lanzar una excepción, lo que resulta conveniente para scripts por lotes:
from aspose_pdf import PdfFileEditor
with PdfFileEditor() as editor:
ok = editor.concatenate(["part1.pdf", "part2.pdf"], "combined.pdf")
if not ok:
print("concatenate failed:", editor.last_exception)
editor.extract("combined.pdf", "first_page_only.pdf", page_from=1, page_to=1)PdfFileEditor.extract() and .insert() take basado en 1 números de página, a diferencia de PageCollectionindexación basada en 0 — ver Problemas comunes a continuación.
Cifrado y Seguridad de Documentos
Document.encrypt(user_password, owner_password=None, permissions=-4) cifra el documento en memoria; decrypt(password) y change_passwords(old, new_user, new_owner=None) invierten o rotan contraseñas. is_encrypted y permissions informan el estado actual.
from aspose_pdf import Document
from aspose_pdf.exceptions import PdfSecurityException
doc = Document()
doc.pages.add()
doc.encrypt("user-pass", "owner-pass", permissions=-4)
doc.save("secured.pdf", overwrite=True)
try:
Document("secured.pdf", password="wrong-pass")
except PdfSecurityException as exc:
print("could not open:", exc)
reopened = Document("secured.pdf", password="user-pass")
print(reopened.is_encrypted) # True
reopened.decrypt("user-pass")
reopened.save("unsecured.pdf", overwrite=True)Abrir un documento cifrado sin contraseña, o con una incorrecta, genera PdfSecurityException — capture esta clase (de aspose_pdf.exceptions) en lugar de asumir que la carga siempre tiene éxito.
Metadatos, Validación y Manejo de Excepciones
Los metadatos del documento residen en doc.info (un simple dict[str, str]), y doc.version / doc.id exponen la versión del encabezado PDF y el identificador del archivo trailer. validate() (alias check()) informa la integridad estructural; repair() intenta corregir problemas comunes como una lista de páginas faltante o un MediaBox fuera de rango.
from aspose_pdf import Document, PdfLoadLimits
from aspose_pdf.exceptions import AsposePdfException, PdfIOException
doc = Document()
doc.pages.add()
doc.info["Title"] = "Quarterly Report"
doc.info["Author"] = "Reporting Bot"
doc.save("report.pdf", overwrite=True)
# Load untrusted input under an explicit resource-limit policy
safe_limits = PdfLoadLimits(max_input_bytes=50 * 1024 * 1024, max_pages=1000)
try:
untrusted = Document("incoming.pdf", limits=safe_limits)
if not untrusted.validate():
untrusted.repair()
except (AsposePdfException, PdfIOException) as exc:
print("failed to process incoming.pdf:", exc)PdfLoadLimits limita la memoria y el recuento de objetos para archivos no confiables; llame a PdfLoadLimits.unlimited() para desactivar todos los límites cuando confíe plenamente en la fuente. AsposePdfException es la clase base de toda la jerarquía de excepciones (incluyendo PdfIOException y PdfSecurityException), por lo que un único except AsposePdfException captura cualquier error generado por la biblioteca.
Consejos y mejores prácticas
- Siempre llama a
dispose()(oclose()) en unDocumentcuando hayas terminado con él, o úsalo como una variable local de corta duración — el motor mantiene el contenido de página decodificado y las imágenes en memoria hasta su eliminación. - Pasa
overwrite=Trueasave()al reescribir una ruta que ya creaste en la misma ejecución; el valor predeterminado esFalsey generaFileExistsError. - Prefiere
doc.optimize()antes de distribuir un PDF generado — es una única llamada que elimina objetos inutilizados y comprime flujos, y normalmente reduce el tamaño del archivo de salida de forma notable. - Establece una política de
PdfLoadLimitsde forma explícita siempre que cargues PDFs de una fuente no confiable (cargas, archivos adjuntos de correo electrónico, extracción web); los valores predeterminados son generosos pero finitos, no son una barrera de seguridad en la que debas confiar ciegamente. - Captura
AsposePdfException(o una subclase específica comoPdfSecurityException) alrededor de las llamadas de carga/guardado en lugar deExceptionsin más — es la base común de todos los errores que genera la biblioteca.
Problemas comunes
| Problema | Causa | Solución |
|---|---|---|
FileExistsError en save() | La ruta de destino ya existe y overwrite se dejó con su False predeterminado | Pasar save(path, overwrite=True) |
UnsupportedFeatureException en save() | Se solicitó un save_format que no es PDF (p.ej., SaveFormat.PPTX, DocFormat.HTML) | Guardar como PDF — cualquier otro valor de SaveFormat/DocFormat genera UnsupportedFeatureException en lugar de escribir la salida |
PdfSecurityException: Password required for encrypted document | Se abrió un PDF encriptado sin el argumento password | Pase Document(path, password="...") o llame a load_from(path, password="...") |
Desfase de una página entre PageCollection y PdfFileEditor | doc.pages[i] está basado en 0; los argumentos de página PdfFileEditor.extract()/.insert() están basados en 1 | Sume o reste 1 al convertir entre las dos API |
IndexError: Page index out of range. de pages.delete() | El índice pasado a delete() no existe en la colección | Compruebe doc.page_count (o len(doc.pages)) antes de eliminar |
FAQ
¿Necesito una licencia para usar Aspose.PDF FOSS para Python?
No. Esta es la edición de código abierto (con licencia MIT); no hay ningún archivo de licencia ni paso de activación que configurar.
¿Puedo exportar un Document a formatos diferentes de PDF?
No en esta versión. save() solo implementa salida PDF — pasar otro valor SaveFormat/DocFormat genera UnsupportedFeatureException en lugar de producir un archivo con etiqueta incorrecta.
¿Cuál es la diferencia entre Document.merge() y el plugin Merger?
Document.merge() combina instancias de Document que ya tienes abiertas en memoria. Merger (con MergeOptions y FileDataSource) es un contenedor de conveniencia archivo a archivo que abre, fusiona y guarda por ti en una sola llamada — útil para scripts por lotes simples que nunca necesitan el objeto intermedio Document.
¿Por qué pages.insert() nunca lanza una excepción por un índice fuera de rango?
PageCollection.insert() ajusta el índice al rango válido (los valores negativos se convierten en 0, los valores que superan el final se convierten en len(doc.pages)) en lugar de lanzar una excepción, por lo que una inserción nunca falla únicamente por el valor del índice.
¿Cómo cargo un PDF de forma segura desde una fuente no confiable?
Construya un PdfLoadLimits con límites explícitos (max_input_bytes, max_pages, max_objects, etc.) y páselo como el argumento limits= a Document(...) o load_from(). Cada campo ya tiene un valor finito por defecto, pero ajustarlos al tamaño de entrada esperado reduce los recursos que un archivo malformado puede consumir.
Resumen de API Reference
| Clase / Método | Descripción |
|---|---|
Document() / Document.load_from | Crea un documento vacío o carga uno desde una ruta, bytes o un flujo binario |
Document.save | Escribe el documento a una ruta o a un flujo escribible (solo PDF) |
Document.dispose() / Document.close() | Libera los recursos del motor; idempotente |
Document.pages | El PageCollection del documento |
Document.info | Metadatos del documento como dict[str, str] |
Document.optimize / Document.optimize_resources / Document.compress_streams() | Eliminar recursos no utilizados y comprimir flujos |
Document.merge() | Añadir otras instancias de Document a esta |
Document.encrypt / Document.decrypt / Document.change_passwords | Aplicar, eliminar o rotar contraseñas del documento |
Document.validate() / Document.check() / Document.repair() | Comprobar e intentar reparar la integridad estructural |
PageCollection.add() / .insert() / .delete() / .item() | Ediciones estructurales de la colección de páginas (basado en cero) |
Page.rect / Page.rotation / Page.index | Geometría y posición por página |
OptimizationOptions | Banderas de granularidad fina consumidas por Document.optimize |
MergeOptions / Merger | Plugin de fusión de archivo a archivo |
SplitOptions / Splitter | Plugin de división de archivo a archivo una página por salida |
FileDataSource | Entrada/salida respaldada por archivo para las API del plugin |
PdfFileEditor | Fachada para concatenate(), extract(), insert(), delete(), append() (páginas basadas en 1) |
PdfLoadLimits | Política inmutable de límite de recursos para entrada no confiable |
AsposePdfException | Clase base para cada excepción que lanza la biblioteca |
PdfSecurityException | Se lanza por contraseñas faltantes/incorrectas y errores de permisos |
PdfIOException | Se lanza por errores de E/S durante el procesamiento de PDF |
Ver también
- API Reference: Documentación completa de la clase y los métodos para
aspose_pdf - Base de Conocimientos: Guías prácticas orientadas a tareas
- Descripción del producto: Resumen de características y capacidades
- Comenzar / Instalación: instalar y configurar
- Aspose.PDF for Python — Enterprise Documentation