Gestión de documentos

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() (o close()) en un Document cuando 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=True a save() al reescribir una ruta que ya creaste en la misma ejecución; el valor predeterminado es False y genera FileExistsError.
  • 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 PdfLoadLimits de 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 como PdfSecurityException) alrededor de las llamadas de carga/guardado en lugar de Exception sin más — es la base común de todos los errores que genera la biblioteca.

Problemas comunes

ProblemaCausaSolución
FileExistsError en save()La ruta de destino ya existe y overwrite se dejó con su False predeterminadoPasar 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 documentSe abrió un PDF encriptado sin el argumento passwordPase Document(path, password="...") o llame a load_from(path, password="...")
Desfase de una página entre PageCollection y PdfFileEditordoc.pages[i] está basado en 0; los argumentos de página PdfFileEditor.extract()/.insert() están basados en 1Sume 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ónCompruebe 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étodoDescripción
Document() / Document.load_fromCrea un documento vacío o carga uno desde una ruta, bytes o un flujo binario
Document.saveEscribe el documento a una ruta o a un flujo escribible (solo PDF)
Document.dispose() / Document.close()Libera los recursos del motor; idempotente
Document.pagesEl PageCollection del documento
Document.infoMetadatos 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_passwordsAplicar, 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.indexGeometría y posición por página
OptimizationOptionsBanderas de granularidad fina consumidas por Document.optimize
MergeOptions / MergerPlugin de fusión de archivo a archivo
SplitOptions / SplitterPlugin de división de archivo a archivo una página por salida
FileDataSourceEntrada/salida respaldada por archivo para las API del plugin
PdfFileEditorFachada para concatenate(), extract(), insert(), delete(), append() (páginas basadas en 1)
PdfLoadLimitsPolítica inmutable de límite de recursos para entrada no confiable
AsposePdfExceptionClase base para cada excepción que lanza la biblioteca
PdfSecurityExceptionSe lanza por contraseñas faltantes/incorrectas y errores de permisos
PdfIOExceptionSe lanza por errores de E/S durante el procesamiento de PDF

Ver también

 Español