HotPDF pošlje vrednosti večizbirnih seznamov skozi povratni prehod FDF in XFDF tako, da vrednost polja od začetka do konca drži kot polje. Od različice 2.755.0 ExportLoadedFormToFDF, ExportLoadedInterchangeToFDF in ExportLoadedFormToXFDF zapišejo vsako izbrano možnost kot njen lasten niz FDF ali element <value> XFDF, ujemajoče uvozne metode pa vsako vrednost preverijo proti možnostim polja in znova zgradijo kazala izbire /I, preden karkoli spremenijo. Nič se vmes ne zlepi v en niz
Odpoved, ki jo to popravi, se zlahka ponovi. Vzemite naročni obrazec z večizbirnim seznamom možnosti izdelkov, pustite uporabniku izbrati dve med njimi, izvozite podatke obrazca za zaledni sistem in nato uvozite urejeno datoteko nazaj v PDF. Pred to spremembo se je seznam vrnil prazen ali napačen. Razlog je, da je ena od izvoznih vrednosti vsebovala prelom vrstice, stara pot pa je izbor izravnala v en sam niz, ločen z vrsticami. Dobiti več izborov nazaj iz tistega niza ni bilo nikoli zanesljivo, z izvozno vrednostjo, ki sama vsebuje prelom vrstice, pa sploh ne more delovati
Zakaj združevanje večizbirnih vrednosti s prelomi vrstic pokvari povratni prehod?
Združevanje izborov v en niz vrže proč meje med vrednostmi, vrednost pa lahko vsebuje ločilo, zato noben uvoznik ne more niza pravilno razdeliti nazaj. ISO 32000-1 §12.7.4.4 dovoljuje, da je vnos /V izbirnega polja bodisi en besedilni niz bodisi polje besedilnih nizov, seznam z zastavico MultiSelect (bit 22 od /Ff) pa uporabi obliko polja, takoj ko je izbranih več kot ena možnost. Ista sekcija definira /I kot polje kazal možnosti od nič v naraščajočem vrstnem redu, kar pregledovalniki uporabijo, da ločita dve možnosti, ki slučajno delita izvozno vrednost. V HotPDF skalarni pridobivalnik GetFormFieldValue bere le obliko niza, zato je spust polja skozenj degradiral izvoz v prazen niz, stari uvoz XFDF pa je zlepil ponavljajoče elemente <value> z LF. Predstavljajte si možnost, izvoženo kot Deep, prelom vrstice, Blue: po združitvi bi Deep\nBlue\nRed lahko bila dva izbora ali trije, datoteka pa ne da načina, da bi vedeli katerega. Popravek je bil, da se preneha uporabljati skalar na sredi povratnega prehoda povsem
Kaj vsebujejo izvožene datoteke FDF in XFDF?
HotPDF zapiše večizbirno vrednost kot tipizirano polje v FDF in kot en element <value> na izbor v XFDF, tako da meje ostanejo vidne na disku. V FDF vsak predmet obdrži črkovanje, ki ga je imel v izvornem PDF: šestnajstiški nizi gredo ven kot hex, dobesedni nizi pa so ubežani z enim samim pomožnikom, ki spremeni CR in LF v \r in \n. V XFDF koren nosi xml:space="preserve", kot zahteva ISO 19444-1, kar pomeni, da vsak presledek znotraj besedilnega elementa šteje kot podatek. HotPDF zato zapiše začetno oznako, ubežano besedilo in končno oznako vsakega <value> v enem kosu, zamik pa drži izven elementa, ter kodira CR, LF in TAB kot znakovne reference, tako da razčlenjevalnik XML, ki uporablja normalizacijo koncev vrstic, ne more spremeniti izvirnih bajtov
<!-- FDF: eno tipizirano polje na polje -->
<< /T (options) /V [(Deep\nBlue) (Red)] >>
<< /T (region) /V [<45553132>] >>
<!-- XFDF: en <value> na izbor -->
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
<fields>
<field name="options">
<value>Deep
Blue</value>
<value>Red</value>
</field>
</fields>
</xfdf>
Dva mejna primera izvoza sta vredna vedenja, preden napišete klicno kodo. Prvič, ExportLoadedFormToFDF zgradi celotno telo FDF v spominu, preden ustvari ciljno datoteko (popravljeno v 2.755.1), zato vrednost, ki je ni mogoče izvoziti, na primer polje, ki nosi kaj drugega kot nize, sproži izjemo, brez da bi obrezala obstoječo datoteko. Drugič, prazen izbor na seznamu, ki ponuja tudi izvozno vrednost praznega niza, je dvoumen v XFDF, ker <value/> lahko pomeni, da nič ni izbrano, ali da je izbrana prazna možnost. ExportLoadedFormToXFDF v tem primeru sproži izjemo, namesto da bi ugibal, in jo sproži, preden se ciljna datoteka odpre. FDF take dvoumnosti nima, ker sta /V [] in /V [()] različna. Oba izvoznika FDF prav tako preskočita končne točke samo z gradnikom, brez imena /T, v skladu z izvoznikom XFDF, ker jih noben uvoznik nikoli ne bi mogel ujemati nazaj s poljem
var
Pdf: THotPDF;
Written: Integer;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('order-form.pdf', '') > 0 then
begin
// Večizbirni seznami so zapisani kot /V [(...) (...)]
Written := Pdf.ExportLoadedFormToFDF('order-form.fdf');
try
Pdf.ExportLoadedFormToXFDF('order-form.xfdf');
except
on E: Exception do
// Prazen izbor plus prazna izvozna možnost: XFDF ne more ločiti
// jih, obstoječa datoteka .xfdf pa ostane nedotaknjena
ShowMessage('XFDF export refused: ' + E.Message);
end;
end;
finally
Pdf.Free;
end;
end;
Kako HotPDF preveri večizbirno vrednost ob uvozu?
HotPDF sprejme uvoženo polje le, kadar je cilj izbirno polje z nastavljeno zastavico MultiSelect in se vsaka vrednost v polju ujema z izvozno vrednostjo v polju /Opt tega polja. Vsako mesto možnosti se lahko uporabi enkrat, zato seznam z dvema možnostima, ki delita izvozno vrednost b, sprejme [<62> <62>] kot dva ločena izbora in zavrne tretji b. Znovi zgrajeni /I sledi vrstnemu redu /Opt in ne vrstnemu redu prihajajočih vrednosti, ker §12.7.4.4 zahteva naraščajoča kazala. HotPDF zgradi novi /V in /I kot odcepljena objekta in ju dodeli šele, ko je vsaka vrednost prestala preverjanje, zato zavrnjena vrednost nikoli ne pusti za sabo polovice polja ali zastarelih kazal. Kopija se zapiše polju, ki se uvaža, in ne v skupno starševsko polje, šestnajstiška črkovanja, ki pridejo iz FDF, ostanejo hex skozi shranjevanje, polja, katerih izračuni so odvisni od seznama, pa so označena za ponovni izračun. Če morate le nastaviti eno vrednost, nastavljanje ene vrednosti polja obrazca v naloženem PDF teče skozi skalarno pot, ki po zasnovi ne obravnava več izborov
Nekatera druga orodja zapišejo navadne izvozne vrednosti ASCII kot šestnajstiške nize brez oznake vrstnega reda bajtov, na primer <416272>, in nato izvozijo XFDF tako, da tiste šestnajstiške števke zapišejo kot besedilo. Stroga dobesedna primerjava na poti nazaj odpove in uvoz se prekine. Različica 2.755.1 dodaja eno ponovitev: ko se vrednost ne ujema z nobeno možnostjo, HPDFHexSpellingText dekodira besedilo kot šestnajstiški paket in rezultat primerja znova. Ponovitev velja samo za vhod, ki bi sicer sprožil izjemo, zato nikoli ne spremeni vrednosti, ki se je že ujema. Ista izdaja je prav tako poskrbela, da skalarna pot in pot polja uporabljata isti dekoder Unicode, ki razume PDFDocEncoding, UTF-16 s katero koli oznako vrstnega reda bajtov in UTF-8. Pred tem se je ena logična vrednost lahko ujema na eni poti in odpovedala na drugi v dokumentih, ki so mešali kodiranja
Zakaj lahko veljavna datoteka FDF še vedno izgubi polja med razčlenjevanjem?
Pregledovalnik FDF, ki ne sledi šestnajstiškim nizom, lahko prereže slovar polja na pol, ko se šestnajstiška vrednost konča točno ob zaključevalcu slovarja. V << /T (region) /V <416273>>> prvi > zapre šestnajstiški niz, naiven pregledovalnik pa ga prebere skupaj z naslednjim > kot konec slovarja in tiho izpusti polje. Uvoznik FDF na ravni datoteke je že sledil, ali je znotraj šestnajstiškega niza, in v 2.755.1 pregledovalca polja in slovarja za ImportLoadedInterchangeFromFDF počneta isto. Druga zadeva zadeva posredne reference. Datoteka FDF je majhen dokument v skladnji PDF z lastnim oštevilčenjem objektov (ISO 32000-1 §12.7.7), zato se vrednost, kot je /V [11 0 R], nanaša na objekt 11 datoteke FDF in ne na objekt 11 PDF-ja, ki ga izpolnjujete. Poenostavljen razčlenjevalnik FDF v HotPDF ne razrešuje referenc znotraj datoteke, zato takega polja ne sprejme, namesto da bi prebral, kar koli objekt 11 slučajno je v ciljnem dokumentu
Uvozi datoteke, toka in XFDF poročajo napake različno
Tri uvozne poti preverjajo enako, odpovedi pa poročajo različno, vredno je izbrati eno namenoma. ImportLoadedFormFromFDF preskoči vsako polje, ki odpove preverjanju, in vrne število polj, ki jih je res uporabil, tako da je števec, nižji od pričakovanega, edini znak težave. ImportLoadedInterchangeFromFDF in ImportLoadedFormFromXFDF sprožita izjemo pri prvem zavrnjenem polju. Vsako polje se zagosti zase, zato polja, obdelana pred izjemo, obdržijo svoje nove vrednosti. Nobene od teh ne obravnavajte kot transakcijo nad celotno izmenjalno datoteko: če potrebujete obnašanje vse-ali-nič, zavrzite naložen dokument, ko pride do izjeme, namesto da bi ga shranili
var
Pdf: THotPDF;
Source: TMemoryStream;
Status: AnsiString;
Info: THPDFFDFInterchangeInfo;
begin
Pdf := THotPDF.Create(nil);
Source := TMemoryStream.Create;
try
Source.LoadFromFile('order-form-reviewed.fdf');
if Pdf.LoadFromFile('order-form.pdf', '') > 0 then
try
// Samo polja; vrednost izven /Opt ali cilj brez večizbire sproži izjemo
if Pdf.ImportLoadedInterchangeFromFDF(Source, True, False, Status, Info) then
Pdf.SaveLoadedDocument('order-form-filled.pdf');
except
on E: Exception do
ShowMessage('Import rejected, nothing saved: ' + E.Message);
end;
finally
Source.Free;
Pdf.Free;
end;
end;
Razširjanje povratnih klicev XFDF, brez da bi se pokvarili obstoječi klicatelji
Podpora polja v nižji enoti XFDF živi v ločenem zapisu, THPDFXFDFArrayAccess, in v novih pretirjavah HPDFXFDFExportFields ter HPDFXFDFImportFields, ne v dodatnih poljih na koncu obstoječega zapisa THPDFXFDFAccess. Razlog je binarna združljivost. Koda, ki polni THPDFXFDFAccess kot krajevno spremenljivko, pogosto nastavi le mesta, ki jih pozna, in nikoli ne počisti preostalih, zato bi nov kazalec funkcije, dodan temu zapisu, vseboval smeti s sklada in knjižnica bi ga vzela za pravi povratni klic. Z ločenim zapisom stari klicatelji obdržijo staro postavitev in stare pretirjave, te pretirjave pa interno podajo zapis polja, vse nil. Izvirna pretirjava skalarnega uvoza še vedno zlepi ponavljajoče vrednosti z LF zaradi združljivosti, le pretirjava, ki zaveda polja, jih obdrži ločene. Ko vežete svojo podatkovno shrambo, začnite od Default(THPDFXFDFArrayAccess). Vrnite True iz GetFormFieldValueArray za vsako polje z vrednostjo seznama, vključno s takim, kjer nič ni izbrano, in False, da padete nazaj na skalarni povratni klic
uses HPDFXFDF;
// Goli kazalec funkcije, ne »of object«: Context nosi vašo shrambo
function StoreGetSelections(Context: Pointer; FieldIndex: Integer;
out Values: THPDFXFDFValueArray): Boolean;
begin
Result := TFormStore(Context).IsListField(FieldIndex);
if Result then
Values := TFormStore(Context).Selections(FieldIndex);
end;
procedure ExportStore(Store: TFormStore; out Bytes: TBytes);
var
Access: THPDFXFDFAccess;
ArrayAccess: THPDFXFDFArrayAccess;
begin
Access := MakeStoreAccess(Store); // vaše obstoječe skalarne vezi
ArrayAccess := Default(THPDFXFDFArrayAccess); // vsako neuporabljeno mesto je nil
ArrayAccess.GetFormFieldValueArray := StoreGetSelections;
HPDFXFDFExportFields(Access, ArrayAccess, Bytes);
end;
Izmenjava večizbirnih vrednosti deluje na seznamih, ki že obstajajo in imajo bit MultiSelect nastavljen v /Ff. Za to, kako se izbirna polja in njihovi zastavični biti sploh ustvarijo, glejte dodajanje ListBox in drugih polj AcroForm naloženemu PDF. Za označevanje pripomb, ki gre skozi drevo <annots> XFDF, glejte uvoz in izvoz pripomb XFDF v HotPDF. Celotna referenca API in preizkusni prenos sta na strani komponente HotPDF Delphi PDF