Komponenta PDFium Component pro Delphi a Lazarus umožňuje výměnu formulářových dat a anotací prostřednictvím formátu XFDF, což je XML výměnný formát definovaný normou ISO 19444-1. Metoda TPdf.ExportXFDF serializuje veškeré hodnoty formulářových polí a všechny podporované anotace v načteném dokumentu do souboru XFDF nebo do TStream. Naopak TPdf.ImportXFDF načte dokument XFDF zpět, znovu vytvoří anotace na odpovídajících stránkách a aplikuje hodnoty polí. Tento obousměrný proces (round-trip) pokrývá dva klíčové scénáře, které každá dokumentová aplikace dříve či později potřebuje: buď recenzent přidá poznámky do PDF v programu Acrobat a zašle vám komentáře ke sloučení, nebo pravidla shody vyžadují, aby data z formulářů žila v samostatném, porovnatelném a auditovatelném souboru namísto toho, aby byla napevno zapečena v samotném PDF
Podporuje knihovna PDFium import a export XFDF?
Samotná knihovna PDFium tuto funkci nepodporuje. Nativní rozhraní C API neobsahuje vůbec žádné funkce pro XFDF ani FDF — v jeho veřejných hlavičkových souborech není nic pro čtení ani zápis těchto formátů, takže jakékoli obalení (wrapping) nepomůže. Komponenta PDFium Component proto implementuje celý engine XFDF přímo v Pascalu, a to ve vyhrazené jednotce, která sestavuje a analyzuje XML přímo nad stávajícím datovým modelem anotací a formulářových polí třídy TPdf. Zapisovač generuje XML ručně a čtečka je ručně napsaný analyzátor stavového stroje (state-machine parser), takže tato funkce nepřidává žádnou závislost na jednotkách Delphi XMLDoc nebo FPC DOM a chová se zcela stejně v Delphi i Lazarusu
Tato volba návrhu je důležitá při zvažování alternativ. Pokud jste z Pascalu volali přímo surové funkce FPDF_*, narazíte u XFDF na zeď: tato funkce v knihovně DLL jednoduše chybí. Komponenta tuto překážku překonává tím, že k XFDF přistupuje jako k čistému problému serializace — shromáždí hodnoty polí a záznamy anotací, které obalová vrstva již umí číst, zapíše je jako standardní XML a při importu provede opačný proces
Co obsahuje soubor XFDF?
Norma ISO 19444-1 definuje XFDF jako XML reprezentaci formátu FDF a jeho obsah se dělí do dvou hlavních bloků. Prvek <fields> nese hierarchické názvy formulářových polí a jejich hodnoty — tedy vše, co uživatel napsal, vybral nebo zaškrtl v AcroFormu. Prvek <annots> obsahuje samotné anotace: metoda TPdf.ExportXFDF generuje 18 subtypů — text, zvýraznění (highlight), podtržení (underline), přeškrtnutí (strikeout), vlnovku (squiggly), čáru (line), kruh (circle), čtverec (square), stříšku (caret), polygon, lomenou čáru (polyline), razítko (stamp), inkoust (ink), volný text (freetext), přílohu souboru (fileattachment), zvuk, odkaz a redakční označení (redact). Ovládací prvky (widget anotace) v bloku <annots> záměrně chybí, protože jejich data se přenášejí v <fields>, a vnitřní typy prohlížeče, jako je Popup, nejsou součástí slovníku XFDF
Aby byl přenos přesný, byl záznam TPdfAnnotation rozšířen o metadata, která XFDF očekává: Name (unikátní identifikátor NM), Subject, ModificationDate, CreationDate, Icon, Opacity, koncové body čar, vrcholy polygonů a lomených čar a cesty inkoustových tahů. Každé nové pole se páruje s logickým indikátorem Has*, takže kód, který vytvářel anotace ve starších verzích, se nadále zkompiluje a generuje stejné slovníky — nevyplněné pole se do souboru nezapíše. Pokud již vytváříte anotace programově, stejný záznam, který používáte pro textové anotace s quad body, nyní nese vše, co XFDF vyžaduje
Jak exportovat data formulářů a anotace do XFDF?
Jediné volání zpracuje celý dokument. Načtěte PDF se zapnutým vyplňováním formulářů, zavolejte ExportXFDF a komponenta projde každou stránku, shromáždí hodnoty polí i anotace a zapíše XML. Návratovou hodnotou je počet zapsaných UTF-8 bajtů, což slouží jako rychlá kontrola v logách
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;
Oba směry podporují přetížení pro TStream, takže vás nic nenutí vytvářet dočasné soubory na disku. Export do TMemoryStream je ideální volbou, pokud XFDF směřuje do HTTP odpovědi, databázového pole typu blob nebo jako položka do podepsaného archivu
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;
Jak ImportXFDF slučuje komentáře zpět do dokumentu?
Na straně importu se uzavírá pracovní postup recenzenta. Kolega okomentuje smlouvu v Acrobatu, exportuje komentáře jako XFDF a zašle vám několik kilobajtů XML namísto druhé kopie PDF. Metoda TPdf.ImportXFDF tento soubor analyzuje, vytvoří každou anotaci na stránce určené jejím atributem page a zapíše hodnoty polí do odpovídajících widget anotací. Funkce vrací celkový počet aplikovaných polí a anotací, takže uživatelské rozhraní může potvrdit přesný rozsah provedených změn
var
Applied: Integer;
begin
Applied := Pdf.ImportXFDF('review-comments.xfdf');
StatusBar.SimpleText :=
Format('%d fields and annotations merged', [Applied]);
end;
Analyzátor je ručně napsaný skener tagů navržený s ohledem na toleranci chyb namísto striktnosti: neznámé prvky se přeskakují, instrukce zpracování, deklarace DOCTYPE a komentáře se ignorují, nerozpoznané názvy příznaků se zahazují a hodnoty atributů se převádějí na původní znaky přes celou sadu XML entit a číselných odkazů včetně náhradních párů UTF-16. XFDF vygenerované Acrobatem, webovým prohlížečem nebo jiným nástrojem se sloučí bez jakýchkoli problémů. Jakmile jsou anotace v dokumentu, schvalovací cyklus pokračuje pomocí mechanismu odpovědí a stavů popsaného v článku o vytvoření schvalovacího postupu anotací s PDFium Component a importované hodnoty polí se účastní běžné logiky procházení polí tabulátorem, což popisuje článek o navigaci ve formulářových polích
Proč u XFDF záleží na oddělovačích desetinných míst?
Každá anotace v XFDF je umístěna pomocí řetězců souřadnic — jako například rect="70.5,540,200,560" —, přičemž norma ISO 19444-1 vyžaduje jako desetinný oddělovač tečku. Výchozí formátování desetinných čísel v Delphi se řídí nastavením systému Windows. Na německém nebo francouzském systému tak běžné volání FloatToStr změní 70.5 na 70,5, což poškodí čárkou oddělený seznam souřadnic na nečitelná data, která ostatní procesory odmítnou nebo nesprávně interpretují. Komponenta PDFium Component normalizuje každé zapisované číslo: desetinný oddělovač systému je přepsán na tečku a koncové nuly jsou odstraněny. Exportovaný soubor je tak bajtově shodný bez ohledu na to, zda byl vytvořen na počítači s nastavením en-US nebo de-DE. Pokud jste někdy ladili PDF nástroj, který v kanceláři fungoval, ale u evropského zákazníka selhal, setkali jste se přesně s touto třídou chyb — je dobré vědět, že komponenta to řeší za vás
Jaká jsou omezení obousměrného přenosu?
Dvě omezení je vhodné uvést na rovinu. Zaprvé, XFDF přenáší data anotací, nikoli jejich vykrslený vzhled — toky vzhledu (appearance streams) nejsou součástí formátu, takže cílový prohlížeč generuje vzhled každé anotace znovu na základě jejích vlastností. Zvýraznění nebo čtverec se vykreslí správně kdekoli; razítko s vlastním vzhledem se vrátí k tomu, co pro daný název razítka vykresluje cílový prohlížeč. Zadruhé, základní rozhraní API knihovny PDFium obsahuje metody pro zápis řetězců, ale žádné pro čísla anotací nebo geometrii cest, takže vlastnosti jako Opacity, koncové body čar, vrcholy a inkoustová gesta jsou určeny pouze pro export: komponenta je při zápisu do XFDF věrně zachová, ale při importu je nedokáže zapsat zpět do PDF. Hodnoty polí, obsah, barvy, souřadnice (rects), body quad, data a metadata identity se přenášejí obousměrně bez omezení
Pro praktický začátek obsahuje ukázkový projekt XfdfLab dodávaný v sadách dem pro Delphi, C++Builder a Lazarus obě volání navázaná na tlačítka nad jakýmkoli otevřeným PDF. Podpora XFDF je zahrnuta v aktuálním vydání produktu PDFium Component spolu s API pro anotace a formuláře, na kterých staví