Komponenta PDFium Component za Delphi in Lazarus izmenjuje podatke obrazcev in anotacije prek formata XFDF, XML-izmenjevalnega formata, ki ga določa standard ISO 19444-1. Metoda TPdf.ExportXFDF serializira vsako vrednost polja obrazca in vsako podprto anotacijo v naloženem dokumentu v datoteko XFDF ali TStream; TPdf.ImportXFDF pa prebere dokument XFDF nazaj, znova ustvari anotacije na njihovih straneh in uporabi vrednosti polj. Ta enojni krog (round-trip) pokriva dva delovna tokova, ki ju sčasoma potrebuje vsaka aplikacija za dokumente: ocenjevalec označi PDF v Acrobat-u in vam pošlje komentarje za združitev, ali pa skladnostno pravilo določa, da morajo podatki obrazca živeti v ločeni datoteki, ki jo je mogoče primerjati in revidirati, namesto da bi bili zapečateni v samem PDF-ju
Ali PDFium podpira uvoz in izvoz XFDF?
Sama knjižnica PDFium tega ne podpira. Izvorni API v jeziku C sploh nima funkcij za XFDF ali FDF — nič v njenih javnih glavah (headers) ne bere ali piše nobenega od teh formatov, zato vas nobena količina ovijanja (wrapping) ne pripelje tja. Komponenta PDFium Component zato celoten pogon XFDF implementira v jeziku Pascal, v namenski enoti, ki gradi in razčlenjuje XML neposredno nad obstoječim podatkovnim modelom anotacij in polj obrazcev TPdf. Pisalnik ročno oddaja XML, bralnik pa je ročno napisan razčlenjevalnik končnega avtomata (state-machine parser), zato funkcija ne uvaja odvisnosti od enote Delphi XMLDoc ali FPC DOM in se obnaša popolnoma enako v Delphiju in Lazarusu
Ta oblikovalska izbira je pomembna pri ocenjevanju alternativ. Če ste iz Pascala klicali surove funkcije FPDF_*, je XFDF zid: ta zmogljivost preprosto ne obstaja v DLL-ju. Komponenta prečka ta zid tako, da XFDF obravnava kot čist problem serializacije — zbere vrednosti polj in zapise anotacij, ki jih ovijalnik že zna prebrati, jih zapiše kot standardni XML in ob uvozu postopek obrne
Kaj vsebuje datoteka XFDF?
Standard ISO 19444-1 opredeljuje XFDF som XML-predstavitev formata FDF, njegova vsebina pa se deli na dva vrhovna bloka. Element <fields> prenaša hierarhična imena polj obrazcev in njihove vrednosti — vse, kar je uporabnik vtipkal, izbral ali označil v AcroFormu. Element <annots> prenaša anotacije: metoda TPdf.ExportXFDF izvozi 18 podvrst — text, highlight, underline, strikeout, squiggly, line, circle, square, caret, polygon, polyline, stamp, ink, freetext, fileattachment, sound, link in redact. Anotacije gradnikov (widget annotations) so namerno odsotne iz <annots>, saj njihovi podatki potujejo v elementu <fields>, notranje podvrste pregledovalnika, kot je Popup, pa niso del besednjaka XFDF
Da bi bilo povratno potovanje zanesljivo, je bil zapis TPdfAnnotation razširjen z metapodatki, ki jih XFDF pričakuje: Name (enolični identifikator NM), Subject, ModificationDate, CreationDate, Icon, Opacity, končne točke črt, oglišča mnogokotnikov in lomljenk ter poti potez s črnilom. Vsako novo polje je seznanjeno z logično stražo Has*, tako da se koda, ki je gradila anotacije za prejšnje različice, še naprej prevaja in proizvaja iste slovarje — nenastavljeno polje se nikoli ne zapiše. Če že programsko ustvarjate oznake, isti zapis, ki ga uporabljate za anotacije besedilnih oznak s štirimi točkami (quad points), zdaj nosi vse, kar potrebuje XFDF
Kako izvoziti podatke obrazca in anotacije v XFDF?
En klic opravi delo za celoten dokument. Naložite PDF z omogočenim izpolnjevanjem obrazcev, pokličite ExportXFDF in komponenta bo prehodila vsako stran, zbrala vrednosti polj ter anotacije in zapisala XML. Vrednost vračanja je število zapisanih UTF-8 bajtov, kar služi kot enostaven preizkus pravilnosti v dnevnikih
var
Pdf: TPdf;
Bytes: Integer;
begin
Pdf := TPdf.Create(Self);
Pdf.FormFill := True; // potrebno, da so vrednosti polj aktivne
Pdf.FileName := 'expense-report.pdf';
Pdf.Active := True;
Bytes := Pdf.ExportXFDF('expense-report.xfdf');
ShowMessage(Format('%d bytes of XFDF written', [Bytes]));
end;
Obe smeri imata preobremenitev s TStream, tako da vas nič ne sili v uporabo začasne datoteke na disku. Izvoz v TMemoryStream je naravna izbira, ko je XFDF namenjen za spletni odgovor HTTP, velik binarni objekt (blob) v bazi podatkov ali podpisan vnos v stisnjeno datoteko (zip)
var
Buffer: TMemoryStream;
begin
Buffer := TMemoryStream.Create;
try
Pdf.ExportXFDF(Buffer); // isti XML, brez vpletene datoteke
Buffer.Position := 0;
// predajte tok spletnemu odgovoru, stolpcu blob ali zapisu zip
finally
Buffer.Free;
end;
end;
Kako ImportXFDF združi komentarje nazaj v dokument?
Uvozna stran je tista, kjer se sklene delovni tok ocenjevalca. Sodelavec označi pogodbo v Acrobatu, izvozi komentarje kot XFDF in vam pošlje nekaj kilobajtov XML-ja namesto druge kopije celotnega PDF-ja. Metoda TPdf.ImportXFDF razčleni to datoteko, ustvari vsako anotacijo na strani, ki jo določa njen atribut page, in zapiše vrednosti polj v ustrezne anotacije gradnikov. Funkcija vrne skupno število uveljavljenih polj in anotacij, tako da lahko uporabniški vmesnik potrdi, koliko podatkov je natančno prispelo
var
Applied: Integer;
begin
Applied := Pdf.ImportXFDF('review-comments.xfdf');
StatusBar.SimpleText :=
Format('%d fields and annotations merged', [Applied]);
end;
Razčlenjevalnik je ročno napisan iskalnik oznak, zasnovan za toleranco in ne strogo pravila: neznani elementi se preskočijo, navodila za obdelavo, deklaracije DOCTYPE in komentarji se prezrejo, neprepoznana imena zastavic se izpustijo, vrednosti atributov pa se razrešijo iz ubežnih znakov prek celotnega nabora XML-entitet in sklicev na številčne znake, vključno z nadomestnimi pari UTF-16. XFDF, ki ga ustvari Acrobat, spletni pregledovalnik ali drugo orodje, se združi brez zapletov. Ko so anotacije v dokumentu, se revizijski krog nadaljuje z mehanizmom za odgovore in stanja, opisanim v izdelavi delovnega toka za pregled anotacij s komponento PDFium Component, uvožene vrednosti polj pa sodelujejo v običajni logiki zaporedja tabulatorjev, opisani v navigaciji med polji obrazca
Zakaj so decimalni ločilniki pomembni za XFDF?
Vsaka anotacija v formatu XFDF je pozicionirana s koordinatnimi nizi — npr. rect="70.5,540,200,560" in podobno — standard ISO 19444-1 pa kot decimalni ločilnik zahteva piko. Privzeto oblikovanje števil s plavajočo vejico v Delphiju sledi nastavitvam operacijskega sistema Windows, zato na nemškem ali francoskem sistemu preprosta funkcija FloatToStr spremeni 70.5 v 70,5, kar popači z vejicami ločen seznam koordinat v neuporabne podatke, ki jih drugi procesorji zavrnejo ali napačno preberejo. Komponenta PDFium Component normalizira vsako številko, ki jo zapiše: decimalni ločilnik lokalnega okolja se prepiše v piko, sledilne ničle pa se odstrižejo, tako da je izvožena datoteka bajtno enaka, ne glede na to, ali je bila ustvarjena na angleškem ali nemškem računalniku. Če ste kdaj odpravljali napake v orodju za PDF, ki je delovalo v pisarni, padlo pa pri evropski stranki, ste se srečali s točno tem razredom hroščev — zato je dobro vedeti, da komponenta to ureja namesto vas
Kakšne so omejitve povratnega potovanja (round-trip)?
Dve omejitvi je vredno odkrito izpostaviti. Prvič, XFDF prenaša podatke o anotacijah, ne pa izrisanih videzov (appearance streams) — ti niso del formata, zato prejemni pregledovalnik znova zgradi izgled vsake anotacije iz njenih lastnosti. Označba ali kvadrat se bosta povsod izrisala pravilno; žig s tlorisom po meri pa se bo vrnil na tisto, kar ciljni pregledovalnik nariše za to ime žiga. Drugič, osnovni API za PDFium ima nastavitvene metode za nize, nima pa jih za številke anotacij ali geometrijo poti, zato so prosojnost Opacity, končne točke črt, oglišča in poteze s črnilom na voljo le za izvoz: komponenta jih zvesto ohrani pri pisanju XFDF, ne more pa jih zapisati nazaj v PDF ob uvozu. Vrednosti polj, vsebina, barve, pravokotniki, štiri točke (quad points), datumi in metapodatki o identiteti pa se prenašajo v obeh smereh
Za praktičen začetek je primer XfdfLab priložen kompletom demo projektov za Delphi, C++Builder in Lazarus, kjer sta oba klica povezana z gumbi nad katerim koli odprtim dokumentom PDF. Podpora za XFDF je vključena v trenutno izdajo komponente PDFium Component, skupaj z API-ji za anotacije in obrazce, na katerih gradi