PDFium komponenta za Delphi i Lazarus razmenjuje podatke obrazaca i anotacija kroz XFDF, XML format za razmenu definisan standardom ISO 19444-1. Metoda TPdf.ExportXFDF serijalizuje svaku vrednost polja obrasca i svaku podržanu anotaciju u učitanom dokumentu u XFDF datoteku ili TStream. Poziv TPdf.ImportXFDF čita XFDF dokument unazad, ponovo kreirajući anotacije na njihovim stranicama i primenjujući vrednosti polja. Taj jedan krug (round-trip) pokriva dva radna toka koja su na kraju potrebna svakoj aplikaciji za dokumente: recenzent označava PDF u Acrobat-u i šalje vam komentare na spajanje, ili pravilo usklađenosti nalaže da podaci obrasca moraju živeti u zasebnoj datoteci pogodnoj za upoređivanje i reviziju, a ne da budu ugrađeni u sam PDF
Da li PDFium podržava uvoz i izvoz XFDF-a
Sama PDFium biblioteka to ne podržava. Izvorni C API uopšte nema XFDF ili FDF funkcije — ništa u njegovim javnim zaglavljima ne čita niti upisuje bilo koji od ova dva formata, tako da vas nikakvo omotavanje ne može dovesti do toga. Stoga, PDFium komponenta implementira čitav XFDF mehanizam u Pascal-u, u namenskoj jedinici koja gradi i parsira XML direktno na vrhu postojećeg modela podataka o anotacijama i poljima obrazaca klase TPdf. Pisač ručno ispisuje XML, a čitač je ručno napisani parser sa mašinom stanja (state-machine parser), tako da ova funkcionalnost ne dodaje zavisnost od Delphi XMLDoc-a ili FPC DOM jedinica i ponaša se identično i na Delphi-ju i na Lazarus-u
Ovaj izbor dizajna je važna pri proceni alternativa. Ako ste pozivali sirove FPDF_* funkcije iz Pascal-a, XFDF je prepreka: ta mogućnost jednostavno ne postoji u DLL datoteci. Komponenta prelazi tu prepreku tretirajući XFDF kao čist problem serijalizacije — prikuplja vrednosti polja i zapise anotacija koje omotač već zna da pročita, upisuje ih kao standardni XML i obrće proces prilikom uvoza
Šta sadrži XFDF datoteka
Standard ISO 19444-1 definiše XFDF kao XML prikaz FDF formata, a njegov sadržaj se deli na dva bloka na najvišem nivou. Element <fields> nosi hijerarhijska imena polja obrasca i njihove vrednosti — sve što je korisnik ukucao, izabrao ili označio u AcroForm-u. Element <annots> nosi anotacije: metoda TPdf.ExportXFDF emituje 18 podtipova — text, highlight, underline, strikeout, squiggly, line, circle, square, caret, polygon, polyline, stamp, ink, freetext, fileattachment, sound, link i redact. Widget anotacije su namerno odsutne iz <annots> jer njihovi podaci putuju u <fields>, a podtipovi interni za pregledač kao što je Popup nisu deo XFDF vokabulara
Kako bi povratno putovanje (round-trip) bilo verno, zapis TPdfAnnotation je proširen metapodacima koje XFDF očekuje: Name (jedinstveni identifikator NM), Subject, ModificationDate, CreationDate, Icon, Opacity, krajnje tačke linije, temena poligona i polilinije, kao i putanje gestova mastilom (ink gesture paths). Svako novo polje je upareno sa logičkim sentinelom Has* (boolean sentinel), tako da kod koji je kreirao anotacije na ranijim verzijama nastavlja da se prevodi i proizvodi iste rečnike — polje koje nije postavljeno se nikada ne upisuje. Ako već programski kreirate markup, isti zapis koji koristite za anotacije za označavanje teksta sa četvorouglim tačkama (quad points) sada nosi sve što je potrebno za XFDF
Kako izvesti podatke obrazaca i anotacije u XFDF
Jedan poziv obrađuje čitav dokument. Učitajte PDF sa omogućenim popunjavanjem obrazaca (form-fill), pozovite ExportXFDF, i komponenta prolazi kroz svaku stranicu, prikuplja vrednosti polja i anotacije i upisuje XML. Povratna vrednost je broj upisanih UTF-8 bajtova, što služi kao jednostavna provera ispravnosti u dnevnicima rada
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 smera imaju TStream preopterećenje (overload), tako da vas ništa ne primorava na korišćenje privremene datoteke na disku. Izvoz u TMemoryStream je prirodan oblik kada je XFDF namenjen HTTP odgovoru, bazi podataka ili potpisanim arhivskim unosima
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;
Kako ImportXFDF spaja komentare nazad u dokument
Strana uvoza je mesto gde se proces recenzije zatvara. Kolega označava ugovor u Acrobat-u, izvozi komentare kao XFDF i šalje vam nekoliko kilobajta XML-a umesto druge kopije PDF-a. Poziv TPdf.ImportXFDF parsira tu datoteku, kreira svaku anotaciju na stranici koju njen atribut page imenuje i upisuje vrednosti polja u odgovarajuće widget anotacije. Funkcija vraća ukupan broj primenjenih polja i anotacija, tako da korisnički interfejs može potvrditi tačnu količinu pristiglih podataka
var
Applied: Integer;
begin
Applied := Pdf.ImportXFDF('review-comments.xfdf');
StatusBar.SimpleText :=
Format('%d fields and annotations merged', [Applied]);
end;
Parser je ručno napisani skener tagova kreiran za toleranciju pre nego za strogoću: nepoznati elementi se preskaču, instrukcije za obradu, DOCTYPE deklaracije i komentari se ignorišu, neprepoznati nazivi zastavica se odbacuju, a vrednosti atributa se razrešavaju (unescaped) kroz čitav skup XML entiteta i numeričkih referenci karaktera, uključujući UTF-16 surogat parove. XFDF koji je proizveo Acrobat, veb pregledač ili neki drugi alat se spaja bez ikakvih problema. Kada se anotacije nađu u dokumentu, ciklus recenzije se nastavlja sa mehanizmom odgovora i statusa opisanim u članku o izgradnji procesa recenzije anotacija sa PDFium komponentom, a uvezene vrednosti polja učestvuju u uobičajenoj logici redosleda tabulatora pokrivenoj u kretanju kroz polja obrazaca
Zašto su separatori decimala važni za XFDF
Svaka anotacija u XFDF-u je pozicionirana koordinatnim stringovima — rect="70.5,540,200,560" i slično — a standard ISO 19444-1 zahteva tačku kao separator decimala. Podrazumevano formatiranje realnih brojeva u Delphi-ju prati Windows lokalitet, tako da na nemačkom ili francuskom sistemu jednostavno pozivanje FloatToStr pretvara 70.5 u 70,5, što kvari listu koordinata razdvojenu zarezima u neupotrebljive podatke koje drugi procesori odbijaju ili pogrešno čitaju. PDFium komponenta normalizuje svaki broj koji upisuje: separator decimala lokaliteta se prepisuje u tačku, a prateće nule se odsecaju, tako da je izvezena datoteka bajt-za-bajt identična bez obzira na to da li je proizvedena na en-US ili de-DE mašini. Ako ste ikada otklanjali greške u PDF alatu koji je radio u kancelariji, a zakazao kod evropskog klijenta, sreli ste se sa ovom klasom grešaka — stoga je dobro znati da komponenta upravlja ovim umesto vas
Koja su ograničenja prenosa u oba smera (round-trip)
Dve granice vredi jasno istaći. Prvo, XFDF prenosi podatke anotacija, a ne njihov renderovani izgled — tokovi izgleda (appearance streams) nisu deo formata, tako da pregledač koji prima podatke ponovo generiše izgled svake anotacije iz njenih svojstava. Isticanje (highlight) ili kvadrat (square) će se ispravno renderovati svuda. Pečat sa prilagođenim izgledom će se vratiti na ono što ciljni pregledač iscrtava za taj naziv pečata. Drugo, osnovni PDFium API ima metode za postavljanje stringova, ali nema nijednu za brojeve anotacija ili geometriju putanja, pa su Opacity, krajnje tačke linija, temena i gestovi mastilom rezervisani samo za izvoz: komponenta ih verno čuva prilikom pisanja XFDF-a, ali ih ne može upisati nazad u PDF prilikom uvoza. Vrednosti polja, sadržaj, boje, pravougaonici, četvorougle tačke, datumi i metapodaci o identitetu se prenose u oba smera
Za praktičan početak, primer XfdfLab se isporučuje u demo kompletima za Delphi, C++Builder i Lazarus i povezuje oba poziva sa dugmićima nad bilo kojim PDF-om koji otvorite. Podrška za XFDF je uključena u trenutno izdanje PDFium komponente, zajedno sa API-jima za anotacije i obrasce na kojima se zasniva