PDF računa ali stroškov, kjer se postavke seštevajo same in se datum samodejno oblikuje, potrebuje tri stvari pritrjene na svoj AcroForm, in HotPDF doda vse tri naloženi datoteki v Delphi: ApplyLoadedFieldCalculation za vsote AFSimple_Calculate, ApplyLoadedFieldValidation za pomočnike Acrobat AF za oblikovanje in preverjanje ter EnsureLoadedFieldAppearanceStream za zapeko vrednosti, ki jo pregledovalnik dejansko izriše
HotPDF je domača komponenta VCL PDF za Delphi in C++Builder in te tri metode delujejo na dokumentu, ki ste ga odprli z LoadFromFile, in ne na tistem, ki ga gradite iz nič. Vsaka vzame 0-indeksiran indeks polja v polju AcroForm /Fields — enak vrstni red, kot ga vrne GetLoadedFormFieldNames — in piše neposredno v slovar polja, tako da je celotno delo le nalaganje, indeksiranje, pripenjanje, SaveLoadedDocument. Gradnja samega nabora polj je ločena naloga, zajeta v dodajanju polj AcroForm naloženemu PDF v Delphi, medtem ko je ta stran o dodajanju aritmetike in oblikovanja obstoječemu naboru polj
Zakaj obrazec PDF potrebuje skripte za seštevanje lastnih polj?
Ker PDF nima pregledovalne plasti. Besedilno polje drži niz, ne formule, in nič v datoteki ne preračuna vsote, ko se postavka spremeni, razen če je pritrjena skripta, ki to stori. Mehanizem je slovar dodatnih dejanj polja, /AA (ISO 32000-1 §12.7.5), ki preslika sprožilne dogodke v dejanja: sprožilec pritiska tipke (K), ko znaki prispejo, sprožilec oblikovanja za prikaz, sprožilec preverjanja (V) ob potrditvi in sprožilec računanja (C), ki se sproži, ko se spremeni katero koli polje na obrazcu. Vsako dejanje je dejanje JavaScript, /S /JavaScript (ISO 32000-1 §12.6.4.14), in skripta, ki jo izvede, je tisto, kar dejansko izvede seštevek ali preoblikovanje. Acrobat ponuja knjižnico že pripravljenih pomočnikov — AFSimple_Calculate, AFNumber_Format, AFDate_FormatEx in ostale —, zato je priložena skripta obyčajno enovrstični klic v to knjižnico in ne koda po meri
Ena podrobnost odloča o tem, ali večstopenjski obrazec da pravilen odgovor: vrstni red računanja. Acrobat zažene vsako polje, ki nosi dejanje računanja, in jih izvede v zaporedju, ki ga navaja polje AcroForm /CO, in ne v vrstnem redu strani. ApplyLoadedFieldCalculation pripne dejanje računanja polju, ki ga poimenujete; ko eno izračunano polje napaja drugo — delna vsota, ki jo bere davčna vrstica, nato pa končna vsota, ki bere obe —, morate potrditi, da vrstni red /CO navaja vsak vhod pred poljem, ki ga porabi, sicer bo končna vsota prebrala zastarelo delno vsoto in zaostajala za eno urejanje
Kako doseči, da obrazec PDF samodejno izračuna vsote?
ApplyLoadedFieldCalculation vzeme indeks ciljnega polja, operacijo in imena izvornih polj, ki jih mora združiti. HotPDF zapiše AFSimple_Calculate("SUM", ["lineTotal.1", "lineTotal.2", ...]) v dejanje računanja ciljnega polja, naštevanje THPDFFieldCalcOp pa izbere funkcijo: fccSum, fccAverage, fccProduct, fccMinimum in fccMaximum se preslikajo v Acrobatove SUM, AVG, PRD, MIN in MAX. Izvorna imena so imena polj AcroForm, isti nizi, ki jih vrne GetLoadedFormFieldNames, tako da je skupni seštevek treh postavk in stroška pošiljanja en sam klic
var
Pdf: THotPDF;
Names: THPDFAnsiStringArray;
i, TotalIdx: Integer;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.LoadFromFile('invoice.pdf');
Names := Pdf.GetLoadedFormFieldNames;
TotalIdx := -1;
for i := 0 to High(Names) do
if Names[i] = 'grandTotal' then TotalIdx := i;
if TotalIdx >= 0 then
begin
Pdf.ApplyLoadedFieldCalculation(TotalIdx, fccSum,
['lineTotal.1', 'lineTotal.2', 'lineTotal.3', 'shipping']);
Pdf.EnsureLoadedFieldAppearanceStream(TotalIdx);
end;
Pdf.SaveLoadedDocument('invoice-live.pdf');
finally
Pdf.Free;
end;
end;
Klic EnsureLoadedFieldAppearanceStream na skupni vsoti ni kozmetičen. Računanje teče znotraj pregledovalnika, tako da dokler bralnik, ki podpira skripte, ne odpre datoteke, polje skupne vsote nima lastne upodobljene vsebine. Pečenje toka videza mu daje številko za prikaz v vmesnem času, kar bo izbral tiskalni posel ali generator sličic, ko nikoli ne zažene skripte
Oblikovanje in preverjanje polj s paketom pomočnikov AF
ApplyLoadedFieldValidation pripne skripte za oblikovanje, pritisk tipk in preverjanje v enem klicu, tip THPDFFieldValidationKind, ki ga prenesete, pa določa, katerega pomočnika Acrobat bo povezal. Prenesite fvkCurrency in HotPDF zapiše AFNumber_Format(2,0,0,0,"$ ",true) kot skripto za oblikovanje z ustreznim AFNumber_Keystroke; fvkNumber uporablja "." za ločilo, fvkPercentage oddaja AFPercent_Format, fvkDate pa oddaja AFDate_FormatEx("dd/mm/yyyy"), razen če prenesete svojo masko v argumentu DateFormat. Posebne oblike — fvkZipCode, fvkSSN in fvkPhone — se preslikajo v AFSpecial_Format s kodo, ki jo Acrobat rezervira za vsako, fvkArbitraryMask pa vzeme niz maske skozi argument Mask za vse, česar te prednastavitve ne pokrivajo. Za številčne vrste HotPDF pripne tudi skripto AFRange_Validate, tako da je izvenobsežni vhod zavrnjen ob potrditvi
// Format the invoice date as ISO, the amount as currency, and mask a tax id
Pdf.ApplyLoadedFieldValidation(DateIdx, fvkDate, 'yyyy-mm-dd', '');
Pdf.ApplyLoadedFieldValidation(AmountIdx, fvkCurrency, '', '');
Pdf.ApplyLoadedFieldValidation(TaxIdIdx, fvkArbitraryMask, '', '999-99-9999');
Pdf.EnsureLoadedFieldAppearanceStream(AmountIdx);
Pomočniki AF pokrivajo običajne oblike, tako da vam nikoli ni treba ročno pisati JavaScripta zanje. Ko polje potrebuje logiko, ki je nobena prednastavitev ne izraža — kontrolno vsoto, navzkrižno pravilo, izraz po meri —, pripnite surovo skripto sami z metodami dejanj na ravni polj, opisanimi v gradnji polj in dejanj AcroForm s HotPDF, ki neposredno vzamejo niz JavaScript. Obe poti pišeta v isti slovar /AA, tako da prednastavljena oblika valute na enem polju in ročno napisano preverjanje na drugem soobstajata v istem dokumentu
Why must you regenerate the appearance stream?
Ker sta niz vrednosti in slikovne pike, ki jih pregledovalnik izriše, dve različni stvari v PDF, in spreminjanje ene ne spremeni druge. Polje shranjuje svojo vrednost v /V, toda tisto, kar bralnik upodobi, izhaja iz toka videza polja, /AP /N. Uredite /V skozi graf objektov in strog pregledovalnik bo še vedno prikazoval star videz, dokler ga nekaj ne regenerira. Slovar obrazca prenaša zastavico /NeedAppearances, ki prosi pregledovalnika, da ob odpiranju ponovno zgradi vsak videz, in Acrobat jo upošteva — toda v brskalnik vgrajeni upodabljalniki, mobilni bralniki, tiskalni strežniki in generatorji sličic jo pogosto prezrejo in izrišejo kateri koli tok, ki je že prisoten, ali pa nič. EnsureLoadedFieldAppearanceStream zapre to vrzel tako, da sam zgradi Form XObject /AP /N iz polj /DA, /V in /Rect, tako da upodobljena vrednost potuje znotraj datoteke, nemesto da bi bila odvisna od pregledovalnika, da jo ponovno nariše
// Bake an appearance for every field before saving, so values render everywhere
Names := Pdf.GetLoadedFormFieldNames;
for i := 0 to High(Names) do
Pdf.EnsureLoadedFieldAppearanceStream(i);
Pdf.SaveLoadedDocument('invoice-flat-appearance.pdf');
Kje skripte AF prenehajo delovati
Vsaka skripta AF* je odvisna od tega, ali ima pregledovalnik motor JavaScript, večina pregledovalnikov pa ga nima. Acrobat in peščica namiznih izdelkov poganjajo te pomočnike; pregledovalniki PDF, vgrajeni v Chrome, Edge, Firefox in glavne mobilne platforme, skupaj s strežniškimi rastrirniki in tiskalnimi cevovodi, sploh ne izvajajo JavaScripta obrazcev. V teh bralnikih se računanje nikoli ne sproži in oblikovanje se nikoli ne uveljavi — polje preprosto prikazuje kateri koli tok videza, s katerim je bilo nazadnje shranjeno, kar je natanko razlog, zakaj je pečenje /AP /N pomembno. Obravnavajte plast AF* kot priročnost za podmnožico uporabnikov na bralniku, ki podpira skripte, in nikoli kot jamstvo. Katero koli vsoto, ki mora biti pravilna na strežniku — znesek računa, ki ga boste zaračunali, davčna številka, ki jo boste vložili —, morate po vrnitvi obrazca ponovno izračunati na vaši strani, saj ne morete predpostaviti, da je bralnik, ki ga je izpolnil, izvedel eno samo vrstico vaše skripte
Vredno je poimenovati še en primer: obrazci, ki so prispeli kot XFA. Dinamični obrazec XFA prenaša svoj računski motor v tovoru XML, o katerem pomočniki AF* ne vedo ničesar, zato pripenjanje AFSimple_Calculate polju XFA ne doseže ničesar. Najprej sploščite obrazec XFA v navaden AcroForm, kot je zajeto v sploščenju XFA v AcroForm v Delphi, in tri metode se nato uveljavijo za rezultirajoča polja AcroForm natanko tako kot za kateri koli drug naložen obrazec
Samodejno računanje in samodejno oblikovanje obrazcev AcroForm se zvede na tri klice na naloženem dokumentu — pripnite računanje, pripnite oblikovanje in preverjanje ter zapecite videz —, čemur sledi SaveLoadedDocument. Tukaj prikazana API za naložene obrazce je del komponente HotPDF Component za Delphi in C++Builder, ki dokumentira celotna naštevanja THPDFFieldValidationKind in THPDFFieldCalcOp skupaj s preostalo površino AcroForm