Article Technique

XFDF Export and Import in Delphi with PDFium Component

Le composant PDFium Component pour Delphi et Lazarus échange les données de formulaire et les annotations via XFDF, le format d'échange XML défini par la norme ISO 19444-1. TPdf.ExportXFDF sérialise chaque valeur de champ de formulaire et chaque annotation prise en charge du document chargé vers un fichier XFDF ou un flux TStream ; TPdf.ImportXFDF lit un document XFDF en retour, recréant les annotations sur leurs pages respectives et appliquant les valeurs aux champs. Cet aller-retour couvre deux flux de travail dont toute application de gestion de documents a besoin : un réviseur annote un PDF dans Acrobat et vous envoie les commentaires à fusionner, ou une règle de conformité exige que les données du formulaire résident dans un fichier distinct, comparable et vérifiable, plutôt que d'être intégrées au PDF lui-même

PDFium prend-il en charge l'importation et l'exportation XFDF ?

La bibliothèque PDFium elle-même ne le fait pas. L'API C native ne possède aucune fonction XFDF ou FDF — rien dans ses en-têtes publics ne lit ou n'écrit l'un ou l'autre format. Par conséquent, le composant PDFium Component implémente l'intégralité du moteur XFDF en Pascal, dans une unité dédiée qui construit et analyse le XML directement par-dessus le modèle de données existant des annotations et des champs de formulaire de TPdf. Le générateur écrit le XML manuellement et le lecteur est un analyseur de type machine à états écrit à la main, de sorte que la fonctionnalité n'ajoute aucune dépendance vis-à-vis de XMLDoc de Delphi ou des unités DOM de FPC, et se comporte de manière identique sur Delphi et Lazarus

Ce choix de conception est crucial lorsque vous évaluez les alternatives. Si vous appeliez des fonctions FPDF_* brutes depuis Pascal, XFDF serait une impasse : cette fonctionnalité n'existe tout simplement pas dans la DLL. Le composant contourne cet obstacle en traitant XFDF comme un pur problème de sérialisation — collecter les valeurs de champs et les enregistrements d'annotations que le wrapper sait déjà lire, les exporter sous forme de XML standard, et inverser le processus à l'importation

Que contient un fichier XFDF ?

La norme ISO 19444-1 définit XFDF comme la représentation XML de FDF, et son contenu se divise en deux blocs de premier niveau. L'élément <fields> contient les noms de champs hiérarchiques et leurs valeurs — tout ce qu'un utilisateur a saisi, sélectionné ou coché dans un AcroForm. L'élément <annots> contient les annotations : TPdf.ExportXFDF exporte 18 sous-types — text, highlight, underline, strikeout, squiggly, line, circle, square, caret, polygon, polyline, stamp, ink, freetext, fileattachment, sound, link et redact. Les annotations de type Widget sont délibérément absentes de l'élément <annots> car leurs données transitent par l'élément <fields>, et les sous-types internes au visualiseur comme Popup ne font pas partie du vocabulaire XFDF

Pour assurer la fidélité de l'aller-retour, l'enregistrement TPdfAnnotation a été étendu avec les métadonnées attendues par XFDF : Name (l'identifiant unique NM), Subject, ModificationDate, CreationDate, Icon, Opacity, les coordonnées de début et de fin de ligne, les sommets de polygones et de polylignes, et les tracés de gestes manuscrits (ink). Chaque nouveau champ est associé à une sentinelle booléenne Has*, de sorte que le code écrit pour des versions antérieures continue de compiler et de produire les mêmes dictionnaires — un champ non renseigné n'étant jamais écrit. Si vous créez déjà des annotations par programmation, le même enregistrement que vous utilisez pour les annotations de balisage de texte avec quad points contient désormais tout ce dont XFDF a besoin

Comment exporter les données de formulaire et les annotations au format XFDF ?

Un seul appel traite l'intégralité du document. Chargez le PDF en activant le remplissage de formulaire, appelez ExportXFDF, et le composant parcourt chaque page, collecte les valeurs de champs et les annotations, puis génère le XML. La valeur de retour correspond au nombre d'octets UTF-8 écrits, ce qui constitue une vérification rapide de cohérence dans les journaux

var
  Pdf: TPdf;
  Bytes: Integer;
begin
  Pdf := TPdf.Create(Self);
  Pdf.FormFill := True;            // needed so field values are live
  Pdf.FileName := 'expense-report.pdf';
  Pdf.Active := True;
  Bytes := Pdf.ExportXFDF('expense-report.xfdf');
  ShowMessage(Format('%d bytes of XFDF written', [Bytes]));
end;

Les deux directions disposent d'une surcharge TStream, ce qui évite d'avoir à créer un fichier temporaire sur le disque. L'exportation vers un flux TMemoryStream est idéale lorsque le contenu XFDF est destiné à une réponse HTTP, un champ blob de base de données ou une entrée d'archive signée

var
  Buffer: TMemoryStream;
begin
  Buffer := TMemoryStream.Create;
  try
    Pdf.ExportXFDF(Buffer);        // same XML, no file involved
    Buffer.Position := 0;
    // hand the stream to a web response, blob column, or zip entry
  finally
    Buffer.Free;
  end;
end;

Comment ImportXFDF réintègre-t-il les commentaires dans le document ?

C'est à l'importation que se boucle le flux de travail de révision. Un collègue annote le contrat dans Acrobat, exporte les commentaires en XFDF et vous envoie quelques kilo-octets de XML au lieu d'une copie du PDF. TPdf.ImportXFDF analyse ce fichier, crée chaque annotation sur la page désignée par son attribut page, et écrit les valeurs dans les annotations Widget correspondantes. La fonction renvoie le nombre cumulé de champs et d'annotations appliqués, permettant à l'interface utilisateur de confirmer le volume de données importées

var
  Applied: Integer;
begin
  Applied := Pdf.ImportXFDF('review-comments.xfdf');
  StatusBar.SimpleText :=
    Format('%d fields and annotations merged', [Applied]);
end;

L'analyseur est un scanner de balises écrit à la main, conçu pour être tolérant plutôt que strict : les éléments inconnus sont ignorés, les instructions de traitement, les déclarations DOCTYPE et les commentaires sont écartés, les indicateurs non reconnus sont rejetés et les valeurs d'attributs sont décodées en gérant toutes les entités XML et références de caractères numériques, y compris les paires de substitution UTF-16. Les fichiers XFDF produits par Acrobat, par un visualiseur web ou par d'autres outils s'intègrent sans difficulté. Une fois les annotations intégrées au document, le cycle de révision se poursuit avec le mécanisme de réponse et de statut décrit dans la mise en place d'un flux de révision d'annotations avec le composant PDFium Component, et les valeurs de champs importées participent à la logique de navigation habituelle traitée dans la navigation dans les champs de formulaire

Pourquoi les séparateurs décimaux sont-ils importants pour le format XFDF ?

Toute annotation dans XFDF is positionnée par des chaînes de coordonnées — rect="70.5,540,200,560" et consorts — et la norme ISO 19444-1 impose le point comme séparateur décimal. Le formatage de nombres réels par défaut de Delphi suit les paramètres régionaux de Windows. Ainsi, sur un système français ou allemand, un simple FloatToStr transforme 70.5 en 70,5, ce qui corrompt une liste de coordonnées séparées par des virgules en générant des données incorrectes que les autres moteurs rejetteront ou liront mal. Le composant PDFium Component normalise chaque nombre qu'il écrit : le séparateur décimal local est remplacé par un point et les zéros non significatifs sont supprimés, de sorte que le fichier exporté est identique au niveau des octets qu'il ait été produit sur une machine configurée en anglais ou en français. Si vous avez déjà eu à déboguer un outil PDF qui fonctionnait au bureau mais échouait chez un client en Europe continentale, vous avez été confronté à cette classe de bugs — le composant la gère pour vous

Quelles sont les limites de cet aller-retour ?

Deux limites méritent d'être formulées clairement. Premièrement, le format XFDF transporte les données d'annotation, pas leur rendu visuel — les flux d'apparence (appearance streams) ne font pas partie du format, de sorte que le visualiseur récepteur régénère l'aspect de chaque annotation à partir de ses propriétés. Un surlignage ou un carré s'affichera correctement partout ; un tampon personnalisé s'en remettra à ce que le visualiseur cible dessine pour ce nom de tampon. Deuxièmement, l'API PDFium sous-jacente possède des méthodes d'écriture pour les chaînes mais aucune pour les valeurs numériques d'annotations ou la géométrie des tracés. Ainsi, l'opacité (Opacity), les extrémités de lignes, les sommets et les tracés manuscrits sont en mode export uniquement : le composant les préserve fidèlement lors de l'écriture XFDF, mais ne peut les réinjecter dans le PDF lors de l'importation. Les valeurs de champs, les contenus, les couleurs, les rectangles de positionnement, les quad points, les dates et les métadonnées d'identité font l'objet d'un aller-retour complet dans les deux directions

Pour démarrer rapidement, le projet d'exemple XfdfLab fourni avec les démonstrations Delphi, C++Builder et Lazarus associe ces deux appels à des boutons applicables à tout PDF ouvert. La prise en charge de XFDF est intégrée dans la version actuelle du composant PDFium Component, aux côtés des API d'annotations et de formulaires sur lesquelles elle repose