La bibliothèque PDF losLab transfère les données de formulaire vers et depuis un PDF de trois manières différentes : FDF et XFDF pour les valeurs de champ AcroForm, ces deux mêmes formats pour les commentaires d'annotation, et un paquet XFA XDP entier écrit directement dans le formulaire. ExportFormDataToXFDF, ImportFormDataFromXFDF, ImportAnnotationsFromFDF, ExportAnnotationsToXFDF et SetXFAFromString sont les points d'entrée, et chacun d'eux dispose d'une variante fichier et d'une variante chaîne de caractères
La raison pour laquelle il existe tant de méthodes est que les données de formulaire PDF ne se limitent pas à une seule chose. Un formulaire AcroForm rempli contient des valeurs de champ, il peut également comporter des commentaires de révision, et un ancien formulaire XFA intègre une description d'application XML entière qui n'a rien à voir avec les deux autres. La bibliothèque PDF losLab maintient volontairement ces trois préoccupations sur des API distinctes, car les fusionner imposerait un modèle de données incorrect à au moins deux d'entre elles. Décider de quelle famille vous avez besoin est le premier choix de conception, et il est généralement réglé dès que vous savez ce que le système récepteur de l'autre côté consomme réellement
Quelle est la différence entre les données de formulaire FDF, XFDF et XFA ?
FDF et XFDF transportent les mêmes informations dans deux syntaxes d'écriture différentes, et XFA est un monde à part. FDF est un document miniature en syntaxe PDF (ISO 32000-2 §12.7.8) : un tableau /Fields de dictionnaires << /T (nom) /V (valeur) >>, avec des chaînes échappées exactement de la même manière que les chaînes littérales à l'intérieur d'un PDF. XFDF est la forme XML des mêmes données (ISO 19444), un arbre <fields> qu'Acrobat et la plupart des back-ends de formulaires lisent et écrivent nativement. XFA n'est ni l'un ni l'autre : il s'agit d'un modèle XML Forms Architecture plus ses données, stocké sous forme de package de données XML (XDP) auquel le PDF fait référence depuis /AcroForm/XFA. Choisissez FDF ou XFDF lorsque vous interopérez sur des valeurs de champ, et ne recourez à XFA que lorsque vous gérez un document conçu à l'origine comme un formulaire XFA
Au sein de FDF et XFDF, la bibliothèque PDF losLab trace une seconde ligne : les valeurs de champ par rapport aux commentaires d'annotation. La famille de données de formulaire (ExportFormDataToFDF, ImportFormDataFromFDF, ExportFormDataToXFDF, ImportFormDataFromXFDF) lit et écrit la sous-arborescence /Fields et ne touche à rien d'autre. La famille d'annotations (ExportAnnotationsToFDF, ImportAnnotationsFromFDF, ExportAnnotationsToXFDF, ImportAnnotationsFromXFDF) lit et écrit la sous-arborescence /Annots à la place, ce qu'Acrobat entend par Exporter les commentaires. Les deux ne se chevauchent jamais, de sorte que l'exportation des valeurs de champ ne récupérera pas les notes de révision éparses, et l'importation des commentaires ne perturbera pas les valeurs qu'un utilisateur a déjà saisies. Ce qu'un widget fait lorsqu'il est cliqué ou recalculé est une troisième préoccupation, abordée dans la note complémentaire sur les actions de formulaire interactives et JavaScript
Comment remplir un formulaire PDF à partir de FDF ou XFDF dans Delphi ?
Chargez le document, appelez une méthode d'importation, puis enregistrez. ImportFormDataFromXFDF et ImportFormDataFromFDF analysent chacun les données de formulaire entrantes, font correspondre chaque entrée à un champ AcroForm par son nom complet, définissent la valeur et renvoient le nombre de champs réellement mis à jour. Les deux méthodes ne mettent à jour que les champs qui existent déjà dans le PDF cible ; aucune ne crée de champ pour un nom que le formulaire ne définit pas, ce qui empêche un fichier de données erroné ou hostile de faire grossir silencieusement votre formulaire
var
Lib: TPDFlib;
FieldsSet: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('application-blank.pdf', '');
// XFDF produced by a case-management system, already UTF-8 on disk
FieldsSet := Lib.ImportFormDataFromXFDF('applicant-1042.xfdf');
if FieldsSet > 0 then
Lib.SaveToFile('application-filled.pdf');
finally
Lib.Free;
end;
end;
Deux détails décident si des données non triviales survivent au voyage. Le premier est l'échappement : FDF stocke les valeurs sous forme de chaînes littérales PDF, ainsi une valeur contenant une parenthèse, une barre oblique inverse ou un octet non imprimable arrive enveloppée dans l'échappement octal défini dans l'ISO 32000-2 §7.3.4.2, et la bibliothèque PDF losLab inverse cet échappement lors de l'importation afin que les parenthèses et les barres obliques reviennent sous forme de caractères littéraux saisis par l'utilisateur. Le second est l'encodage : les méthodes basées sur les fichiers écrivent et lisent XFDF et FDF en UTF-8, ce que promet la déclaration XFDF et ce dont toute valeur de champ non-ASCII (un nom accentué, un symbole monétaire, une adresse CJK) a besoin pour effectuer un aller-retour sans corruption. Si vous construisez vous-même le XFDF, déclarez UTF-8 et écrivez UTF-8, et l'importation sera d'accord avec vous
Champs hiérarchiques, choix multi-valeurs et texte enrichi
Champs hiérarchiques, choix multi-valeurs et texte enrichi
Les noms de champs hiérarchiques sont le premier endroit où un exportateur naïf échoue. AcroForm adresse un champ imbriqué avec un titre complet à points tel que Applicant.FullName, mais XFDF ne place pas cette chaîne à points dans un seul attribut de nom ; l'ISO 19444 l'imbrique, sous la forme <field name="Applicant"><field name="FullName">. La bibliothèque PDF losLab divise le titre à points en éléments <field> imbriqués lors de l'exportation et réassemble les éléments imbriqués en titre complet lors de l'importation, de sorte que les deux directions restent symétriques. À l'exportation, elle ignore également les champs parents non terminaux, car un nœud parent dans un AcroForm ne porte que le niveau de dénomination et n'a pas de valeur propre ; l'émettre produirait un <value></value> vide qui ne correspond pas au formulaire réel. Les zones de liste à sélection multiple sont le second piège : un champ de choix peut contenir plusieurs valeurs sélectionnées à la fois, ce que XFDF exprime par des éléments <value> répétés et FDF exprime par un tableau /V, et la bibliothèque PDF losLab ne divise un champ en plusieurs valeurs que s'il s'agit véritablement d'un choix à sélection multiple, de sorte qu'un champ de texte multiligne ordinaire conserve ses sauts de ligne au lieu de se briser en valeurs erronées
Le texte enrichi est le troisième élément, et celui sur lequel on se trompe le plus souvent. Un champ avec mise en forme stocke son balisage dans l'entrée RV sous forme de sous-arbre XHTML, et XFDF le transporte dans <value-richtext>. La bibliothèque PDF losLab écrit ce sous-arbre sous forme de fragment XML actif plutôt que de l'échapper, de sorte qu'un outil en aval lit du vrai texte enrichi au lieu d'une chaîne de balises visibles ; lors de l'importation, elle préserve le sous-arbre RV brut et applique toujours la simple <value> à V. Lorsqu'un champ propose les deux, la valeur simple l'emporte pour V et le texte enrichi l'accompagne dans RV, ce qui est la règle d'interopérabilité qui empêche une importation de texte enrichi de réécrire discrètement une valeur déjà définie par un autre outil. Lorsque votre texte enrichi existe pour transmettre la structure du document aux technologies d'assistance, traitez-le de la même manière que vous traiteriez l'ordre de lecture abordé dans la note sur le PDF balisé et la structure d'accessibilité
var
Lib: TPDFlib;
const
XFDF =
'<?xml version="1.0" encoding="UTF-8"?>' +
'<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">' +
'<fields>' +
' <field name="Applicant">' +
' <field name="FullName"><value>Alice Example</value></field>' +
' </field>' +
' <field name="Skills">' +
' <value>Delphi</value><value>PDF</value>' +
' </field>' +
' <field name="Notes">' +
' <value>See attachment</value>' +
' <value-richtext><body><p>See <b>attachment</b></p></body></value-richtext>' +
' </field>' +
'</fields></xfdf>';
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('intake.pdf', '');
// Applicant.FullName reassembles; Skills fills the /V + /I arrays;
// Notes gets V from <value> and RV from <value-richtext>
Lib.ImportFormDataFromXFDFString(XFDF);
Lib.SaveToFile('intake-filled.pdf');
finally
Lib.Free;
end;
end;
Comment effectuer un aller-retour de commentaires d'annotation au format FDF ou XFDF ?
Les commentaires voyagent sur la famille des annotations, et le sous-ensemble pris en charge est délibérément restreint. ExportAnnotationsToXFDF et ImportAnnotationsFromXFDF, avec leurs homologues FDF, transportent un balisage de style texte avec les champs qui effectuent réellement l'aller-retour proprement : le sous-type d'annotation, son rectangle, son index de page basé sur 0, l'auteur dans T, le sujet dans Subj, le Contents simple, et la couleur, qui mappe le triplet PDF /C DeviceRGB vers et depuis un attribut XFDF #RRGGBB. L'importation n'accepte que les noms d'éléments connus et ignore toute entrée dont la page est hors de portée ou dont le rectangle is manquant, de sorte qu'un XFDF modifié manuellement ou étranger ne puisse pas insérer d'annotation malformée dans le document. Ce que le sous-ensemble ne transporte pas encore mérite d'être énoncé clairement : le contenu en texte enrichi (RC), les fenêtres contextuelles (popups), les points quadrilatères (quadpoints), les listes d'encre, les sommets et les flux d'apparence figés sont hors de portée pour le moment, de sorte que la géométrie de surbrillance et les apparences de tampons personnalisés ne survivront pas à ce chemin. Pour confirmer ce qui a réellement été importé, parcourez les annotations de page ou l'arborescence d'éléments plus large traitée dans la recherche de texte et l'énumération des éléments de page
var
Src, Dest: TPDFlib;
Xfdf: WideString;
begin
Src := TPDFlib.Create;
Dest := TPDFlib.Create;
try
Src.LoadFromFile('reviewed.pdf', '');
Xfdf := Src.ExportAnnotationsToXFDFString; // <annots> subset only
Dest.LoadFromFile('clean-copy.pdf', ''); // pages must line up by index
Dest.ImportAnnotationsFromXFDFString(Xfdf);
Dest.SaveToFile('clean-copy-commented.pdf');
finally
Dest.Free;
Src.Free;
end;
end;
Écriture d'un paquet XFA XDP complet avec SetXFAFromString
L'XFA est l'exception, et SetXFAFromString est la façon dont vous écrivez le tout d'un coup. La méthode prend un package de données XML complet, le document <xdp:xdp> avec ses paquets de modèles et de jeux de données, et le stocke sous forme de flux référencé par /AcroForm/XFA. La bibliothèque PDF losLab crée le conteneur AcroForm à la demande lorsque le document n'en possède pas, de sorte que vous n'avez pas besoin d'ajouter un champ temporaire juste pour donner à l'XFA un endroit où s'accrocher, et elle jette tout état XFA analysé qu'elle détenait afin qu'une lecture ultérieure reflète le paquet que vous venez d'écrire plutôt qu'un cache obsolète. Comme un paquet XFA est du XML et pas nécessairement de l'UTF-8, la bibliothèque détecte une marque d'ordre d'octets UTF-16 et décode le paquet correctement avant l'analyse, ce qui importe pour les paquets produits par des outils qui utilisent l'UTF-16 par défaut
Une fois le paquet en place, GetXFAFormFieldValue and SetXFAFormFieldValue ciblent les champs individuels via leur chemin Scripting Object Model. La bibliothèque PDF losLab accepte les racines SOM standard ainsi que les chemins relatifs simples, de sorte que form1.FullName, $data.form1.FullName et xfa.datasets.data.form1.FullName se résolvent tous vers le même nœud de données, et le côté modèle accepte $template et xfa.template de la même manière. Cette tolérance est importante lorsque les chemins SOM sont générés par un autre système qui émet toujours le formulaire entièrement qualifié
var
Lib: TPDFlib;
const
Xdp =
'<?xml version="1.0" encoding="UTF-8"?>' +
'<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">' +
' <template xmlns="http://www.xfa.org/schema/xfa-template/3.3/">' +
' <subform name="form1">' +
' <field name="FullName"><ui><textEdit/></ui></field>' +
' </subform>' +
' </template>' +
' <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">' +
' <xfa:data><form1><FullName>Alice Example</FullName></form1></xfa:data>' +
' </xfa:datasets>' +
'</xdp:xdp>';
begin
Lib := TPDFlib.Create;
try
Lib.SetXFAFromString(Xdp, 0); // creates the AcroForm container if none exists
// read back through the data DOM with an SOM path
if Lib.GetXFAFormFieldValue('form1.FullName') = 'Alice Example' then
Lib.SetXFAFormFieldValue('form1.FullName', 'Bob Example');
Lib.SaveToFile('xfa-packet.pdf');
finally
Lib.Free;
end;
end;
Le bilan honnête est que les valeurs de champ font un aller-retour complet via FDF et XFDF, y compris la hiérarchie, la sélection multiple et le texte enrichi ; les commentaires d'annotation font un aller-retour sous la forme d'un sous-ensemble de balisage textuel défini présentant des lacunes évidentes ; et XFA est écrit et lu comme un paquet entier avec en plus un accès SOM par champ. Adaptez le format au consommateur, décrivez UTF-8 pour tout ce que vous construisez à la main, et rappelez-vous que les méthodes d'importation ne touchent jamais qu'aux champs et annotations qui correspondent déjà au document. Les méthodes de données de formulaire, d'annotation et XFA décrites ici font partie de la bibliothèque PDF losLab pour Delphi et C++Builder, dont la référence comporte la liste complète des paramètres pour chaque point d'entrée d'exportation et d'importation