Az XFA (XML Forms Architecture) elavult. Az ISO 32000-1 a 12.7. szakaszban tartalmazza azzal a megjegyzéssel, hogy el lett távolítva a PDF 2.0-ból, és a modern megjelenítők egyre-másra dobják ki az XFA motorjaikat. Mindez azonban nem ürítette ki az archívumokat. A kormányzati űrlapok, a biztosítási kérelmek és a banki bizonylatok a jobbik részben két évtizeden át XFA formátumban készültek, és ezek a fájlok még ma is érkeznek a postaládákba és a dokumentum-munkafolyamatokba. Amikor a megjelenítő, amely korábban leképezte őket, leáll, az űrlap üres oldallá válik egy „kérjük, nyissa meg másik olvasóban” helyőrzővel. A tartós megoldás az XFA lapítása (flatten) olyan statikus PDF tartalommá, amelyet bármelyik olvasó ki tud rajzolni.
A lapítás nehéz része nem a mezőknél van. A szövegdobozok és jelölőnégyzetek elég tisztán leképeződnek AcroForm widgetekké. A nehéz rész a formázott szöveg (rich text), amelyet az XFA egy rajzelemben (draw element), egy <exData contentType="text/html"> blokkban tárol. Ez a blokk egy HTML részkészlet beágyazott stílusokkal és gyakran horgonyokkal (anchors). Ennek az oldalra juttatása a formázott szöveg és az élő hiperhivatkozások reprodukálását is jelenti, és a hiperhivatkozások azok, ahol a legtöbb megvalósítás csendben feladja.
Hogyan néz ki valójában az XFA formázott szöveg
Az exData törzse az XHTML egy kis szelete. A bekezdés egy <p>; a formázott karaktersorozat egy <span> saját beágyazott CSS-sel a vastagság, dőlés, szín és méret meghatározására; a hiperhivatkozás pedig egy <a href="...">, amely a látható szövegét csomagolja be. Egyetlen sor több egymás utáni span-t is tartalmazhat, mindegyik eltérő stílussal, és az egyikük lehet egy horgony. A stílus nem dekoráció, amelyet el lehetne hagyni. Egy félkövér pirossal megjelenített záradéknak – mivel az egy jogi figyelmeztetés – félkövérnek és pirosnak kell maradnia a lapítás után is, különben a lapított dokumentum félrevezetően ábrázolná az eredetit.
Így a lapító motor nem kezelheti a blokkot egyetlen karakterláncként. Be kell járnia a beágyazott struktúrát, fel kell oldania az egyes futások (runs) hatásos stílusát úgy, hogy a span beágyazott CSS-ét a rajzelem alap betűtípusára rétegezi, és a futásokat egymás után rendezi el a sorban. A HotPDF ezeket az elrendezett töredékeket belsőleg TXFARichRun rekordként modellezi. A rekord hordozza a futás szövegét, a feloldott stílusát, a mért befoglaló dobozát, és horgony esetén a Href-et, amelyre mutat.
A futások elrendezése balról jobbra
A pozicionálás az, ahol a formázott szöveg már nem elemzési (parsing), hanem szedési (typesetting) problémává válik. A futások osztoznak a soron, így minden futás ott kezdődik, ahol az előző véget ért. Nincs olyan jelölés, amely rögzítené ezeket a pozíciókat; le kell mérni őket. A motor belső LayoutRichText rutinja minden futást ugyanazokkal a betűtípus-metrikákkal mér meg, amelyek később kirajzolják, majd a futás vízszintes eltolását az összes korábbi futásszélesség futó összegére állítja be. Az első futás a rajzdoboz kezdőpontjában kezdődik, a második az első futás szélességénél, a harmadik az első kettő együttes szélességénél, és így tovább a sor mentén.
Ezért számít annyira a mérő betűtípus igazítása. Az elrendezési lépés méri az előrelépéseket (advances); a különálló renderelési lépés rajzolja ki a glifákat. Ha ez a két lépés eltér a betűtípust illetően, az elrendezés által számított dobozok nem a leképező által rajzolt glifák alatt fognak elhelyezkedni. A HotPDF lépésben tartja őket azáltal, hogy a belső RunStyleToFontSpec segédfüggvényen keresztül minden futás feloldott stílusát leképezi egy betűtípus-specifikációra, amely megfelel a leképező saját, 10 pontos Arial alapértelmezésének. A mért előrelépés és a rajzolt szöveg ezután megegyezik, és a futás kiszámított doboza valóban lefedi azokat a karaktereket, amelyeket az olvasó lát.
// 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;
A horgonyfutástól a PDF Link annotációig
A kész PDF-ben lévő hiperhivatkozás nem része az oldaltartalomnak. Ez egy különálló objektum, egy Link annotáció, amelyet az ISO 32000-1 12.5.6.5. szakasza ír le. Az annotáció rendelkezik egy /Rect területtel, amely meghatározza az oldalon kattintható téglalapot, valamint egy művelettel, amely a téglalapra történő kattintáskor fut le. Külső link esetén a művelet egy URI művelet: /S /URI, a céllal mint annak /URI karakterláncával. Alatta a látható szöveg közönséges oldaltartalom; az annotáció a ráhelyezett láthatatlan kattintási zóna (hot zone).
A lapítási útvonal pontosan ezt a modellt követi. Ha egy futás rendelkezik Href értékkel, a HotPDF először megrajzolja a stílusozott szöveget, majd létrehoz egy Link annotációt a futás doboza felett. Az annotáció nyilvános belépési pontja az AddURILink oldalmetódus, amely létrehozza a /Type /Annot /Subtype /Link objektumot egy /URI művelettel, és visszaadja az annotációs szótárat. Téglalapja a futás mért doboza, lefordítva a rajzelem helyi koordinátáiról oldalkoordinátákra. Az eredmény egy olyan link, amely pontosan a horgonyszövegre illeszkedik, és sehol máshol.
// 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;
Miért kell a kattintási doboznak a mért szélességekből származnia
Csábító dolog azt képzelni, hogy a linket úgy határozzuk meg, hogy keresünk az oldalon a látható szövegre, és a téglalapot a megtalált elem köré rajzoljuk. Ez nem működik, és az ok alapvető fontosságú abban, hogyan tárolódik a lapított szöveg. A stílusozott futások beágyazott részhalmaz-betűtípusokkal (embedded subset fonts) vannak megrajzolva. A részhalmaz-betűtípus újraszámozza a megőrzött glifákat, így az oldaltartalom-folyam hexadecimális CID kódokat tartalmaz, nem pedig az eredeti karakterkódokat. Az oldalon lévő bájtok nem azok a betűk, amelyeket az ember olvas, és nem kereshetők szövegként. A horgony feliratának keresése nem talál semmit, mert az a felirat nem létezik szó szerinti szövegként sehol az adatfolyamban.
A téglalap egyetlen megbízható horgonya a geometria, amelyet az elrendezési menet már előállított. Az egyes futások eltolását és mért szélességét a sor tördelésekor számítottuk ki, még azelőtt, hogy a glifák újra lettek volna számozva, és ezek írják le, hol fog a szöveg fizikailag megjelenni. A HotPDF ezért a link téglalapját közvetlenül a futás elhelyezett dobozából veszi, nem pedig bármilyen szöveges keresésből. Mivel a mérés a renderelő betűtípust használta, a doboz helyes a részhalmaz-képzéstől függetlenül. A geometria túléli a kódolást; a szöveg nem. Ez a teljes érvelés a mért szélességen alapuló pozicionálás mellett, és ez az oka annak, hogy az olyan lapító, amely szövegkereséssel próbálja meg utólag elhelyezni a linkeket, eltolódott vagy eltűnő kattintási zónákat eredményez.
A lapítás vezérlése a kódból
Olyan PDF esetén, amely már tartalmaz XFA csomagot, a belépési pont a FlattenLoadedXFA. Töltse be a dokumentumot, hívja meg a metódust, és mentse az eredményt. Az Editable paraméter dönti el, mi történjen az űrlapmezőkkel: a True értékkel megtarthatja őket kitölthető AcroForm widgetekként, a False értékkel pedig minden widgetet csak olvashatóra állíthat be, így a kimenet egy rögzített rekord lesz. A formázott szövegű rajzblokkok a stílusozott futásaikkal és link annotációikkal mindkét esetben elkészülnek. A függvény a kibocsátott widgetek számát adja vissza.
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;
A hívás után mindig olvassa be az XFAFlattenWarnings listát. A lista minden lapítás kezdetén kiürül, és sort gyűjt minden olyan elemről, amelyet a motor nem volt hajlandó leképezni: nem támogatott mezőtípus, nem dekódolható rajzolt kép, vagy használható span-ek nélküli exData blokk. Ezek egyike sem emel kivételt, így az üres figyelmeztetések listája bizonyítja, hogy minden leképeződött, a nem üres pedig pontosan megmutatja, mely eredetiket kell ellenőrizni. Ha a nyers XFA-t XDP bájtként kezeli a betöltött PDF helyett, a testvér ApplyXFAAsAcroForm metódus közvetlenül fogadja ezeket a bájtokat, és osztozik ugyanazon a kódútvonalon és figyelmeztetési viselkedésen. A kiegészítő AddXFAPacket metódus a másik irányba működik, beágyazva egy XFA csomagot az éppen épített dokumentumba.
Az eredmény ellenőrzése olvasóban
Nyissa meg a lapított fájlt az Acrobatban vagy bármely jelenlegi megjelenítőben, és ellenőrizzen két dolgot. Először is, hogy a formázott szöveg a stílusával együtt leképeződött-e: a félkövér részek félkövérek, a színesek hordozzák a színüket, és a span-ek a megfelelő sorrendben ülnek a sorban ahelyett, hogy átfednék egymást vagy kifutnának a dobozból. Másodszor, hogy a hiperhivatkozások élnek-e. Vigye az egeret egy horgony fölé, és az állapotsornak mutatnia kell a címet; kattintson rá, és az URI műveletnek meg kell nyitnia azt. Használja a megjelenítő annotáció-vizsgálóját annak megerősítésére, hogy mindegyik egy valódi /Link annotáció, amelynek /Rect területe körbeöleli a horgonyszöveget, olyan tartalom felett ülve, amely most már egyszerűen kirajzolt glifákból áll az űrlap által renderelt XFA helyett. A stílusozott statikus szöveg és a valódi téglalapokon elhelyezkedő Link annotációk kombinációja teszi lehetővé, hogy a lapított dokumentum túlélje a már szükségtelenné vált XFA motorokat.
Maguknak a mezőknek – a formázott szöveget körülvevő szövegdobozoknak, jelölőnégyzeteknek és választólistáknak – a lapítását az XFA űrlapok AcroForm widgetekké való lapításáról szóló útmutatónk tárgyalja. A Link annotációk kézzel történő felépítésének és elhelyezésének tágabb történetéhez – a lapítási útvonal által generáltakon túl – lásd a PDF annotációk kezelése a HotPDF-ben cikket. Mindkettő ugyanarra az annotációs és űrlapmodellre épül, amely a Delphi és C++Builder platformokhoz készült HotPDF Component csomaggal együtt érhető el.