PDF nepozná koncept variabilného písma. Písmo vložené do súboru PDF je pevná sada obrysov s pevnými metrikami, takže variabilné písmo musí byť pred vložením do dokumentu zredukované na jednu statickú inštanciu. HotPDF toto inštancovanie vykonáva interne: preskúmate osi variabilného písma, zvolíte súradnice, napríklad hrúbku 620 alebo šírku 87,5, a knižnica tieto hodnoty zapečie do kompletného, samostatného programu písma, ktorý dokáže vykresliť ktorýkoľvek štandardu vyhovujúci prehliadač PDF
Dôvod, prečo na tom záleží, je praktický, nie teoretický. Písmolejne čoraz častejšie dodávajú jeden variabilný súbor namiesto tuctu statických hrúbok a dizajnérske tímy volia hodnoty, ktoré neposkytuje žiadna pomenovaná inštancia. Bez inštancovania sa generátor zostáv buď vráti k predvolenej inštancii, čím zahodí dizajnérske rozhodnutie, alebo vloží celé variabilné písmo a spolieha sa, že prehliadač rešpektuje súradnice osí, o ktorých nemá ako vedieť, čo od neho žiadny prehliadač nemusí robiť
Čo musí inštancovanie v skutočnosti prestavať?
Variabilné písmo OpenType ukladá jeden predvolený obrys na glyf plus sadu delt indexovaných podľa pozície v návrhovom priestore. Aplikovanie súradnice osi neznamená len zapísať číslo do hlavičky; znamená to prejsť tabuľku gvar, interpolovať delty pre požadovanú polohu, presunúť body a následne prepočítať všetko, čo bolo z týchto bodov odvodené. HotPDF prestavuje obrysy glyfov, dlhú tabuľku loca, kompletné horizontálne a vertikálne metriky, globálny ohraničujúci rámec písma aj úpravu kontrolného súčtu sfnt
Rovnako dôležité je, čo sa odstráni. Statická inštancia si nesmie ponechať fvar, avar, gvar, HVAR, VVAR, MVAR, STAT ani cvar, a musí zmiznúť aj zastaraný DSIG, pretože podpísané bajty už neexistujú. Ponechanie čohokoľvek z toho vytvorí písmo, ktoré sa tvári ako variabilné, no nesie obrysy, ktoré už boli presunuté, a prehliadače, ktoré variácie skutočne aplikujú, ich potom aplikujú druhýkrát
Fantómové body a pasca dvojitej aplikácie
Najjemnejšie pravidlo v celom procese sa týka metrík. V gvar počet bodov glyfu zahŕňa body obrysu, prípadne body komponentov pri zloženom glyfe, plus štyri fantómové body, ktoré kódujú ľavú stranu odsadenia, šírku posunu a ich vertikálne ekvivalenty. Aj tieto fantómové body podliehajú deltám
Keď má teda písmo tabuľku gvar, HotPDF odvodí horizontálne a vertikálne metriky z interpolovaných fantómových bodov a naviac neaplikuje HVAR ani VVAR. Pridanie oboch je klasická chyba: rovnaká variácia sa aplikuje dvakrát a každá šírka posunu vyjde mierne väčšia, čo sa prejaví ako text, ktorý sa postupne posúva doprava naprieč zarovnaným riadkom. Iba keď písmo nemá gvar, knižnica zapečie úložisko variácií metrík priamo do hmtx alebo vmtx
Ďalšie dva detaily udržujú geometriu presnú. Fantómové body sa nikdy nezúčastňujú interpolácie obrysu, takže body, ktoré nie sú pre jednoduchý glyf explicitne uvedené, sa odvodzujú pomocou IUP pre každý obrys, pričom fantómové body sú vylúčené. A zložené glyfy majú svoje delty aplikované na posuny komponentov, ktoré používajú parametre XY, po čom sa hranice potomkov rekurzívne prepočítajú. Táto rekurzia má obmedzenú hĺbku a kontrolu cyklov, pretože inak by sa mohol nekonečne rekurzívne prechádzať škodlivý alebo jednoducho poškodený graf komponentov
Preskúmanie návrhového priestoru pred výberom
Prvým volaním v každom pracovnom postupe inštancovania je InspectVariableFont, ktoré vypíše osi a pomenované inštancie definované písmolejňou. Záznamy osí obsahujú štvorbajtovú značku, minimálnu, predvolenú a maximálnu hodnotu, príznaky a ID názvu; pomenované inštancie obsahujú ID názvu podrodiny, príznaky, voliteľné ID názvu PostScript a jednu súradnicu na os:
var
Pdf: THotPDF;
Axes: THPDFVariableFontAxisArray;
Instances: THPDFVariableFontNamedInstanceArray;
I: Integer;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.InspectVariableFont('C:\Fonts\Inter.ttf', Axes, Instances) then
begin
for I := 0 to High(Axes) do
Writeln(Format('%s min=%.1f default=%.1f max=%.1f',
[string(Axes[I].Tag), Axes[I].MinimumValue,
Axes[I].DefaultValue, Axes[I].MaximumValue]));
Writeln(Format('%d named instance(s) defined', [Length(Instances)]));
end
else
Writeln('not a variable font - embed it as an ordinary TrueType face');
finally
Pdf.Free;
end;
end;
Na vypísaní rozsahu osi záleží, pretože hodnoty osí sa orezávajú na rozsah deklarovaný písmom, nie na rozsah, ktorý ponúka vaše používateľské rozhranie. Posuvník, ktorý používateľovi umožní požadovať hrúbku 1000 pri písme, ktorého os wght končí na 900, by sa mal opraviť v rozhraní, nie potichu na úrovni písma, inak sa tlačený výstup nebude zhodovať s náhľadom
Výber súradníc a vygenerovanie dokumentu
Výber osí je stavový a vzťahuje sa na písma zaregistrované následne. SetVariableFontAxis prijíma štvorbajtovú tlačiteľnú ASCII značku a konečnú hodnotu a čokoľvek iné odmietne výnimkou namiesto tichého ignorovania. ClearVariableFontAxes resetuje výber a GetVariableFontAxisSelections vypíše, čo je aktuálne nastavené, čo sa oplatí logovať v generátoroch zostáv, kde sa toho istého objektu dokumentu môže dotknúť viacero vetiev kódu. Samotná rodina sa vyberá podľa názvu cez SetFont, presne tak, ako by sa vybral akýkoľvek iný vložený rez TrueType:
begin
Pdf := THotPDF.Create(nil);
try
Pdf.BeginDoc;
Pdf.SetVariableFontAxis('wght', 620); // polotučné, nie pomenovaná inštancia
Pdf.SetVariableFontAxis('wdth', 87.5); // mierne zúžené
Pdf.CurrentPage.SetFont('Inter', [], 11);
Pdf.CurrentPage.TextOut(72, 720, 0, 'Quarterly results');
Pdf.ClearVariableFontAxes; // späť na predvolenú inštanciu
Pdf.CurrentPage.SetFont('Inter', [], 10);
Pdf.CurrentPage.TextOut(72, 700, 0, 'Prepared by the finance team');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Udalosť OnVariableFontInstance sa spustí pri vytvorení každej inštancie a hlási hodnoty osí, ktoré boli použité, čo je najlacnejší spôsob, ako v logu doložiť, čo daný PDF skutočne obsahuje. Keďže každá odlišná sada súradníc vytvára odlišný program písma, považujte výber osí za súčasť kľúča vášho cache písiem; mechanika cachovania je opísaná v časti perzistentná cache podmnožín písiem
Ako inštancovanie ovplyvňuje podmnožiny a tvarovanie
Inštancovanie prebieha pred tvorbou podmnožiny a toto poradie je správne. Inštancované písmo je bežný statický rez TrueType, takže ho obyčajný nástroj na tvorbu podmnožín spracuje ako ktorékoľvek iné: vypočíta uzáver glyfov, ponechá glyfy, ktoré dokument skutočne používa, a zvyšok zahodí. Interakcia, na ktorú treba dávať pozor, je, že dva rôzne výbery osí tej istej rodiny sú dva rôzne programy písma, takže dokument, ktorý kombinuje hrúbku 400 a hrúbku 620, vloží dve podmnožiny, nie jeden zdieľaný rez s dvoma inštanciami
Tvarovanie nie je v princípe ovplyvnené, no v praxi sa oplatí overiť. Rozvrhové funkcie žijú v GSUB a GPOS, ktoré inštancovanie zachováva, takže ligatúry a štylistické alternatívy naďalej fungujú tak, ako opisuje časť štylistické alternatívy OpenType GSUB. Mení sa polohovanie: zúžená inštancia má užšie posuny než predvolená, takže akékoľvek rozloženie, ktoré merá text pred inštancovaním, meralo nesprávne šírky. Merajte s rovnakým výberom osí, s akým budete vykresľovať, a nezrovnalosť zmizne
Posledná ochranná poznámka z implementácie, užitočná pre každého, kto tento smer rozširuje. Písma bez vertikálnych metrík aj tak vyhodnocujú argumenty dynamických polí na mieste volania v Delphi, takže polia v čase parsovania sa vždy alokujú namiesto spoliehania sa na kontrolu HasVerticalMetrics, ktorá by mala preskočiť prázdny index. Ide o typ detailu na úrovni jazyka, ktorý zdanlivo ošetrenú vetvu premení na access violation práve pri písmach, s ktorými ste netestovali
Podpora variabilných písiem zapadá do rovnakej pipeline pre písma ako vkladanie, tvorba podmnožín a uzáver glyfov, čo podrobnejšie opisuje časť uzáver podmnožiny písma a tvarované glyfy. Kompletná sada typografických funkcií pre Delphi a C++Builder je uvedená na stránke HotPDF Delphi PDF component