💡 Exemple complet disponible sur GitHub :
extract-annotations-from-pdf-using-groupdocs-parser-dotnet

Introduction

Un PDF qui a été révisé contient généralement plus que son texte visible : notes autocollantes, remarques surlignées et commentaires en ligne laissés par les relecteurs. Faire défiler chaque page pour les trouver ne fonctionne pas lorsqu’un document a traversé plusieurs cycles de commentaires. GroupDocs.Parser est une bibliothèque .NET qui lit les annotations intégrées d’un document de façon programmatique, transformant les commentaires dispersés des relecteurs en données structurées que votre code peut exploiter. Ce tutoriel montre comment extraire les annotations d’un PDF complet, les détailler page par page, les associer au texte du document, puis exporter les résultats au format CSV ou JSON.

J’ai rencontré ce problème en construisant un suivi de révision pour une équipe de documentation : une note de version de 40 pages était passée par trois relecteurs, et ouvrir manuellement le fichier pour trouver chaque commentaire prenait plus de temps que de corriger les problèmes signalés. Extraire les annotations en quelques lignes de code a transformé cela en une tâche de deux minutes.

Dans les sections suivantes, vous apprendrez à :

  • Extraire chaque annotation d’un PDF en un seul passage.
  • Associer chaque annotation à la page à laquelle elle appartient.
  • Récupérer le texte du document et le texte des annotations ensemble en une seule lecture.
  • Sérialiser les résultats en CSV ou JSON pour les outils en aval.

Pourquoi extraire les annotations PDF est important

Lire les annotations PDF de façon programmatique est utile pour :

  • Flux de travail de révision : collecter chaque commentaire de relecteur sans ouvrir le fichier dans un visualiseur PDF.
  • Collaboration : mettre en avant les sections surlignées ou notées directement dans vos propres outils.
  • Audit : conserver un enregistrement du balisage laissé sur un document au fil du temps, même après qu’il ait été aplati ou finalisé.

GroupDocs.Parser a ajouté l’extraction native des annotations pour les documents PDF dans la version 26.7 via la méthode GetAnnotations, ainsi qu’une nouvelle option IncludeAnnotations sur TextOptions pour intégrer le texte des annotations dans une lecture de texte ordinaire.

Prérequis

  • .NET 6.0 ou version ultérieure
  • GroupDocs.Parser for .NET 26.7+ (licence temporaire)
  • Un fichier PDF contenant des annotations existantes (par ex., document-with-annotations.pdf)

Installation via NuGet :

dotnet add package GroupDocs.Parser

Comment extraire les annotations d’un document PDF ?

Réponse : Chargez le fichier avec Parser, puis appelez GetAnnotations() pour le document entier ou GetAnnotations(pageIndex) pour une page unique. Chaque résultat est une collection d’objets AnnotationItem dont la propriété Value contient le texte du commentaire. Si vous préférez voir les commentaires intégrés au contenu régulier du document, activez IncludeAnnotations sur TextOptions et appelez GetText à la place.

Extraction du document complet

L’extrait suivant récupère chaque annotation du fichier en un seul appel, ce qui est la façon la plus rapide de vérifier si un document possède des commentaires ouverts.

// Extract every annotation from the whole document
var result = new List<string>();
using (var parser = new Parser(path))
{
    IEnumerable<AnnotationItem> annotations = parser.GetAnnotations();
    if (annotations == null)
    {
        return result; // format doesn't support annotations
    }

    foreach (var item in annotations)
    {
        result.Add(item.Value); // annotation text
    }
}
return result;

Points clés :

  • GetAnnotations() renvoie null lorsque l’extraction d’annotations n’est pas prise en charge pour le document, et une collection vide lorsque le document n’en possède tout simplement aucune.
  • Chaque AnnotationItem expose son texte via la propriété Value — c’est le seul point de données que le SDK rapporte actuellement.
  • Aucune attribution de page n’est incluse ici ; utilisez la surcharge par page ci‑dessous si vous en avez besoin.

Extraction page par page

Lorsque l’emplacement d’un commentaire importe, parcourez les pages du document et appelez GetAnnotations(pageIndex) pour chacune d’elles.

// Tag each annotation with its zero-based page index
var result = new List<AnnotationRecord>();
using (var parser = new Parser(path))
{
    if (!parser.Features.Annotations)
    {
        return result;
    }

    var info = parser.GetDocumentInfo();
    if (info == null || info.PageCount == 0)
    {
        return result;
    }

    for (int pageIndex = 0; pageIndex < info.PageCount; pageIndex++)
    {
        IEnumerable<AnnotationItem> pageAnnotations = parser.GetAnnotations(pageIndex);
        if (pageAnnotations == null)
        {
            continue;
        }

        foreach (var item in pageAnnotations)
        {
            result.Add(new AnnotationRecord { PageIndex = pageIndex, Value = item.Value });
        }
    }
}
return result;

Points clés :

  • GetDocumentInfo().PageCount pilote la boucle ; il n’existe pas de « compte de pages d’annotation ».
  • GetAnnotations(pageIndex) utilise un indice zéro‑based, comme toutes les autres méthodes de niveau page de l’API.
  • La liste résultante AnnotationRecord a exactement la forme requise pour une exportation CSV ou JSON.

Extraction du texte avec les annotations

Au lieu de deux passages sur le document, vous pouvez intégrer le texte des annotations directement dans la sortie d’extraction de texte ordinaire.

// Read document text with annotation text included
using (var parser = new Parser(path))
{
    var options = new TextOptions
    {
        IncludeAnnotations = true
    };

    using (TextReader reader = parser.GetText(options))
    {
        return reader?.ReadToEnd() ?? string.Empty;
    }
}

Points clés :

  • IncludeAnnotations est une propriété de TextOptions, donc cela fonctionne avec le même appel GetText que vous utilisez déjà pour l’extraction de texte brut.
  • Utile lorsque vous souhaitez une sortie de type transcription unique plutôt qu’une liste de commentaires séparée.
  • Combinez‑le avec GetText(pageIndex, options) si vous ne le voulez que pour une page.

Vérifier la prise en charge des annotations au préalable

Tous les formats ne supportent pas les annotations, il est donc judicieux de vérifier avant de bâtir une logique autour de GetAnnotations.

// Returns true if the loaded document format supports annotation extraction
using (var parser = new Parser(path))
{
    return parser.Features.Annotations;
}

Points clés :

  • Features.Annotations est un simple drapeau booléen sur l’instance Parser.
  • Le vérifier dès le départ rend l’intention explicite, même si GetAnnotations échoue déjà proprement en renvoyant null.

Exportation des annotations au format CSV

Une exportation CSV permet aux relecteurs d’ouvrir la liste des commentaires directement dans Excel. La méthode ci‑dessous écrit un fichier à deux colonnes (page,value) à partir des enregistrements tagués par page créés précédemment.

var sb = new StringBuilder();
sb.AppendLine("page,value");

foreach (var record in records)
{
    sb.AppendLine($"{record.PageIndex},{CsvEscape(record.Value)}");
}

File.WriteAllText(outputPath, sb.ToString());

Points clés :

  • CsvEscape cite en toute sécurité les champs contenant des virgules, des guillemets ou des sauts de ligne.
  • Le fichier résultant s’ouvre directement dans Excel ou peut être acheminé vers un outil de ticketing.

Helper : CsvEscape

if (string.IsNullOrEmpty(s)) return string.Empty;
if (s.Contains(",") || s.Contains("\"") || s.Contains("\n"))
{
    return "\"" + s.Replace("\"", "\"\"") + "\"";
}
return s;

Exportation des annotations au format JSON

Pour les pipelines qui consomment les commentaires de façon programmatique, un tableau JSON est généralement plus adapté qu’un CSV plat.

var sb = new StringBuilder();
sb.AppendLine("[");

for (int i = 0; i < records.Count; i++)
{
    var comma = i < records.Count - 1 ? "," : string.Empty;
    sb.AppendLine($"  {{ \"page\": {records[i].PageIndex}, \"value\": \"{Escape(records[i].Value)}\" }}{comma}");
}

sb.AppendLine("]");
File.WriteAllText(outputPath, sb.ToString());

Points clés :

  • La sortie est un tableau plat d’objets { page, value } — facile à désérialiser pour n’importe quel service en aval.
  • Escape maintient la charge utile JSON valide sans faire appel à une bibliothèque de sérialisation.

Helper : Escape

return s?.Replace("\\", "\\\\").Replace("\"", "\\\"") ?? string.Empty;

Comparaison des méthodes : quand utiliser laquelle

Méthode Idéal pour Principaux avantages Limitations
Extraction du document complet Vérification rapide « des commentaires existent‑t‑ils ? » Un appel unique, code le plus simple Pas d’attribution de page
Extraction page par page Diriger les retours vers la bonne section Résultats tagués par page, prêts à exporter Un appel supplémentaire par page
Texte combiné + Annotations Transcript unique lisible Pas de second passage sur le document Les commentaires ne sont pas séparés du texte principal
Export CSV Suivi de révision basé sur tableur Ouverture facile dans Excel, lisible par l’homme Structure plate uniquement
Export JSON Pipelines automatisés, systèmes de ticketing Structuré, lisible par machine Charge légèrement plus importante

Commencez par l’extraction du document complet pour confirmer qu’un fichier possède des commentaires, puis passez à l’extraction page par page lorsque vous devez orienter le feedback vers une section précise.

Bonnes pratiques et astuces

  • Libérez Parser rapidement : encapsulez‑le dans un bloc using pour libérer les ressources natives.
  • Distinguisez null d’une collection vide : GetAnnotations renvoyant null signifie que le format n’est pas supporté ; une collection vide signifie que le document n’a aucun commentaire.
  • Vérifiez Features.Annotations dans les jobs batch : ignorez les fichiers non supportés dès le départ plutôt que de compter sur un test null en profondeur de boucle.
  • Réutilisez la liste taguée par page : construisez‑la une fois avec ExtractAnnotationsByPage et alimentez à la fois les exportateurs CSV et JSON à partir des mêmes données, afin que les deux sorties ne divergent jamais.
  • Sécurité : le texte des annotations est une entrée libre du relecteur – traitez‑le comme toute autre chaîne non fiable avant de l’afficher dans une UI ou un rapport.

Conclusion

GroupDocs.Parser vous offre un moyen direct et programmatique d’extraire les commentaires des relecteurs d’un PDF au lieu de les chercher manuellement. En extrayant les annotations pour le document entier, en les taguant par page ou en les intégrant au flux de texte ordinaire, vous pouvez créer des flux de travail de révision qui font remonter le feedback dès que le document entre dans votre pipeline. Exportez les résultats en CSV ou JSON et intégrez‑les directement aux outils déjà utilisés par votre équipe.

Prochaines étapes :

Ressources supplémentaires