Technical Article

XFA raiškiojo teksto ir nuorodų užšaldymas su HotPDF

Atidarykite XML formų architektūros (angl. XML Forms Architecture arba XFA) specifikaciją skyriuje apie turinį, ir greitai suprasite, kad interaktyvios formos projektavimas yra labiau susijęs su HTML atvaizdavimu nei su tradiciniu PDF piešimu. XFA laukas laiko savo vertę XML pakete, o kai ta vertė turi būti suformatuota keliais šriftais, spalvomis ar turėti paspaudžiamų nuorodų, XFA naudoja XHTML pogrupį, apgaubtą exData elementu. Taigi, jūsų lauko vertė yra ne tik tekstas. Tai yra eilučių lūžių, pusjuodžio teksto dalių ir nuorodų medis, atrodantis kaip <body><p>Spustelėkite <a href="https://example.com">čia</a></p></body>. Kadaangi modernūs PDF skaitytuvai atsisako XFA palaikymo, atėjo laikas išmokti užšaldyti (angl. flatten) šį raiškųjį tekstą į statinį PDF turinį Delphi programoje, neprarandant pačių nuorodų

Šiame straipsnyje apžvelgiamas XHTML išdėstymo modelis XFA formose, kaip apibrėžta XFA specifikacijos 3.3 skyriuje, ir parodoma, kaip HotPDF paverčia XML medį į statinį PDF turinio srautą su tikromis URI anotacijomis

Didysis atsiskyrimas: AcroForm prieš XFA

Prieš pradedant analizuoti XHTML žymas, svarbu suprasti skirtumą tarp AcroForm (klasikinio PDF formų modelio) ir XFA. AcroForm naudoja statinius puslapius su interaktyviais laukais kaip anotacijas viršuje. XFA atveju pats puslapis dažnai yra dinamiškas, sugeneruotas iš XML šablono ir duomenų paketo vykdymo metu. Tai reiškia, kad kai XFA forma užpildoma ir išsaugoma, ji priklauso nuo peržiūros programos XFA variklio, kuris interpretuoja XML ir atkuria vaizdą kiekvieno atidarymo metu. Kai skaitytuvas neturi šio variklio (kaip yra daugelyje mobiliųjų ir interneto peržiūros programų), vartotojas mato tuščią puslapį arba įspėjimą, prašantį atidaryti failą Acrobat programoje

Užšaldymas išsprendžia šią problemą. Jis nuskaito XML duomenis, suformatuoja tekstą, nupiešia glifus tiesiai puslapio turinio sraute kaip statinius vektorinius kelius ir pašalina interaktyvią formą. Iššūkis su exData laukais yra tas, kad užšaldymas negali būti tiesiog teksto išmetimas; jis turi atkurti šrifto svorius, spalvas ir išlaikyti paspaudžiamas nuorodas kaip tikras PDF nuorodas

XHTML srautas XFA specifikacijoje

XFA specifikacijos 3.3 skyriuje apibrėžiamas XHTML profilis, kurį laukas gali nešti. Tai yra griežtas XHTML pogrupis. Leidžiamos žymos yra <body>, <p>, <span> ir <a>. Stiliaus informacija pateikiama per style atributus, kuriuose palaikomos pagrindinės CSS savybės: font-family, font-size, font-weight, font-style, color ir text-decoration

Analizatorius (angl. parser) turi vaikščioti šiuo medžiu ir palaikyti būsenos krūvą. Kai jis susiduria su <span style="font-weight:bold">, jis pastumia pusjuodį stilių į krūvą, išveda vėlesnį tekstą su pusjuodžiu šriftu ir nuima stilių, kai randa uždarymo žymą. Lūžiai tarp pastraipų (<p>) nustato naujos eilutės koordinates, o <a> žyma neša papildomą atsakomybę – jos href atributas nurodo nuorodos tikslą

// 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;

Nuorodos rėmelio apskaičiavimas

PDF nuoroda yra ne teksto dalis, o stačiakampis aktyviosios srities rėmelis puslapyje, susietas su veiksmu. Tai reiškia, kad kai HotPDF atvaizduoja XHTML tekstą su nuoroda, jis turi išmatuoti kiekvieno glifo plotį nuorodos tekste, apskaičiuoti tikslią vietą puslapyje, kur tas tekstas bus nupieštas, ir aplink jį sukurti /Link anotaciją su /Rect masyvu, kuris tiksliai apgaubia tekstą

Šis matavimas yra jautrus šriftui. Jei šrifto metrika neteisinga, stačiakampis bus per siauras arba per platus, o paspaudžiama sritis nesutaps su tekstu. HotPDF naudoja vidinį teksto matavimo variklį, kad gautų tikslias ribas prieš piešdamas glifus

// 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;

XFA užšaldymo API Delphi programoje

HotPDF suteikia tiesioginį būdą užšaldyti XFA formas per FlattenXFAFields metodą. Šis iškvietimas pereina per visus formos laukus, randa tuos, kurie turi raiškiojo teksto exData reikšmes, išanalizuoja XHTML struktūrą, atkuria ją puslapyje kaip statines žymes ir atitinkamose vietose prideda URI nuorodas

Iškvietimas atrodo paprastai: Pdf.FlattenXFAFields(1), kur vienetas nurodo, kad nuorodos turi būti sugeneruotos iš <a> žymų. Visi XFA laukai yra pakeičiami statinėmis žymėmis, o dinaminis XML paketas ištrinamas iš dokumento katalogo, todėl failas tampa suderinamas su bet kuria peržiūros programa

Įspėjimų skaitymas po užšaldymo

Raiškiojo teksto XML gali turėti elementų ar stilių, kurių PDF negali tiesiogiai atvaizduoti, pavyzdžiui, įdėtų lentelių ar išorinių vaizdų. Tokiais atvejais HotPDF užšaldo tekstą, tačiau sugeneruoja įspėjimus apie praleistus elementus. Geras programuotojas visada patikrina XFAFlattenWarnings po iškvietimo

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 perskaitykite XFAFlattenWarnings po iškvietimo. Šis sąrašas išvalomas kiekvieno užšaldymo pradžioje ir sukaupia po eilutę kiekvienam elementui, kurio variklis atsisakė atvaizduoti: nepalaikomas lauko tipas, piešiamas vaizdas, kuris neišsikoduoja, arba exData blokas be tinkamų segmentų. Nė vienas iš jų nesukelia išimties (angl. exception), todėl tuščias įspėjimų sąrašas yra jūsų įrodymas, kad viskas buvo atvaizduota sėkmingai, o netuščias sąrašas tiksliai nurodo, kuriuos originalus reikia patikrinti. Kai turite neapdorotus XFA duomenis kaip XDP baitus, o ne įkeltą PDF, giminingas metodas ApplyXFAAsAcroForm priima šiuos baitus tiesiogiai ir dalijasi tuo pačiu kodo keliu bei įspėjimų elgsena. Papildomas AddXFAPacket metodas veikia priešinga kryptimi – įterpia XFA paketą į kuriamą dokumentą

Rezultato patvirtinimas peržiūros programoje

Atidarykite užšaldytą failą Acrobat arba bet kurioje kitoje dabartinėje peržiūros programoje ir patikrinkite du dalykus. Pirmiausia, ar raiškusis tekstas buvo atvaizduotas išlaikant stilių: ar pusjuodis tekstas išliko pusjuodis, ar spalvotos dalys išlaikė savo spalvą ir ar teksto segmentai išsidėstė tinkama tvarka eilutėje, užuot persidengę ar išėję už rėmelio ribų. Antra, ar nuorodos yra gyvos. Užveskite pelės žymeklį virš nuorodos ir būsenos juostoje turėtų pasirodyti tikslinis adresas; spustelėkite jį, ir URI veiksmas turėtų jį atidaryti. Naudokite peržiūros programos anotacijų inspektorių, kad įsitikintumėte, jog kiekviena iš jų yra tikra /Link anotacija, kurios /Rect glaudžiai apgaubia nuorodos tekstą, esantį virš turinio, kuris dabar yra tiesiog nupiešti glifai, o ne formos pateiktas XFA. Šis derinys – stilizuotas statinis tekstas plius tikros nuorodų anotacijos teisinguose stačiakampiuose – leidžia užšaldytam dokumentui gyventi ilgiau už XFA variklius, kurių jam nebereikia

Pačių laukų (teksto laukelių, žymimųjų langelių ir pasirinkimo sąrašų, kurie supa šį raiškųjį tekstą) užšaldymas yra aprašytas mūsų apžvalgoje apie XFA formų užšaldymą į AcroForm valdiklius. Norėdami gauti platesnį vaizdą apie nuorodų anotacijų kūrimą ir talpinimą rankiniu būdu (be tų, kurias sugeneruoja užšaldymo kelias), žr. darbą su PDF anotacijomis HotPDF aplinkoje. Abu remiasi tuo pačiu anotacijų ir formų modeliu, kuris tiekiamas kartu su HotPDF komponentu, skirtu Delphi ir C++Builder