Come lavorare con le annotazioni PDF in Python

Come lavorare con le annotazioni PDF in Python

Aspose.PDF FOSS per Python espone ogni annotazione su una pagina come un oggetto Annotation live tramite il AnnotationCollection della pagina, così puoi aggiungere annotazioni di markup, link e 3D, ispezionare le loro proprietà specifiche del tipo e generare i flussi di aspetto di cui i visualizzatori PDF hanno bisogno per renderizzarle — tutto da puro Python. Questa guida mostra come installare la libreria, aggiungere annotazioni, leggerle e generare i loro flussi di aspetto.

Guida passo-passo

Passo 1: Installa il pacchetto

Installa il pacchetto FOSS Aspose.PDF:

git clone https://github.com/aspose-pdf-foss/Aspose-PDF-FOSS-for-Python.git
cd Aspose-PDF-FOSS-for-Python
pip install -e .

Verifica l’installazione importando il modulo aspose_pdf di livello superiore, che espone la classe Document usata nei passaggi seguenti. Lo snippet stampa aspose_pdf OK quando l’importazione ha successo; un ModuleNotFoundError solitamente indica che il pacchetto è stato installato in un ambiente Python diverso da quello in cui viene eseguito lo script:

import aspose_pdf
print("aspose_pdf OK")

Passo 2: Importa le classi richieste

Importa Document per contenere il PDF, più le classi di annotazione che utilizzerai per creare e ispezionare le annotazioni:

from aspose_pdf import Document
from aspose_pdf.annotations import (
    Annotation,
    AnnotationType,
    AnnotationFlags,
    MarkupAnnotation,
    LinkAnnotation,
)

Passo 3: Aggiungi un’annotazione a una pagina

Ogni Page espone le sue annotazioni tramite la proprietà annotations, un AnnotationCollection. Chiama add(subtype, rect, contents) con un nome di sottotipo, un rettangolo (left, bottom, right, top) e il contenuto testuale dell’annotazione. I sottotipi di markup standard come "Highlight" vengono restituiti come un’istanza MarkupAnnotation:

from aspose_pdf import Document

document = Document()
document.pages.add()
page = document.pages[0]

annotation = page.annotations.add(
    "Highlight",
    (100, 700, 300, 720),
    "Key clause",
)
print(type(annotation).__name__)   # MarkupAnnotation
print(annotation.contents)         # Key clause

Passo 4: Crea annotazioni da sottotipi enum

AnnotationType elenca tutti i sottotipi standard di annotazione PDF (PDF 32000-1:2008, Tabella 169), così puoi passare un membro enum invece di una stringa grezza. I dati specifici del tipo — come i vertici di un poligono — vanno nel dizionario properties e vengono letti nuovamente con get_property:

from aspose_pdf import Document
from aspose_pdf.annotations import AnnotationType

document = Document()
document.pages.add()
page = document.pages[0]

annotation = page.annotations.add(
    AnnotationType.POLYGON,
    (0, 0, 10, 10),
    "",
    properties={"Vertices": [0, 0, 10, 0, 5, 10]},
)
print(annotation.subtype)                    # Polygon
print(annotation.get_property("Vertices"))   # [0, 0, 10, 0, 5, 10]

Passo 5: Leggi e itera le annotazioni esistenti

AnnotationCollection è iterabile, così puoi attraversare ogni annotazione già presente su una pagina — incluse quelle caricate da un PDF esistente — e leggere le proprietà comuni che ogni Annotation espone (subtype, contents, rect, title, author, color):

from aspose_pdf import Document

document = Document()
document.pages.add()
page = document.pages[0]
page.annotations.add("Text", (50, 50, 70, 70), "First note")
page.annotations.add("Text", (80, 80, 100, 100), "Second note")

for annotation in page.annotations:
    print(annotation.subtype, "-", annotation.contents)

Passo 6: Genera flussi di aspetto dell’annotazione

Un’annotazione creata senza un appearance_normal esplicito non ha alcuna resa visibile (/AP /N) finché non viene generata. Chiama generate_appearance(force) su un singolo Annotation, oppure generate_appearances(force) sull’intero AnnotationCollection per sintetizzare tutti i flussi di aspetto mancanti nella pagina in una volta:

from aspose_pdf import Document
from aspose_pdf.engine.cos import AnnotationName

document = Document()
document.pages.add()
page = document.pages[0]

stamp = page.annotations.add(
    "Stamp",
    (100, 100, 260, 150),
    "",
    properties={"Name": AnnotationName("Approved")},
)
if stamp.generate_appearance():
    print(f"Appearance stream: {len(stamp.appearance_normal)} byte(s)")

# Regenerate every missing appearance stream on the page in one call:
count = page.annotations.generate_appearances(force=True)
print(f"Regenerated {count} appearance stream(s)")

Passo 7: Distinguere le sottoclassi delle annotazioni

AnnotationCollection.add() indirizza a una specifica sottoclasse in base al sottotipo: i sottotipi in stile markup (Highlight, Square, Stamp e simili) ritornano come MarkupAnnotation, e "Link" ritorna come LinkAnnotation. Entrambi ereditano tutti i metodi e le proprietà da Annotation, così i controlli isinstance ti consentono di ramificare sul tipo di annotazione senza ispezionare direttamente le stringhe subtype:

from aspose_pdf import Document
from aspose_pdf.annotations import LinkAnnotation, MarkupAnnotation

document = Document()
document.pages.add()
page = document.pages[0]

link = page.annotations.add("Link", (50, 750, 200, 770), "")
highlight = page.annotations.add("Highlight", (50, 700, 200, 720), "")

print(isinstance(link, LinkAnnotation))         # True
print(isinstance(highlight, MarkupAnnotation))  # True

Problemi comuni e correzioni

get_property returns None per una proprietà che ho appena impostato

properties le chiavi sono nomi di campo PDF esatti, sensibili al maiuscolo/minuscolo ("Vertices", "Name" e simili) — un errore di battitura o un caso errato viene silenziosamente ignorato anziché generare un’eccezione. Passa un argomento default a get_property(name, default) e controllalo esplicitamente durante il debug di un nuovo sottotipo.

generate_appearance() returns False

Non tutte le combinazioni di sottotipo e proprietà possono essere sintetizzate in un flusso di aspetto dal generatore integrato. Controlla has_appearance prima di presumere che la chiamata sia riuscita, e fornisci un appearance_normal pre-renderizzato (bytes) direttamente su add() per i sottotipi che il generatore non copre.

Sottoclasse di annotazione inattesa dopo add()

La stringa del sottotipo (o il membro AnnotationType) che fornisci determina la classe restituita: i sottotipi di markup ritornano come MarkupAnnotation, "Link" ritorna come LinkAnnotation, e qualsiasi altro sottotipo riconosciuto ritorna come il Annotation di base. Usa isinstance() contro MarkupAnnotation/LinkAnnotation invece di presumere una stringa di sottotipo specifica.

AnnotationFlags i valori non sembrano cambiare il rendering

AnnotationFlags (PRINT, HIDDEN, NO_ZOOM, READ_ONLY e simili) è un enum standard Python IntFlag per comporre e interpretare i bit di comportamento di un’annotazione con l’operatore | — è un tipo valore, non una proprietà che Annotation.add() scrive automaticamente. Combina le flag necessarie e passale attraverso lo stesso meccanismo properties specifico per tipo usato per altri dati specifici del sottotipo.

Lavorare con una pagina che non ha ancora annotazioni

page.annotations è sempre un AnnotationCollection valido (potenzialmente vuoto) — non è mai necessario controllare None prima di chiamare add(), iterare o chiamare clear().

Domande frequenti

Quali sottotipi di annotazione supporta Aspose.PDF FOSS per Python?

AnnotationType elenca tutti i 25 sottotipi standard della Tabella 169 del PDF 32000-1:2008, inclusi TEXT, LINK, FREE_TEXT, LINE, SQUARE, CIRCLE, POLYGON, HIGHLIGHT, STAMP, INK, FILE_ATTACHMENT, REDACT e altri.

Questa libreria supporta le annotazioni 3D?

Sì. PDF3DAnnotation, insieme a PDF3DArtwork, PDF3DContent, PDF3DView, PDF3DLightingScheme, e PDF3DRenderMode, modella una superficie di annotazione PDF 3D minimale (un rettangolo, un’opera d’arte incorporata e viste nominate) per i flussi di lavoro PDF 3D prerelease. Vedi il riferimento PDF3DAnnotation per il suo set completo di proprietà.

Come rimuovo un’annotazione da una pagina?

Chiama page.annotations.delete(index) per rimuovere un’annotazione in base alla posizione, oppure page.annotations.clear() per rimuovere tutte le annotazioni nella pagina.

Posso inserire un’annotazione in una posizione specifica invece di aggiungerla alla fine?

Sì — AnnotationCollection.insert(index, subtype, rect, contents, title, appearance_normal, properties) accetta gli stessi argomenti di add() più il target index.

Come viene rappresentato il colore di un’annotazione?

La proprietà color su Annotation (e le sue sottoclassi) è un tuple[float, ...] che corrisponde al conteggio dei componenti della voce PDF /C (vuoto quando il colore non è impostato) — non un oggetto colore dedicato.

Vedi anche

 Italiano