Gestione dei documenti

Gestione dei documenti

Gestione dei Documenti

La classe Document è il punto di ingresso per quasi tutte le operazioni in Aspose.PDF FOSS per Python: creare un nuovo PDF, caricare uno esistente, modificare le sue pagine e scrivere nuovamente il risultato. Questa guida percorre il ciclo di vita del documento, le operazioni sulla raccolta di pagine, l’ottimizzazione, i flussi di lavoro multi-file, la crittografia e le eccezioni che dovresti gestire.


Ciclo di vita del documento: Creare, Aprire e Salvare

Document() senza argomenti crea un documento vuoto in memoria. Passa un percorso file, raw bytes, o qualsiasi stream binario leggibile come primo argomento (oppure chiama load_from() esplicitamente) per caricare invece un PDF esistente. save() accetta un percorso o uno stream binario scrivibile come 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() solleva FileExistsError se il percorso di destinazione esiste già, a meno che non venga passato overwrite=True. close() è un alias per dispose(); entrambi sono idempotenti, quindi chiamarli più di una volta è sicuro.

Solo PDF è implementato come destinazione di salvataggio — questa è la funzione centrale della libreria, completamente funzionante. Passare un valore di esportazione come SaveFormat.PPTX o DocFormat.HTML a save() solleva UnsupportedFeatureException invece di scrivere un file etichettato in modo errato, quindi un’esportazione fallita è sempre evidente piuttosto che silenziosa.


Gestione della raccolta di pagine

doc.pages è un PageCollection. Supporta len(), l’iterazione e l’indicizzazione a base zero (doc.pages[0]), oltre a add(), insert(index, page) e delete(index) per modifiche strutturali. Ogni Page espone index, rect (il MediaBox) e 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) aggiunge una pagina vuota quando viene chiamato senza argomento. pages.insert() limita un indice fuori intervallo alla posizione valida più vicina anziché generare un errore.


Ottimizzare e comprimere i documenti

Document.optimize esegue la deduplicazione di immagini/stream, la raccolta dei rifiuti di oggetti inutilizzati e la compressione dello stream in una sola chiamata. Fornisci un’istanza di OptimizationOptions per controllare quali tecniche vengono eseguite; omettila per utilizzare il profilo di pulizia standard.

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() è un alias di optimize(). Se desideri solo la compressione dello stream senza il passaggio di pulizia strutturale, chiama direttamente doc.compress_streams().


Unire, dividere e modificare i file

Per i documenti che hai già aperto, Document.merge() aggiunge altre istanze di Document a quella corrente:

from aspose_pdf import Document

base = Document("part1.pdf")
extra = Document("part2.pdf")

base.merge(extra)
base.save("combined.pdf", overwrite=True)

Per i flussi di lavoro file-a-file senza aprire un Document da solo, i plugin low-code Merger e Splitter accettano un oggetto MergeOptions/SplitOptions costruito dagli input e output di 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 offre la stessa famiglia di operazioni come una facciata che restituisce True/False invece di generare un’eccezione, il che è comodo per gli script batch:

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 basato su 1 numeri di pagina, a differenza di PageCollectionindicizzazione a base 0 — vedi Problemi comuni di seguito.


Crittografia e sicurezza del documento

Document.encrypt(user_password, owner_password=None, permissions=-4) cifra il documento in memoria; decrypt(password) e change_passwords(old, new_user, new_owner=None) invertono o ruotano le password. is_encrypted e permissions segnalano lo stato attuale.

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)

Aprire un documento crittografato senza password, o con quella errata, genera PdfSecurityException — intercetta questa classe (da aspose_pdf.exceptions) invece di presumere che il caricamento abbia sempre successo.


Metadati, convalida e gestione delle eccezioni

I metadati del documento risiedono su doc.info (un semplice dict[str, str]), e doc.version / doc.id espongono la versione dell’intestazione PDF e l’identificatore del file trailer. validate() (alias check()) segnala l’integrità strutturale; repair() tenta di correggere problemi comuni come una lista di pagine mancante o un MediaBox fuori intervallo.

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 e il conteggio degli oggetti per file non attendibili; chiama PdfLoadLimits.unlimited() per disabilitare tutti i limiti quando ti fidi completamente della sorgente. AsposePdfException è la classe base per l’intera gerarchia di eccezioni (inclusi PdfIOException e PdfSecurityException), quindi un unico except AsposePdfException cattura qualsiasi errore sollevato dalla libreria.


Suggerimenti e migliori pratiche

  • Chiama sempre dispose() (o close()) su un Document quando hai finito di usarlo, oppure usalo come variabile locale a vita breve — il motore mantiene il contenuto delle pagine decodificate e le immagini in memoria fino allo smaltimento.
  • Passa overwrite=True a save() quando riscrivi un percorso che hai già creato nella stessa esecuzione; il valore predefinito è False e genera FileExistsError.
  • Preferisci doc.optimize() prima di distribuire un PDF generato — è una chiamata singola che rimuove gli oggetti inutilizzati e comprime i flussi, e di solito riduce notevolmente la dimensione dell’output.
  • Imposta esplicitamente una politica PdfLoadLimits ogni volta che carichi PDF da una fonte non attendibile (caricamenti, allegati email, estrazioni web); i valori predefiniti sono generosi ma finiti, non rappresentano una barriera di sicurezza su cui fare affidamento ciecamente.
  • Gestisci AsposePdfException (o una sottoclasse specifica come PdfSecurityException) intorno alle chiamate di caricamento/salvataggio invece di usare direttamente Exception — è la base comune per ogni errore sollevato dalla libreria.

Problemi comuni

ProblemaCauseCorrezione
FileExistsError su save()Il percorso di destinazione esiste già e overwrite è stato lasciato al suo valore predefinito FalsePassa save(path, overwrite=True)
UnsupportedFeatureException su save()È stato richiesto un save_format non-PDF (ad es. SaveFormat.PPTX, DocFormat.HTML)Salva come PDF — qualsiasi altro valore SaveFormat/DocFormat solleva UnsupportedFeatureException invece di scrivere l’output
PdfSecurityException: Password required for encrypted documentAperto un PDF crittografato senza l’argomento passwordPassa Document(path, password="...") o chiama load_from(path, password="...")
Errore di uno nei numeri di pagina tra PageCollection e PdfFileEditordoc.pages[i] è basato su 0; gli argomenti di pagina PdfFileEditor.extract()/.insert() sono basati su 1Aggiungi o sottrai 1 quando converti tra le due API
IndexError: Page index out of range. da pages.delete()L’indice passato a delete() non esiste nella collezioneVerifica doc.page_count (o len(doc.pages)) prima di eliminare

FAQ

Devo avere una licenza per usare Aspose.PDF FOSS per Python?

No. Questa è l’edizione open-source (con licenza MIT); non esiste alcun file di licenza né passo di attivazione da configurare.

Posso esportare un Document in formati diversi dal PDF?

Non in questa versione. save() implementa solo l’output PDF — fornire un altro valore SaveFormat/DocFormat genera UnsupportedFeatureException invece di produrre un file con etichetta errata.

Qual è la differenza tra Document.merge() e il plugin Merger?

Document.merge() combina le istanze Document che hai già aperto in memoria. Merger (con MergeOptions e FileDataSource) è un wrapper di convenienza file-a-file che apre, unisce e salva per te in una sola chiamata — utile per script batch semplici che non hanno mai bisogno dell’oggetto intermedio Document.

Perché pages.insert() non solleva mai un’eccezione per un indice fuori intervallo?

PageCollection.insert() limita l’indice all’intervallo valido (i valori negativi diventano 0, i valori oltre la fine diventano len(doc.pages)) invece di sollevare un’eccezione, così un inserimento non fallisce mai solo a causa del valore dell’indice.

Come posso caricare in modo sicuro un PDF da una fonte non affidabile?

Costruisci un PdfLoadLimits con limiti espliciti (max_input_bytes, max_pages, max_objects, e così via) e passalo come argomento limits= a Document(...) o load_from(). Ogni campo ha già un valore finito di default, ma restringerli alla dimensione di input prevista riduce le risorse che un file malformato può consumare.


API Reference Riepilogo

Classe / MetodoDescrizione
Document() / Document.load_fromCrea un documento vuoto o caricane uno da un percorso, da byte o da un flusso binario
Document.saveScrivi il documento su un percorso o su un flusso scrivibile (solo PDF)
Document.dispose() / Document.close()Rilascia le risorse del motore; idempotente
Document.pagesIl PageCollection del documento
Document.infoMetadati del documento come un dict[str, str]
Document.optimize / Document.optimize_resources / Document.compress_streams()Rimuovi le risorse inutilizzate e comprimi i flussi
Document.merge()Accoda altre istanze di Document a questa
Document.encrypt / Document.decrypt / Document.change_passwordsApplica, rimuovi o ruota le password del documento
Document.validate() / Document.check() / Document.repair()Verifica e tenta di correggere l’integrità strutturale
PageCollection.add() / .insert() / .delete() / .item()Modifiche strutturali alla raccolta di pagine (basato su zero)
Page.rect / Page.rotation / Page.indexGeometria e posizione per pagina
OptimizationOptionsFlag di granularità fine consumati da Document.optimize
MergeOptions / MergerPlugin di fusione file-a-file
SplitOptions / SplitterPlugin di divisione file-a-file una pagina per output
FileDataSourceInput/output basato su file per le API del plugin
PdfFileEditorFacade per concatenate(), extract(), insert(), delete(), append() (pagine indicizzate a partire da 1)
PdfLoadLimitsPolicy immutabile di limite delle risorse per input non attendibile
AsposePdfExceptionClasse base per ogni eccezione sollevata dalla libreria
PdfSecurityExceptionSollevata per password mancanti o errate e errori di permessi
PdfIOExceptionSollevata per errori di I/O durante l’elaborazione del PDF

Vedi anche

 Italiano