Comment travailler avec les annotations PDF dans Python
Aspose.PDF FOSS pour Python expose chaque annotation sur une page comme un objet Annotation vivant via le AnnotationCollection de la page, ainsi vous pouvez ajouter des annotations de balisage, de lien et 3D, inspecter leurs propriétés spécifiques au type, et générer les flux d’apparence dont les visionneuses PDF ont besoin pour les rendre — le tout depuis du Python pur. Ce guide montre comment installer la bibliothèque, ajouter des annotations, les lire, et générer leurs flux d’apparence.
Guide étape par étape
Étape 1: installer le package
Installez le package 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 .Vérifiez l’installation en important le module aspose_pdf de niveau supérieur, qui expose la classe Document utilisée dans les étapes suivantes. L’extrait affiche aspose_pdf OK lorsque l’import réussit; un ModuleNotFoundError signifie généralement que le package a été installé dans un environnement Python différent de celui dans lequel votre script s’exécute:
import aspose_pdf
print("aspose_pdf OK")Étape 2 : Importer les classes requises
Importez Document pour contenir le PDF, ainsi que les classes d’annotation que vous utiliserez pour créer et inspecter les annotations:
from aspose_pdf import Document
from aspose_pdf.annotations import (
Annotation,
AnnotationType,
AnnotationFlags,
MarkupAnnotation,
LinkAnnotation,
)Étape 3 : Ajouter une annotation à une page
Chaque Page expose ses annotations via la propriété annotations, un AnnotationCollection. Appelez add(subtype, rect, contents) avec un nom de sous-type, un rectangle (left, bottom, right, top) et le contenu texte de l’annotation. Les sous-types de balisage standard tels que "Highlight" sont retournés sous forme d’instance 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Étape 4 : Créer des annotations à partir de sous-types d’énumération
AnnotationType répertorie chaque sous-type d’annotation PDF standard (PDF 32000-1:2008, tableau 169), de sorte que vous puissiez fournir un membre d’énumération au lieu d’une chaîne brute. Les données spécifiques au type — par exemple les sommets d’un polygone — sont placées dans le dictionnaire properties et sont récupérées avec 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]Étape 5 : Lire et parcourir les annotations existantes
AnnotationCollection est itérable, vous pouvez donc parcourir chaque annotation déjà présente sur une page — y compris celles chargées depuis un PDF existant — et lire les propriétés communes que chaque Annotation expose (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)Étape6: Générer les flux d’apparence des annotations
Une annotation créée sans appearance_normal explicite n’a aucun rendu visible (/AP /N) tant qu’il n’est pas généré. Appelez generate_appearance(force) sur une seule Annotation, ou generate_appearances(force) sur l’ensemble du AnnotationCollection pour synthétiser chaque flux d’apparence manquant sur la page en une fois:
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)")Étape7: Distinguer les sous-classes d’annotation
AnnotationCollection.add() répartit vers une sous-classe spécifique en fonction du sous-type: les sous-types de type balisage (Highlight, Square, Stamp et similaires) reviennent en tant que MarkupAnnotation, et "Link" revient en tant que LinkAnnotation. Les deux héritent de toutes les méthodes et propriétés de Annotation, ainsi les vérifications isinstance vous permettent de vous ramifier selon le type d’annotation sans inspecter directement les chaînes 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)) # TrueProblèmes courants et correctifs
get_property returns None pour une propriété que je viens de définir
Les clés properties sont des noms de champs PDF exacts, sensibles à la casse ("Vertices", "Name" et similaires) — une faute de frappe ou une mauvaise casse est silencieusement ignorée plutôt que levée. Passez un argument default à get_property(name, default) et vérifiez-le explicitement lors du débogage d’un nouveau sous-type.
generate_appearance() returns False
Toutes les combinaisons de sous-type et de propriété ne peuvent pas être synthétisées en flux d’apparence par le générateur intégré. Vérifiez has_appearance avant de supposer que l’appel a réussi, et fournissez un appearance_normal pré-rendu (bytes) directement sur add() pour les sous-types que le générateur ne couvre pas.
Sous-classe d’annotation inattendue après add()
La chaîne de sous-type (ou le membre AnnotationType) que vous transmettez détermine la classe renvoyée: les sous-types de balisage reviennent sous la forme MarkupAnnotation, "Link" revient sous la forme LinkAnnotation, et tout autre sous-type reconnu revient sous la forme de base Annotation. Utilisez isinstance() contre MarkupAnnotation/LinkAnnotation plutôt que de supposer une chaîne de sous-type spécifique.
AnnotationFlags les valeurs ne semblent pas modifier le rendu
AnnotationFlags (PRINT, HIDDEN, NO_ZOOM, READ_ONLY, et similaires) est une énumération Python IntFlag standard pour composer et interpréter les bits de comportement d’une annotation avec l’opérateur | — c’est un type valeur, pas une propriété que Annotation.add() écrit automatiquement. Combinez les indicateurs dont vous avez besoin et transmettez-les via le même mécanisme properties spécifique au type utilisé pour d’autres données spécifiques au sous-type.
Travailler avec une page qui n’a pas encore d’annotations
page.annotations est toujours un AnnotationCollection valide (éventuellement vide) — vous n’avez jamais besoin de vérifier None avant d’appeler add(), d’itérer, ou d’appeler clear().
Foire aux questions
Quels sous-types d’annotation Aspose.PDF FOSS pour Python prend-il en charge?
AnnotationType répertorie les 25 sous-types standards du PDF 32000-1:2008 Table 169, y compris TEXT, LINK, FREE_TEXT, LINE, SQUARE, CIRCLE, POLYGON, HIGHLIGHT, STAMP, INK, FILE_ATTACHMENT, REDACT, et d’autres.
Cette bibliothèque prend-elle en charge les annotations 3D?
Oui. PDF3DAnnotation, ainsi que PDF3DArtwork, PDF3DContent, PDF3DView, PDF3DLightingScheme, et PDF3DRenderMode, modélise une surface d’annotation PDF 3D minimale (un rectangle, un artwork intégré et des vues nommées) pour les flux de travail PDF 3D en préversion. Voir le référence PDF3DAnnotation pour son ensemble complet de propriétés.
Comment supprimer une annotation d’une page?
Appelez page.annotations.delete(index) pour supprimer une annotation par position, ou page.annotations.clear() pour supprimer toutes les annotations de la page.
Puis-je insérer une annotation à une position spécifique au lieu de l’ajouter à la fin?
Oui — AnnotationCollection.insert(index, subtype, rect, contents, title, appearance_normal, properties) prend les mêmes arguments que add() plus la cible index.
Comment la couleur d’une annotation est-elle représentée?
La propriété color sur Annotation (et ses sous-classes) est un tuple[float, ...] correspondant au nombre de composants de l’entrée PDF /C (vide lorsque la couleur n’est pas définie) — pas un objet couleur dédié.