Tehnički članak

Dodavanje AcroForm polja u učitani PDF u Delphiju

Imate predložak računa treće strane ili arhivirani ugovor koji je netko generirao prije mnogo godina u softveru koji više nitko ne može pronaći, a zahtjev je da ga učinite interaktivnim: stavite okvir za potpis u kut, dodajte nekoliko tekstnih polja, pretvorite ravnu kontrolnu listu u stvarne potvrdne okvire. Problem je u tome što ovaj PDF ne izrađujete od nule. Već postoji, već ima stranice, sadržaje i fontove koje ne kontrolirate, i trebate nadograditi objektni graf AcroForm widgetima bez ponovne izrade. To je drugačiji problem od izrade obrasca na novom dokumentu, a dio koji ljude zbuni nevidljiv je sve dok rezultat ne otvorite u pregledniku i polja koja ste upravo upisali nigdje nisu na stranici

HotPDF je izvorna VCL PDF komponenta za Delphi i C++Builder, a od verzije v2.247.0 nudi namjensku skupinu metoda baš za to: izradu svih šest standardnih vrsta polja izravno na dokumentu učitanom pomoću LoadFromFile. Ovaj članak prolazi kroz to što te metode rade, ISO 32000-1 rječnik koji stvaraju i jednu zastavicu bez koje cijeli postupak tiho proizvede datoteku koja izgleda prazno

Zašto je stvaranje polja na učitanom dokumentu vlastiti put koda

Kada PDF gradite od nule, HotPDF upravlja cijelim objektim modelom. Svaka je stranica zapisivi THPDFPage omotač, a dodavanje tekstnog polja kroz AddTextField povezuje novi widget s objektom napomena stranice, objektom stranice i zbirkom polja obrasca, a zatim iz resursa fontova dokumenta stvara appearance stream. Appearance stream je vidljiva površina widgeta, okvir, obrub i sav zadani tekst, iscrtani kao PDF crtački operatori koje preglednik prikazuje doslovno

U učitanom dokumentu nemate ništa od te potpore. Stranice su stigle kao sirovi rječnici; nema zapisivog THPDFPage omotača na koji biste objesili widget, a što je važnije, nema fontnog cjevovoda spremnog za crtanje appearance streamova. Učitani put zato ide drugim smjerom. Polja zapisuje izravno u parsirani objektni graf i stranice adresira preko nultog indeksa umjesto preko objekta stranice. Vrste polja i bitovi zastavica potpuno se podudaraju s putem od nule, pa je Text field Text field na oba načina; ono što se mijenja jest cjevovod ispod i, što je ključno, način na koji se iscrtava površina widgeta

Zašto je zastavica /NeedAppearances ovdje obavezna

Ovo je jedina činjenica koja odlučuje hoće li se vaš rad pojaviti. Budući da učitani put ne generira appearance streamove, novododani widget u preglednik stiže bez /AP unosa: polje bez opisanog izgleda. Mnogi preglednici, kada trebaju prikazati widget koji nema appearance niti uputu da ga sami izgrade, ne nacrtaju ništa. Polje je u datoteci, strukturno valjano, dostupno alatu za popunjavanje obrasca i potpuno nevidljivo čovjeku

Zaobilazni izlaz definiran je u ISO 32000-1 §12.7.3: rječnik AcroForm nosi /NeedAppearances logičku vrijednost, a kada je true istinita, usklađeni čitač mora sam izgraditi nedostajuće appearance streamove iz svakog polja/DA stringa i vrijednosti. HotPDF to postavlja umjesto vas. Prvi put kada dodate bilo koje polje u učitani dokument, EnsureLoadedAcroForm se pokreće: ako katalog nema /AcroForm kreira ga, ako nema /Fields polja, kreira i to, i prisiljava /NeedAppearances true. To ne pozivate izravno, ali činjenica da postoji objašnjava ponašanje. Objašnjava i napomenu o implementaciji koju vrijedi jasno reći: nekolicina minimalnih ili neusklađenih preglednika ignorira /NeedAppearances i dalje ne prikazuje ništa. Za uobičajene čitače zastavica radi svoj posao, ali ako vaša publika koristi neobičan ugrađeni renderer, testirajte ga prije nego što nešto obećate

Dodavanje šest vrsta polja

Svaka metoda slijedi istu strukturu. Prosljeđujete indeks stranice s nultim početkom, četiri kuta pravokutnika widgeta u PDF koordinatama korisničkog prostora, naziv polja i sve dodatne argumente koje tip treba. Pravokutnik je X1, Y1, X2, Y2 s ishodištem PDF-a u donjem lijevom kutu stranice, pa su veće Y vrijednosti više; to je koordinatna konvencija iz formata datoteke, a ne konvencija zaslona s gornjim lijevim kutom, i pogrešan redoslijed je druga najčešća pogreška nakon zaboravljanja zastavice. Svaki poziv vraća novi indeks polja s nultim početkom, ili -1 ako je indeks stranice izvan raspona ili se objekt stranice nije mogao razriješiti

var
  Pdf: THotPDF;
  Idx: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('contract.pdf') <= 0 then Exit;

    // Text field: name, initial value, max length (0 = unlimited)
    Idx := Pdf.AddLoadedTextField(0, 72, 680, 320, 700, 'FullName', '', 0);

    // CheckBox: export value, initial checked state
    Pdf.AddLoadedCheckBox(0, 72, 640, 90, 658, 'AgreeTerms', 'Yes', False);

    // Signature field: just a name and a rectangle
    Pdf.AddLoadedSignatureField(0, 360, 72, 540, 132, 'ApproverSig');

    if Idx >= 0 then
      Pdf.SaveLoadedDocument('contract-interactive.pdf');
  finally
    Pdf.Free;
  end;
end;

Treći i četvrti string argument tekstnog polja jesu naziv polja i njegova početna /V vrijednost; cijeli broj je /MaxLen, koji se zapisuje samo kada je veći od nule. HotPDF svakom uređivom polju daje zadani string izgleda /Helv 12 Tf 0 0 0 rg, što je ono što čitač koji poštuje /NeedAppearances čita kako bi odlučio kojim fontom i bojom ispisuje vrijednost. Potvrdni okvir uzima izvoznu vrijednost, niz koji obrazac šalje kada je okvir označen, plus logičku vrijednost za početno stanje; interno zapisuje odgovarajuće /V, /AS, i /DV nazive unosa tako da su stanja uključenja i isključenja usklađena čim se datoteka otvori. Prazna izvozna vrijednost prema zadanim postavkama postaje Yes, uobičajeni naziv za checkbox u stanju "on"

Izborna polja i bitne zastavice /Ff

ComboBox i ListBox su oba izborna polja, vrsta polja /Ch u ISO 32000-1 §12.7.4. Razlika između padajućeg izbornika i popisa sa pomicanjem jedna je bit u cjelobrojnoj zastavici polja /Ff: bit 18, zastavica Combo, vrijednost $40000. HotPDF tu bit postavlja za AddLoadedComboBox i ostavlja ga isključenim za AddLoadedListBox; inače su ta dva ista, a oba svoje izbore uzimaju kao otvoreni niz stringova upisan u /Opt unos

// Dropdown (Combo flag set internally) with an initial selection
Pdf.AddLoadedComboBox(0, 72, 600, 300, 620, 'Country', 'Canada',
  ['United States', 'Canada', 'Mexico']);

// Scrolling list, no initial value
Pdf.AddLoadedListBox(0, 72, 520, 300, 590, 'Priority', '',
  ['Low', 'Normal', 'High']);

// Push button with a caption drawn through /MK
Pdf.AddLoadedPushButton(0, 360, 600, 480, 626, 'SubmitBtn', 'Submit');

Dvije napomene o popisu opcija. HotPDF svaki /Opt unos zapisuje kao običan string, gdje su izvozna vrijednost i prikazana oznaka isti tekst. ISO 32000-1 §12.7.4.4 također dopušta dvoelementni [export display] oblik kada vam treba da se poslana vrijednost razlikuje od onoga što korisnik vidi; metode za stvaranje na učitanom dokumentu koriste jednostavniji jednostruki string oblik, pa ako trebate različite izvoznu i prikaznu vrijednost, to biste sami postavili u rezultirajućem rječniku. A vrijednost koju prosljeđujete kao trenutačni odabir polja trebala bi biti jedna od ponuđenih opcija, jer je preglednik uspoređuje s popisom

Push gumb je drugi slučaj vođen zastavicama: vrsta polja /Btn s bitom 17, zastavicom PushButton, vrijednost $10000. Taj bit odvaja klikabilni gumb od potvrdnog okvira, koji je također /Btn polje, ali bez njega. Natpis koji prosljeđujete zapisuje se u rječnik karakteristika izgleda /MK kao uobičajeni natpis /CA. Iskreno o opsegu ovdje vrijedi reći ovo: gumb se stvara s oznakom i pravokutnikom, ali metoda za stvaranje na učitanom dokumentu ne prilaže akciju, pa je sam po sebi to gumb koji izgleda ispravno i pri kliku ne radi ništa. Povezivanje akcija za slanje, poništavanje ili JavaScript zasebna je stvar; za stranu izrade od nule tijek rada polje-plus-akcija opisan je u izrada AcroForm polja i akcija u Delphiju, koji je prava točka usporedbe za ono što učitani put namjerno izostavlja

Rječnik koji svako polje dijeli

Ispod svih šest metoda nalazi se jedan zajednički graditelj koji stvara widget anotaciju i registrira je na dva mjesta. On zapisuje /Type /Annot i /Subtype /Widget, /Rect niz iz vaših četiriju koordinata, zastavice anotacije /F 4 koje postavljaju Print bit tako da se polje ispisuje i na papiru i na zaslonu, naziv polja /T, vrstu polja /FT, zastavice /Ff, i /P povratnu referencu na objekt stranice. Zatim novi field dodaje u AcroFormovu /Fields polje i u /Annots niz te stranice, razrješavajući usput neizravne reference tako da proširuje stvarne nizove umjesto da widget ostavi bez roditelja

Ta dvostruka registracija važna je zato što widget koji živi samo u jednom od ta dva popisa ne radi kako treba na suptilan način. Polje prisutno u /Fields ali nedostaje iz /Annots poznato je obrascu, ali se nikada ne iscrtava; obrnuto je iscrtano, ali nepoznato logici obrasca. HotPDF drži oba u sinkronizaciji pri svakom dodavanju, što je vrsta vođenja evidencije koju biste inače morali savršeno pogoditi ručno prema specifikaciji

Nekoliko iskrenih ograničenja

Postavite očekivanja prije nego što na ovome izgradite tijek rada. Ponašanje flatten-and-regenerate ovisi o tome poštuje li preglednik /NeedAppearances , što pokriva Acrobat, moderne pregledničke PDF engine i uobičajene desktop čitače, ali nije čvrsto jamstvo za svaki renderer u divljini. Ako morate proizvesti datoteku čija polja svugdje izgledaju jednako, uključujući i u preglednicima koji ignoriraju zastavicu, tada ste u području appearance streamova i od nule pisani pristup koji vam crta /AP za vas je bolji izbor. Isto tako, signature field se stvara kao prazni signature widget spreman za potpisivanje; postavljanje polja nije isto što i primjena kriptografskog potpisa

Za mijenjanje onoga što već postoji, umjesto za dodavanje novog, srodna operacija je flattening obrasca, gdje interaktivna polja pečete natrag u statični sadržaj stranice tako da vrijednosti postanu trajne i neuređive; taj povratni ciklus, uključujući to kako se obrađuju obrasci s XFA-om, opisan je u ravnanje XFA i AcroForm polja u Delphiju. Dodavanje polja i ravnanje polja dvije su strane istog životnog ciklusa: ovaj članak pokazuje kako interaktivnost dovesti na dokument kojem je nedostajala, a ravnanje je kako je ponovno ukloniti kada obrazac odradi svoju svrhu

API za obrasce na učitanim dokumentima prikazan ovdje isporučuje se kao dio standardnog HotPDF Component za Delphi i C++Builder, uz potpunu referencu za zastavice polja, rukovanje izgledom i ostatak AcroForm modela