losLab PDF Library transferă datele de formular în și dintr-un PDF în trei moduri diferite: FDF și XFDF pentru valorile câmpurilor AcroForm, aceleași două formate pentru comentariile de adnotare și un pachet XFA XDP complet scris direct în formular. ExportFormDataToXFDF, ImportFormDataFromXFDF, ImportAnnotationsFromFDF, ExportAnnotationsToXFDF și SetXFAFromString sunt punctele de intrare, iar fiecare dintre acestea are o variantă de fișier și o variantă de șir de caractere
Motivul pentru care există atât de multe metode este că datele de formular PDF nu reprezintă un singur lucru. Un AcroForm completat are valori de câmp, dar poate conține și comentarii de revizuire, în timp ce un formular XFA moștenit (legacy) încorporează o descriere completă XML a aplicației care nu are legătură cu niciuna dintre celelalte două. losLab PDF Library păstrează aceste trei funcționalități pe API-uri separate în mod deliberat, deoarece îmbinarea lor ar impune un model de date greșit pentru cel puțin două dintre ele. Decizia privind familia de metode de care aveți nevoie este prima alegere de proiectare și este stabilită de obicei în momentul în care știți ce consumă de fapt sistemul receptor de pe cealaltă parte
Care este diferența dintre datele de formular FDF, XFDF și XFA?
FDF și XFDF conțin aceleași informații în două sintaxe diferite, iar XFA reprezintă o lume separată. FDF este un document în miniatură cu sintaxă PDF (ISO 32000-2 §12.7.8): un tablou (array) /Fields de dicționare << /T (nume) /V (valoare) >>, cu șiruri de caractere escapate exact în modul în care sunt escapate șirurile literale în interiorul unui PDF. XFDF este forma XML a acelorași date (ISO 19444), un arbore <fields> pe care Acrobat și majoritatea backend-urilor de formulare îl citesc și îl scriu în mod nativ. XFA nu este niciunul dintre acestea: este un șablon XML Forms Architecture plus datele seine, stocat ca un XML Data Package (XDP) pe care PDF-ul îl referențiază din /AcroForm/XFA. Alegeți FDF sau XFDF când interoperați pe valori de câmp și apelați la XFA doar atunci când întrețineți un document care a fost creat inițial ca un formular XFA
În cadrul FDF și XFDF, losLab PDF Library trasează o a doua linie de demarcație: valorile câmpurilor versus comentariile de adnotare. Familia de date de formular (ExportFormDataToFDF, ImportFormDataFromFDF, ExportFormDataToXFDF, ImportFormDataFromXFDF) citește și scrie subarborele /Fields și nu atinge nimic altceva. Familia de adnotări (ExportAnnotationsToFDF, ImportAnnotationsFromFDF, ExportAnnotationsToXFDF, ImportAnnotationsFromXFDF) citește și scrie în schimb subarborele /Annots, ceea ce Acrobat numește Export Comments. Cele două nu se suprapun niciodată, astfel încât exportul valorilor câmpurilor nu va colecta note de revizuire rătăcite, iar importul comentariilor nu va modifica valorile pe care un utilizator le-a introdus deja. Ceea ce face un widget (control) când este apăsat sau recalculat reprezintă o a treia problemă distinctă, acoperită în nota însoțitoare despre acțiunile interactive de formular și JavaScript
Cum se populează un formular PDF din FDF sau XFDF în Delphi?
Încărcați documentul, apelați o metode de import și salvați. ImportFormDataFromXFDF și ImportFormDataFromFDF analizează fiecare datele de formular primite, potrivesc fiecare intrare cu un câmp AcroForm după numele său complet calificat, stabilesc valoarea și returnează numărul de câmpuri actualizate efectiv. Ambele metode actualizează doar câmpurile care există deja în PDF-ul țintă; niciuna nu creează un câmp pentru un nume pe care formularul nu îl definește, ceea ce împiedică un fișier de date rătăcit sau ostil să vă mărească formularul în mod silențios
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;
Câmpuri ierarhice, selecții multiple și text formatat
Numele ierarhice de câmpuri sunt primul loc în care un exportator simplist se blochează. AcroForm adresează un câmp imbricat cu un titlu complet separat prin puncte, cum ar fi Applicant.FullName, dar XFDF nu plasează acel șir cu puncte într-un singur atribut name; ISO 19444 îl imbricează, sub forma <field name="Applicant"><field name="FullName">. losLab PDF Library împarte titlul cu puncte în elemente <field> imbricate la export și reasamblează elementele imbricate înapoi în titlul complet la import, astfel încât cele două direcții să rămână simetrice. La export, omite de asemenea câmpurile părinte non-terminale, deoarece un nod părinte într-un AcroForm are doar rol de nivel de denumire și nu are o valoare proprie; emiterea acestuia ar produce un element <value></value> gol care nu s-ar potrivi cu formularul real. Casetele de listă cu selecție multiplă (multi-select) sunt a doua capcană: un câmp de opțiuni poate conține mai multe valori selectate deodată, pe care XFDF le exprimă ca elemente <value> repetate, iar FDF le exprimă ca un tablou /V, iar losLab PDF Library împarte un câmp în mai multe valori doar atunci când este într-adevăr o alegere cu selecție multiplă, astfel încât un câmp de text obișnuit pe mai multe linii își păstrează întreruperile de linie în loc să fie fragmentat în valori eronate
Textul formatat (rich text) este al treilea element și cel pe care programatorii îl greșesc cel mai des. Un câmp cu formatare își stochează marcajul în intrarea RV ca un subarbore XHTML, iar XFDF îl transportă în <value-richtext>. losLab PDF Library scrie acel subarbore ca un fragment XML activ în loc să îl escapeze, astfel încât un instrument din aval citește text formatat real în loc de un șir de etichete (tags) vizibile; la import, păstrează subarborele RV brut și aplică în continuare elementul simplu <value> la V. Acolo unde un câmp le oferă pe amândouă, valoarea simplă câștigă pentru V, iar textul formatat este transmis alături în RV, aceasta fiind regula de interoperabilitate care împiedică un import de text formatat să rescrie în mod silențios o valoare pe care un alt instrument a setat-o deja. Atunci când textul formatat există pentru a transmite structura documentului către tehnologiile de asistență, tratați-l în același mod în care ați trata ordinea de citire discutată în nota despre structura de accesibilitate și PDF etichetat (tagged)
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;
Cum se realizează fluxul complet (round-trip) al comentariilor de adnotare ca FDF sau XFDF?
Comentariile circulă în cadrul familiei de adnotări, iar subsetul acceptat este în mod deliberat restrâns. ExportAnnotationsToXFDF și ImportAnnotationsFromXFDF, împreună cu echivalentele lor FDF, transportă marcaje de tip text cu câmpurile care realizează de fapt un ciclu complet curat: subtipul adnotării, dreptunghiul acesteia, indicele paginii bazat pe 0, autorul în T, subiectul în Subj, conținutul simplu Contents și culoarea, care mapează tripletul PDF /C DeviceRGB din și într-un atribut XFDF #RRGGBB. Importul acceptă doar numele de elemente cunoscute și omite orice intrare a cărei pagină este în afara limitelor sau al cărei dreptunghi lipsește, astfel încât un XFDF editat manual sau străin nu poate introduce o adnotare defectuoasă în document. Ceea ce nu acoperă încă acest subset merită menționat în mod clar: conținutul textului formatat (RC), pop-up-urile, punctele de cadrane (quadpoints), listele de cerneală (ink lists), vârfurile (vertices) și fluxurile de aspect pre-randate (baked appearance streams) nu fac obiectul acestei versiuni, așa că geometria de evidențiere și aspectul ștampilelor personalizate nu vor supraviețui acestei căi. Pentru a confirma ce a fost importat efectiv, parcurgeți adnotările paginii sau arborele mai larg de elemente descris în căutarea de text și enumerarea elementelor de pagină
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;
Scrierea unui pachet XFA XDP complet cu SetXFAFromString
XFA este cazul atipic, iar SetXFAFromString este modul în care scrieți întregul pachet deodată. Metoda primește un XML Data Package complet, documentul <xdp:xdp> cu pachetele sale de șabloane și seturi de date, și îl stochează ca flux referențiat din /AcroForm/XFA. losLab PDF Library creează containerul AcroForm la cerere atunci când documentul nu are niciunul, astfel încât nu trebuie să adăugați un câmp de umplutură doar pentru a oferi XFA un punct de conectare, și elimină orice stare XFA analizată pe care o deținea, astfel încât o citire ulterioară să reflecte pachetul pe care tocmai l-ați scris, mai degrabă decât un cache învechit. Deoarece un pachet XFA este XML și nu neapărat UTF-8, biblioteca detectează un marcaj de ordine a octeților (BOM) UTF-16 și decodifică corect pachetul înainte de analiză, lucru important pentru pachetele produse de instrumente care au ca implicit UTF-16
Odată ce pachetul este la locul său, GetXFAFormFieldValue și SetXFAFormFieldValue adresează câmpuri individuale prin calea lor Scripting Object Model (SOM). losLab PDF Library acceptă rădăcinile SOM standard, precum și căile relative simple, astfel încât form1.FullName, $data.form1.FullName și xfa.datasets.data.form1.FullName se rezolvă toate la același nod de date, iar partea de șablon acceptă $template și xfa.template în același mod. Această toleranță este importantă atunci când căile SOM sunt generate de un alt sistem care emite întotdeauna forma complet calificată
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;
Rezumatul onest este că valorile câmpurilor realizează un ciclu complet prin FDF și XFDF, incluzând ierarhia, selecția multiplă și textul formatat; comentariile de adnotare realizează un ciclu complet ca un subset definit de marcaj text cu lacune clare; iar XFA este scris și citit ca un pachet întreg cu acces SOM suplimentar la nivel de câmp. Adaptați formatul la consumator, declarați UTF-8 pentru tot ceea ce construiți manual și rețineți că metodele de import afectează doar câmpurile și adnotările care se potrivesc deja cu documentul. Metodele de date de formular, adnotări și XFA descrise aici fac parte din losLab PDF Library pentru Delphi și C++Builder, a cărei referință conține lista completă de parametri pentru fiecare punct de intrare de export și import