Die PDFium-Komponente für Delphi und Lazarus tauscht Formulardaten und Anmerkungen über XFDF aus, das in ISO 19444-1 definierte XML-Austauschformat. TPdf.ExportXFDF serialisiert jeden Formularfeldwert und jede unterstützte Anmerkung im geladenen Dokument in eine XFDF-Datei oder einen TStream; TPdf.ImportXFDF liest ein XFDF-Dokument wieder ein, erstellt die Anmerkungen auf ihren Seiten neu und wendet die Feldwerte an. Dieser eine Round-Trip deckt zwei Workflows ab, die letztendlich jede Dokumentenanwendung benötigt: Ein Reviewer markiert ein PDF in Acrobat und sendet Ihnen die Kommentare zum Zusammenführen zu, oder eine Compliance-Regel schreibt vor, dass Formulardaten in einer separaten, differenzierbaren und prüfbaren Datei gespeichert werden müssen, anstatt direkt im PDF selbst verankert zu sein
Unterstützt PDFium den XFDF-Import und -Export?
Die PDFium-Bibliothek selbst tut dies nicht. Die native C-API besitzt überhaupt keine XFDF- oder FDF-Funktionen — nichts in ihren öffentlichen Headern liest oder schreibt eines der beiden Formate, sodass auch kein noch so umfangreiches Wrapping Sie dorthin führt. Die PDFium-Komponente implementiert daher die gesamte XFDF-Engine in Pascal in einer dedizierten Unit, die XML direkt auf dem bestehenden TPdf-Anmerkungs- und Formularfeld-Datenmodell aufbaut und analysiert. Der Writer gibt das XML manuell aus, und der Reader ist ein handgeschriebener State-Machine-Parser, sodass das Feature keine Abhängigkeit von Delphi XMLDoc oder den FPC DOM-Units hinzufügt und sich unter Delphi und Lazarus identisch verhält
Diese Designentscheidung ist wichtig, wenn Sie Alternativen bewerten. Wenn Sie bisher rohe FPDF_*-Funktionen aus Pascal aufgerufen haben, ist XFDF wie eine Wand: Diese Fähigkeit ist in der DLL schlichtweg nicht vorhanden. Die Komponente überwindet diese Hürde, indem sie XFDF als reines Serialisierungsproblem behandelt — sie sammelt die Feldwerte und Anmerkungsdatensätze, die der Wrapper bereits lesen kann, schreibt sie als Standard-XML aus und kehrt den Prozess beim Import um
Was enthält eine XFDF-Datei?
ISO 19444-1 definiert XFDF als die XML-Darstellung von FDF, und seine Nutzdaten verteilen sich auf zwei Blöcke der obersten Ebene. Das Element <fields> enthält hierarchische Formularfeldnamen und deren Werte — also alles, was ein Benutzer in ein AcroForm eingegeben, ausgewählt oder angehakt hat. Das Element <annots> enthält die Anmerkungen: TPdf.ExportXFDF gibt 18 Subtypen aus — Text, Hervorhebung, Unterstreichung, Durchstreichung, Schnörkel, Linie, Kreis, Quadrat, Caret, Polygon, Polylinie, Stempel, Tinte, Freitext, Dateianhang, Ton, Link und Schwärzung (Redact). Widget-Anmerkungen fehlen in <annots> bewusst, da ihre Daten in <fields> übertragen werden, und Viewer-interne Subtypen wie Popup gehören nicht zum XFDF-Vokabular
Um den Round-Trip originalgetreu zu gestalten, wurde der Datensatz TPdfAnnotation um die von XFDF erwarteten Metadaten erweitert: Name (der eindeutige Bezeichner NM), Subject, ModificationDate, CreationDate, Icon, Opacity, Linienendpunkte, Polygon- und Polylinien-Eckpunkte sowie Tintengestenpfade. Jedes neue Feld ist mit einer booleschen Has*-Wächtervariable gepaart, sodass Code, der Anmerkungen für frühere Versionen erstellt hat, weiterhin kompiliert und dieselben Dictionaries erzeugt — ein nicht gesetztes Feld wird niemals geschrieben. Wenn Sie Markup bereits programmgesteuert erstellen, enthält derselbe Datensatz, den Sie für Textmarkup-Anmerkungen mit Quadpoints verwenden, nun alles, was XFDF benötigt
Wie exportiert man Formulardaten und Anmerkungen nach XFDF?
Ein einziger Aufruf genügt für das gesamte Dokument. Laden Sie das PDF mit aktiviertem Ausfüllen von Formularen, rufen Sie ExportXFDF auf, und die Komponente durchläuft jede Seite, sammelt Feldwerte sowie Anmerkungen und schreibt das XML. Der Rückgabewert ist die Anzahl der geschriebenen UTF-8-Bytes, was eine einfache Plausibilitätsprüfung in Protokollen ermöglicht
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;
Beide Richtungen verfügen über eine Überladung mit TStream, sodass keine temporäre Datei auf der Festplatte erzwungen wird. Der Export in einen TMemoryStream ist die natürliche Form, wenn die XFDF-Daten für eine HTTP-Antwort, ein Datenbank-Blob oder einen signierten Archiveintrag bestimmt sind
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;
Wie führt ImportXFDF Kommentare wieder im Dokument zusammen?
Auf der Importseite schließt sich der Workflow des Reviewers. Ein Kollege versieht den Vertrag in Acrobat mit Anmerkungen, exportiert die Kommentare als XFDF und sendet Ihnen wenige Kilobyte XML anstelle einer zweiten Kopie des PDFs. TPdf.ImportXFDF analysiert diese Datei, erstellt jede Anmerkung auf der Seite, die durch ihr Attribut page angegeben wird, und schreibt die Feldwerte in die passenden Widget-Anmerkungen. Die Funktion gibt die kombinierte Anzahl der angewendeten Felder und Anmerkungen zurück, sodass die Benutzeroberfläche genau bestätigen kann, was angekommen ist
var
Applied: Integer;
begin
Applied := Pdf.ImportXFDF('review-comments.xfdf');
StatusBar.SimpleText :=
Format('%d fields and annotations merged', [Applied]);
end;
Der Parser ist ein handgeschriebener Tag-Scanner, der eher auf Toleranz als auf Striktheit ausgelegt ist: Unbekannte Elemente werden übersprungen, Verarbeitungsanweisungen, DOCTYPE-Deklarationen und Kommentare werden ignoriert, nicht erkannte Flag-Namen werden verworfen und Attributwerte werden über die gesamte Palette von XML-Entitäten und numerischen Zeichenreferenzen, einschließlich UTF-16-Surrogatpaaren, demaskiert. Von Acrobat, einem Web-Viewer oder einem anderen Tool erstelltes XFDF wird problemlos zusammengeführt. Sobald sich die Anmerkungen im Dokument befinden, wird der Review-Zyklus mit dem Antwort- und Statusmechanismus fortgesetzt, der im Artikel über das Erstellen eines Workflows zur Überprüfung von Anmerkungen mit der PDFium-Komponente beschrieben ist. Importierte Feldwerte nehmen an der normalen Tabulatorreihenfolgelogik teil, die im Artikel über Formularfeldnavigation behandelt wird
Warum sind Dezimaltrennzeichen für XFDF wichtig?
Jede Anmerkung in XFDF wird über Koordinatenzeichenketten positioniert — wie rect="70.5,540,200,560" —, und ISO 19444-1 verlangt den Punkt als Dezimaltrennzeichen. Die Standard-Fließkommaformatierung von Delphi folgt dem Windows-Gebietsschema, sodass auf einem deutschen oder französischen System ein einfaches FloatToStr 70.5 in 70,5 verwandelt. Dies beschädigt eine durch Kommata getrennte Koordinatenliste und macht sie zu unbrauchbarem Datenmüll, den andere Prozessoren ablehnen oder falsch interpretieren. Die PDFium-Komponente normalisiert jede Zahl, die sie schreibt: Das Dezimaltrennzeichen des Gebietsschemas wird in einen Punkt umgeschrieben, und nachfolgende Nullen werden abgeschnitten, sodass die exportierte Datei Byte-identisch ist, unabhängig davon, ob sie auf einer en-US- oder einer de-DE-Maschine erstellt wurde. Wenn Sie jemals ein PDF-Tool debuggt haben, das im Büro funktionierte, aber bei einem europäischen Kunden fehlschlug, haben Sie genau diese Fehlerklasse kennengelernt — gut zu wissen, dass die Komponente sich darum kümmert
Wo liegen die Grenzen des Round-Trips?
Zwei Grenzen sollten deutlich genannt werden. Erstens überträgt XFDF Anmerkungsdaten, keine gerenderten Darstellungen — Appearance-Streams sind nicht Teil des Formats, sodass der empfangende Viewer das Aussehen jeder Anmerkung aus ihren Eigenschaften neu generiert. Eine Hervorhebung oder ein Quadrat wird überall korrekt gerendert; ein Stempel mit einer benutzerdefinierten Darstellung fällt auf das zurück, was der Zielviewer für diesen Stempelnamen zeichnet. Zweitens besitzt die zugrunde liegende PDFium-API Setter für Zeichenketten, aber keine für Anmerkungsnummern oder Pfadgeometrien, sodass Opacity, Linienendpunkte, Eckpunkte und Tintengesten nur für den Export bestimmt sind: Die Komponente behält diese beim Schreiben von XFDF getreu bei, kann sie jedoch beim Import nicht in das PDF zurückschreiben. Feldwerte, Inhalte, Farben, Rechtecke, Quadpoints, Daten und Identitätsmetadaten durchlaufen den Round-Trip in beide Richtungen vollständig
Für einen praktischen Einstieg ist das Beispiel XfdfLab in den Demosätzen für Delphi, C++Builder und Lazarus enthalten und verknüpft beide Aufrufe mit Schaltflächen über jedem geöffneten PDF. Die XFDF-Unterstützung ist in der aktuellen Version der PDFium-Komponente enthalten, neben den Anmerkungs- und Formular-APIs, auf denen sie aufbaut