Articol tehnic

Exportul și importul XFDF în Delphi cu PDFium Component

PDFium Component pentru Delphi și Lazarus schimbă date de formulare și adnotări prin intermediul XFDF, formatul de schimb XML definit de ISO 19444-1. TPdf.ExportXFDF serializează fiecare valoare de câmp de formular și fiecare adnotare acceptată din documentul încărcat într-un fișier XFDF sau TStream; TPdf.ImportXFDF citește înapoi un document XFDF, recreând adnotările pe paginile lor și aplicând valorile câmpurilor. Acest flux bidirecțional acoperă două fluxuri de lucru de care orice aplicație de documente are nevoie în cele din urmă: un evaluator adnotează un PDF în Acrobat și vă trimite comentariile pentru a le îmbina, sau o regulă de conformitate impune ca datele din formulare să existe într-un fișier separat, comparabil și auditabil, în loc să fie încorporate direct în PDF-ul propriu-zis

Acceptă PDFium importul și exportul XFDF?

Biblioteca PDFium în sine nu le acceptă. API-ul C nativ nu are deloc funcții XFDF sau FDF — nimic din antetele sale publice nu citește sau scrie vreunul dintre formate, deci nicio cantitate de cod wrapper nu vă poate ajuta. Prin urmare, PDFium Component implementează întregul motor XFDF în Pascal, într-o unitate dedicată care construiește și analizează fișierele XML direct peste modelul de date existent TPdf pentru adnotări și câmpuri de formulare. Componenta de scriere (writer) emite XML-ul manual, iar cea de citire (reader) este un parser de stare scris manual, astfel încât caracteristica nu adaugă nicio dependență de Delphi XMLDoc sau de unitățile FPC DOM și se comportă identic în Delphi și Lazarus

Această decizie de proiectare contează atunci când evaluați alternativele. Dacă ați apelat funcții brute FPDF_* din Pascal, XFDF este o barieră: această capacitate pur și simplu nu există în DLL. Componenta depășește această barieră tratând XFDF ca pe o problemă pură de serializare — colectează valorile câmpurilor și înregistrările de adnotări pe care wrapperul știe deja să le citească, le scrie ca XML standard și inversează procesul la import

Ce conține un fișier XFDF?

ISO 19444-1 definește XFDF ca fiind reprezentarea XML a FDF, iar conținutul său este împărțit în doar două blocuri de nivel superior. Elementul <fields> conține numele ierarhice ale câmpurilor de formular și valorile lor — tot ceea ce un utilizator a tastat, a ales sau a bifat într-un AcroForm. Elementul <annots> conține adnotările: TPdf.ExportXFDF emite 18 subtipuri — text, highlight, underline, strikeout, squiggly, linie, cerc, pătrat, caret, poligon, polilinie, ștampilă, cerneală (ink), freetext, atașament de fișier, sunet, link și redactare. Adnotările de tip widget lipsesc în mod deliberat din <annots> deoarece datele lor circulă în <fields>, iar subtipurile interne ale vizualizatorului, cum ar fi Popup, nu fac parte din vocabularul XFDF

Pentru ca fluxul bidirecțional să fie exact, înregistrarea TPdfAnnotation a fost extinsă cu metadatele pe care le așteaptă XFDF: Name (identificatorul unic NM), Subject, ModificationDate, CreationDate, Icon, Opacity, punctele de capăt ale liniilor, vârfurile poligoanelor și poliliniilor și traseele gesturilor de cerneală. Fiecare câmp nou se asociază cu o santinelă booleană Has*, astfel încât codul care a construit adnotări pe versiunile anterioare continuă să se compileze și să producă aceleași dicționare — un câmp nesetat nu este scris niciodată. Dacă generați deja marcaje în mod programatic, aceeași înregistrare pe care o folosiți pentru adnotări de marcaj text cu puncte quad conține acum tot ceea ce are nevoie XFDF

Cum se exportă datele din formulare și adnotările în XFDF?

Un singur apel procesează întregul document. Încărcați PDF-ul cu completarea formularelor activată, apelați ExportXFDF, iar componenta parcurge fiecare pagină, colectează valorile câmpurilor și adnotările și scrie XML-ul. Valoarea returnată este numărul de octeți UTF-8 scriși, oferind o verificare rapidă în jurnal

var
  Pdf: TPdf;
  Bytes: Integer;
begin
  Pdf := TPdf.Create(Self);
  Pdf.FormFill := True;            // necesar pentru ca valorile câmpurilor să fie active
  Pdf.FileName := 'expense-report.pdf';
  Pdf.Active := True;
  Bytes := Pdf.ExportXFDF('expense-report.xfdf');
  ShowMessage(Format('%d bytes of XFDF written', [Bytes]));
end;

Ambele direcții au o supraîncărcare de tip TStream, deci nimic nu vă obligă să folosiți un fișier temporar pe disc. Exportarea într-un TMemoryStream este formatul firesc atunci când XFDF-ul se îndreaptă către un răspuns HTTP, un câmp blob din baza de date sau o intrare de arhivă semnată

var
  Buffer: TMemoryStream;
begin
  Buffer := TMemoryStream.Create;
  try
    Pdf.ExportXFDF(Buffer);        // același XML, nu implică fișiere
    Buffer.Position := 0;
    // trimiteți streamul către un răspuns web, o coloană de tip blob sau o intrare zip
  finally
    Buffer.Free;
  end;
end;

Cum îmbină ImportXFDF comentariile înapoi în document?

Partea de import reprezintă etapa în care se încheie fluxul de lucru al evaluatorului. Un coleg adnotează contractul în Acrobat, exportă comentariile ca XFDF și vă trimite câțiva kiloocteți de XML în loc de o a doua copie a PDF-ului. TPdf.ImportXFDF analizează acel fișier, creează fiecare adnotare pe pagina indicată de atributul său page și scrie valorile câmpurilor în adnotările widget potrivite. Funcția returnează numărul total combinat de câmpuri și adnotări aplicate, astfel încât interfața utilizator poate confirma exact ce s-a preluat

var
  Applied: Integer;
begin
  Applied := Pdf.ImportXFDF('review-comments.xfdf');
  StatusBar.SimpleText := Format('%d câmpuri și adnotări îmbinate', [Applied]);
end;

Odată ce adnotările se află în document, ciclul de recenzare continuă cu sistemul de răspunsuri și stări descris în construirea unui flux de lucru pentru recenzarea adnotărilor cu PDFium Component, iar valorile câmpurilor importate participă la logica de tab-uri prezentată în navigarea în câmpurile de formular

De ce contează separatoarele zecimale pentru XFDF?

Fiecare adnotare din XFDF este poziționată prin șiruri de coordonate — rect="70.5,540,200,560" și altele asemănătoare —, iar ISO 19444-1 impune utilizarea punctului ca separator zecimal. Formatarea implicită a numerelor reale din Delphi urmează specificul regional (locale) din Windows, deci pe un sistem german sau francez un simplu FloatToStr transformă 70.5 în 70,5, ceea ce corupe o listă de coordonate separată prin virgulă într-un text eronat pe care alte procesoare îl resping sau îl citesc greșit. PDFium Component normalizează fiecare număr pe care îl scrie: separatorul zecimal local este înlocuit cu un punct, iar zerourile de la sfârșit sunt eliminate, astfel încât fișierul exportat este identic din punct de vedere al octeților, fie că a fost produs pe o mașină en-US sau de-DE. Dacă ați depanat vreodată un instrument PDF care funcționa în birou și eșua la un client european, ați întâlnit exact această clasă de erori — este bine de știut că această componentă o rezolvă în mod automat

Care sunt limitele fluxului bidirecțional?

Două limite merită menționate clar. În primul rând, XFDF transportă date de adnotare, nu aspecte randate — fluxurile de aspect (appearance streams) nu fac parte din format, deci vizualizatorul receptor regenerează aspectul fiecărei adnotări din proprietățile sale. O evidențiere sau un pătrat se va randa corect oriunde; o ștampilă cu aspect personalizat va reveni la ceea ce vizualizatorul țintă desenează pentru acel nume de ștampilă. În al doilea rând, API-ul PDFium subiacent are setări (setters) pentru șiruri, dar nu și pentru numere de adnotare sau geometria căilor, deci Opacity, capetele de linii, vârfurile și gesturile de cerneală sunt doar pentru export: componenta le păstrează corect când scrie XFDF, dar nu le poate scrie înapoi într-un PDF la import. Valorile câmpurilor, conținutul, culorile, dreptunghiurile (rects), punctele quad, datele și metadatele de identitate funcționează bidirecțional în ambele sensuri

Pentru un început practic, exemplul XfdfLab este livrat în seturile demo pentru Delphi, C++Builder și Lazarus, conectând ambele apeluri la butoane peste orice PDF deschis. Suportul pentru XFDF este inclus în versiunea curentă a PDFium Component, alături de API-urile pentru adnotări și formulare pe care se bazează