XFA, XML formų architektūra, yra nebenaudojama. ISO 32000-1 nurodo ją 12.7 skyriuje su pastaba, kad ji pašalinta iš PDF 2.0, o modernios peržiūros programos po vieną atsisako savo XFA variklių. Tačiau niekas iš to neištuštino archyvų. Vyriausybių priėmimo formos, draudimo paraiškos ir bankų išrašai buvo kuriami kaip XFA geresniąją dviejų dešimtmečių dalį, ir šie failai vis dar pasiekia pašto dėžutes ir dokumentų srautus šiandien. Kai peržiūros programa, kuri anksčiau jas atvaizduodavo, nustoja tai daryti, forma virsta tuščiu puslapiu su vietos rezervuaru „prašome atidaryti kitoje skaityklėje“. Ilgalaikis sprendimas – suplokštinti XFA į statinį PDF turinį, kurį gali nupiešti bet kuri skaityklė
Sunkioji to plokštinimo dalis yra ne laukai. Teksto laukeliai ir žymimieji langeliai pakankamai švariai susieti su „AcroForm“ valdikliais. Sunkioji dalis yra raiškusis tekstas, kurį XFA saugo piešimo (draw) elemente, <exData contentType="text/html"> bloke. Šis blokas yra HTML poaibis su tiesioginiu (inline) stiliaus formatavimu ir, dažnai, inkaravimo žymėmis. Perkelti jį į puslapį reiškia atkurti tiek stilizuotą tekstą, tiek veikiančius hipersaitus, o ties hipersaitais dauguma įgyvendinimų tyliai pasiduoda
Kaip iš tikrųjų atrodo XFA raiškusis tekstas
exData turinys yra nedidelė XHTML dalis. Pastraipa yra <p>; stilizuota simbolių atkarpa yra <span>, turinti savo tiesioginį CSS svoriui, pasvirimui, spalvai ir dydžiui; o hipersaitas yra <a href="...">, gaubiantis matomą tekstą. Vienoje eilutėje iš eilės gali būti kelios atkarpos, kiekviena su skirtingu stiliumi, ir viena iš jų gali būti inkaras. Stilius nėra dekoracija, kurią galima praleisti. Sąlyga, pateikta paryškintai raudonai, nes tai teisinis įspėjimas, turi likti paryškinta raudonai ir po plokštinimo, kitaip suplokštintas dokumentas neteisingai atspindi originalą
Taigi plokštinimo variklis negali traktuoti šio bloko kaip vienos eilutės. Jis turi pereiti per vidinę struktūrą, išspręsti kiekvienos sekos galutinį stilių, padengiant tiesioginį CSS per piešimo elemento bazinį šriftą, ir išdėstyti sekas vieną po kitos per eilutę. HotPDF modeliuoja kiekvieną iš šių išdėstytų fragmentų kaip vidinį TXFARichRun įrašą. Įrašas neša sekos teksto, jos galutinį stilių, išmatuotą laukelį ir, inkaro atveju, Href, į kurį jis rodo
Sekų išdėstymas iš kairės į dešinę
Pozicionavimas yra ten, kur raiškusis tekstas nustoja būti analizės problema ir tampa tipografijos problema. Sekos dalijasi viena eilute, todėl kiekviena seka prasideda ten, kur baigėsi ankstesnė. Nėra jokio žymėjimo, kuris fiksuotų šias pozicijas; jas reikia išmatuoti. Variklio vidinė LayoutRichText rutina matuoja kiekvieną seką tais pačiais šriftų matavimais, kurie vėliau ją nupieš, ir tada nustato sekos horizontalų postūmį į bendrą visų ankstesnių sekų pločių sumą. Pirma seka prasideda nuo piešimo laukelio pradžios taško, antra seka prasideda nuo pirmos sekos pločio, trečia seka – nuo pirmų dviejų bendro pločio ir taip toliau per eilutę
Būtent todėl matavimo šrifto lygiavimas yra toks svarbus. Išdėstymo praėjimas matuoja postūmius; atskiras atvaizdavimo praėjimas piešia glifus. Jei šie du praėjimai nesutampa dėl šrifto, laukeliai, kuriuos apskaičiavo maketas, neatsidurs po glifais, kuriuos nupiešė vaizduoklis. HotPDF suderina juos susiedamas kiekvienos sekos galutinį stilių su šrifto specifikacija per vidinį RunStyleToFontSpec pagalbininką, kuris atitinka vaizduoklio „Arial“, 10 punktų, numatytuosius nustatymus. Tuomet išmatuotas postūmis ir nupieštas tekstas sutampa, o sekos apskaičiuotas laukelis tikrai apima simbolius, kuriuos mato skaitytojas
// Conceptual shape of one laid-out run. The engine builds an array of these
// internally; you never construct them yourself, but the fields explain how a
// link's hit box is derived from measured geometry rather than from text.
type
TRichRunInfo = record
Dx, Dy : Double; // top-left, relative to the draw-box origin
W, H : Double; // measured run box (width from the layout pass)
Text : AnsiString; // the run's visible characters
Href : AnsiString; // URI target for an <a> run, '' otherwise
end;
Nuo inkaro sekos iki PDF Link anotacijos
Hipersaitas užbaigtame PDF faile nėra puslapio turinio dalis. Tai atskiras objektas, „Link“ anotacija, aprašyta ISO 32000-1 12.5.6.5 skyriuje. Anotacija turi /Rect, kuris apibrėžia spustelėjamą stačiakampį puslapyje, ir veiksmą, kuris įvyksta spustelėjus stačiakampį. Išorinei nuorodai veiksmas yra URI veiksmas: /S /URI, kurio tikslo adresas yra /URI eilutė. Matomas tekstas po juo yra paprastas puslapio turinys; anotacija yra nematoma aktyvioji zona, uždėta virš jo
Plokštinimo kelias tiksliai seka šiuo modeliu. Kai seka neša Href, HotPDF pirmiausia nupiešia stilizuotą tekstą, tada sukuria „Link“ anotaciją virš sekos laukelio. Viešasis įvesties taškas šiai anotacijai yra puslapio metodas AddURILink, kuris sukuria objektą /Type /Annot /Subtype /Link su /URI veiksmu ir grąžina anotacijos žodyną. Jo stačiakampis yra sekos išmatuotas laukelis, išverstas iš piešimo elemento vietinių koordinačių į puslapio koordinates. Rezultatas yra nuoroda, kuri nukrenta tiksliai ant inkaro teksto ir niekur kitur
// The same public API the flatten path uses for each anchor run. It produces
// an ISO 32000-1 12.5.6.5 Link annotation: /Subtype /Link with a /URI action
// over the given rectangle. The optional description fills /Contents so a
// screen reader can announce the target.
var
LinkRect: TRect;
Annot: THPDFDictionaryObject;
begin
LinkRect := Rect(72, 690, 268, 706); // page-space hit box for the run
Annot := Pdf.CurrentPage.AddURILink(LinkRect,
'https://www.example.gov/appeal', 'File an appeal online');
end;
Kodėl paspaudimo laukelis turi atkeliauti iš išmatuotų pločių
Gundanti mintis įsivaizduoti nuorodos vietą, ieškant puslapyje jos matomo teksto ir brėžiant stačiakampį aplink viską, kas surasta. Tačiau tai neveikia, o to priežastis yra esminė, atsižvelgiant į tai, kaip saugomas suplokštintas tekstas. Stilizuotos sekos piešiamos naudojant įterptus poaibio šriftus. Poaibio šriftas pernumeruoja glifus, kuriuos išlaiko, todėl puslapio turinio sraute saugomi šešioliktainiai CID kodai, o ne originalūs simbolių kodai. Baitai puslapyje nėra tos raidės, kurias skaito žmogus, ir jie neieškomi kaip tekstas. Inkaro antraštės paieška nieko neranda, nes šios antraštės kaip žodinio teksto niekur sraute nėra
Vienintelis patikimas orientyras stačiakampiui yra geometrija, kurią maketo praėjimas jau sukūrė. Kiekvienos sekos postūmis ir išmatuotas plotis buvo apskaičiuoti, kol tekėjo eilutė, prieš pernumeruojant bet kokį glifą, ir apibrėžia, kur tekstas fiziškai pasirodys. Todėl HotPDF nuorodos stačiakampį paima tiesiai iš sekos iškloto laukelio, o ne iš jokios teksto paieškos. Kadangi matuojant naudotas vaizduojamas šriftas, laukelis yra teisingas, neatsižvelgiant į poaibių sudarymą. Geometrija išgyvena kodavimą; tekstas – ne. Tai yra pagrindinis argumentas, kodėl pozicionavimui reikia naudoti išmatuotus pločius, ir būtent todėl plokštinimo įrankis, bandantis retroaktyviai pridėti nuorodas per teksto paiešką, sukuria aktyvias zonas, kurios slankioja arba pradingsta
Plokštinimo valdymas iš jūsų kodo
PDF failui, kuriame jau yra XFA paketas, įvesties taškas yra FlattenLoadedXFA. Įkelkite dokumentą, iškvieskite metodą ir išsaugokite rezultatą. Parametras Editable nusprendžia, kas nutiks formos laukams: perduokite True, kad išlaikytumėte juos kaip pildomus „AcroForm“ valdiklius, arba False, kad visus valdiklius pažymėtumėte kaip tik skaitomus, taip paverčiant išvestį į įšaldytą įrašą. Raiškiojo teksto piešimo blokai su jų stilizuotomis sekomis ir nuorodų anotacijomis generuojami abiem atvejais. Funkcija grąžina valdiklių, kuriuos ji išvedė, skaičių
var
Pdf: THotPDF;
Emitted, i: Integer;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.LoadFromFile('xfa_appeal_form.pdf');
// True keeps fields fillable; False freezes them read-only.
Emitted := Pdf.FlattenLoadedXFA(True);
// Anything the engine could not map is reported, not raised.
for i := 0 to Pdf.XFAFlattenWarnings.Count - 1 do
Writeln('XFA warning: ', Pdf.XFAFlattenWarnings[i]);
Pdf.SaveLoadedDocument('appeal_form_flat.pdf');
Writeln('Widgets emitted: ', Emitted);
finally
Pdf.Free;
end;
end;
Visada po iškvietimo perskaitykite XFAFlattenWarnings. Sąrašas išvalomas kiekvieno plokštinimo pradžioje ir kaupia po eilutę kiekvienam elementui, kurio variklis atsisakė atvaizduoti: nepalaikomas lauko tipas, piešiamas vaizdas, kurio nepavyko iškoduoti, exData blokas be naudingų atkarpų. Nė viena iš šių situacijų nesukelia išimties, todėl tuščias perspėjimų sąrašas yra jūsų įrodymas, kad viskas buvo susieta, o netuščias tiksliai pasako, kokius originalus reikia patikrinti. Jei turite originalų XFA ne kaip įkeltą PDF, o kaip XDP baitus, giminingas metodas ApplyXFAAsAcroForm paima tuos baitus tiesiogiai ir dalijasi tuo pačiu kodo keliu bei tomis pačiomis perspėjimų taisyklėmis. Papildantis metodas AddXFAPacket eina į priešingą pusę – įterpia XFA paketą į kuriamą dokumentą
Rezultato patvirtinimas skaityklėje
Atidarykite suplokštintą failą naudodami Acrobat ar bet kurią šiuolaikinę peržiūros programą ir patikrinkite du dalykus. Pirma, ar raiškusis tekstas išlaikė savo stilių: paryškintos sekos yra paryškintos, spalvotos sekos išlaiko savo spalvą, o atkarpos sėdi eilutėje teisinga tvarka, nesidubliuoja ir neiškrenta iš laukelio. Antra, ar hipersaitai veikia. Užvedus pelės žymeklį ant inkaro, būsenos juostoje turi pasirodyti tikslo adresas; jį spustelėjus, URI veiksmas turėtų jį atidaryti. Naudokite peržiūros programos anotacijų inspektorių ir patikrinkite, ar kiekviena iš jų tikrai yra /Link anotacija, kurios /Rect apgaubia inkaro tekstą ir yra patalpinta ant turinio, kurį dabar sudaro paprasti nupiešti glifai, o ne formoje atvaizduotas XFA. Būtent toks derinys – stilizuotas statinis tekstas plius tikrosios Link anotacijos atitinkamuose stačiakampiuose – užtikrina, kad suplokštintas dokumentas gyvuos ilgiau nei XFA varikliai, kurių jam nebereikia
Pačių laukų – teksto laukelių, žymimųjų langelių ir pasirinkimų sąrašų, supančių šį raiškųjį tekstą, plokštinimas aprašytas mūsų vadove, kaip plokštinti XFA formas į AcroForm valdiklius. Išsamesnė Link anotacijų rankinio kūrimo ir išdėstymo apžvalga (kuri apima ne tik tas, kurias sugeneruoja plokštinimo maršrutas) pateikta straipsnyje PDF anotacijų naudojimas su HotPDF. Abu šie sprendimai remiasi tais pačiais anotacijų ir formų modeliais, kurie pateikiami „Delphi“ ir „C++Builder“ skirtame HotPDF komponente