PDF ne poznaje koncept varijabilnog fonta. Font ugrađen u PDF datoteku fiksni je skup obrisa s fiksnim metrikama, pa varijabilni font mora biti sveden na jednu statičnu instancu prije nego što uđe u dokument. HotPDF to instanciranje obavlja interno: pregledavate osi varijabilnog fonta, birate koordinate poput debljine 620 ili širine 87,5, a knjižnica te vrijednosti ugrađuje u potpuni, samostalni font program koji svaki usklađeni PDF čitač može prikazati
Razlog zašto je ovo važno praktičan je, a ne teoretski. Ljevaonice slova sve češće isporučuju jednu varijabilnu datoteku umjesto desetak statičnih debljina, a dizajnerski timovi biraju vrijednosti koje ne pruža nijedna imenovana instanca. Bez instanciranja generator izvještaja ili se vraća na zadanu instancu, čime se odbacuje dizajnerska odluka, ili ugrađuje cijeli varijabilni font i nada se da će preglednik poštovati koordinate osi za koje nema način da zna, a to nijedan čitač nije obvezan činiti
Što instanciranje zapravo mora ponovno izgraditi?
OpenType varijabilni font pohranjuje jedan zadani obris po glifu plus skup delta vrijednosti indeksiranih prema poziciji u dizajnerskom prostoru. Primjena koordinate osi nije samo upisivanje broja u zaglavlje; to znači prolazak kroz tablicu gvar, interpolaciju delta vrijednosti za traženu poziciju, pomicanje točaka i zatim ponovno izračunavanje svega što je izvedeno iz tih točaka. HotPDF ponovno gradi obrise glifova, dugu tablicu loca, potpune vodoravne i okomite metrike, globalni okvir omeđivanja fonta i prilagodbu sfnt kontrolne sume
Jednako je važno i što se uklanja. Statična instanca ne smije zadržati fvar, avar, gvar, HVAR, VVAR, MVAR, STAT ili cvar, a zastarjeli DSIG također mora otići, budući da potpisani bajtovi više ne postoje. Ako se bilo što od toga zadrži, dobiva se font koji tvrdi da je varijabilan, a nosi obrise koji su već pomaknuti, pa će ga čitači koji doista primjenjuju varijacije primijeniti drugi put
Fantomske točke i zamka dvostruke primjene
Najsuptilnije pravilo u cijelom postupku odnosi se na metrike. U gvar-u broj točaka za glif obuhvaća točke obrisa, odnosno točke komponenti za složeni glif, plus četiri fantomske točke koje kodiraju lijevi bočni razmak, širinu pomaka i njihove okomite ekvivalente. Same te fantomske točke također podliježu delta vrijednostima
Stoga, kada font ima tablicu gvar, HotPDF izvodi vodoravne i okomite metrike iz interpoliranih fantomskih točaka i dodatno ne primjenjuje HVAR ni VVAR. Primjena oboje klasična je pogreška: ista varijacija primijeni se dvaput i svaka širina pomaka ispadne malo preširoka, što se očituje kao tekst koji postupno klizi udesno duž poravnatog retka. Tek kada font nema gvar, knjižnica ugrađuje spremište varijacije metrike izravno u hmtx ili vmtx
Još dva detalja čuvaju točnost geometrije. Fantomske točke nikada ne sudjeluju u interpolaciji kontura, pa se točke koje nisu izričito navedene za jednostavan glif zaključuju pomoću IUP-a po konturi, uz isključenje fantomskih točaka. Složeni glifovi dobivaju svoje delta vrijednosti primijenjene na pomake komponenti koji koriste XY parametre, nakon čega se granice podređenih elemenata ponovno izračunavaju rekurzivno. Ta je rekurzija ograničena dubinom i provjerava se na cikluse, jer bi zlonamjeran ili tek pokvaren graf komponenti inače mogao rekurzivno teći bez kraja
Pregled dizajnerskog prostora prije odabira
Prvi poziv u svakom tijeku rada instanciranja je InspectVariableFont, koji vraća osi i imenovane instance koje je ljevaonica definirala. Zapisi osi nose oznaku od četiri bajta, minimalnu, zadanu i maksimalnu vrijednost, zastavice i ID naziva; imenovane instance nose ID naziva podobitelji, zastavice, neobavezni ID PostScript naziva i jednu koordinatu po osi:
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;
Izvještavanje o rasponu osi važno je jer se vrijednosti osi ograničavaju na raspon koji font deklarira, a ne na raspon koji nudi vaše sučelje. Klizač koji korisniku dopušta zatražiti debljinu 1000 na fontu čija os wght staje na 900 treba ispraviti u sučelju, a ne tiho na razini fonta, jer će se u suprotnom ispisani izlaz razlikovati od pretpregleda
Odabir koordinata i generiranje dokumenta
Odabir osi ima stanje i primjenjuje se na fontove registrirane nakon toga. SetVariableFontAxis prima oznaku od četiri bajta ispisivih ASCII znakova i konačnu vrijednost, a sve ostalo odbacuje iznimkom umjesto da to tiho ignorira. ClearVariableFontAxes resetira odabir, a GetVariableFontAxisSelections izvještava što je trenutno na čekanju, što se isplati bilježiti u strojevima za izvještaje gdje je nekoliko putova koda moglo dotaknuti isti objekt dokumenta. Sama obitelj fontova bira se po imenu putem SetFont, potpuno jednako kao i svako drugo ugrađeno TrueType pismo:
begin
Pdf := THotPDF.Create(nil);
try
Pdf.BeginDoc;
Pdf.SetVariableFontAxis('wght', 620); // polumasno, nije imenovana instanca
Pdf.SetVariableFontAxis('wdth', 87.5); // blago suženo
Pdf.CurrentPage.SetFont('Inter', [], 11);
Pdf.CurrentPage.TextOut(72, 720, 0, 'Quarterly results');
Pdf.ClearVariableFontAxes; // povratak na zadanu instancu
Pdf.CurrentPage.SetFont('Inter', [], 10);
Pdf.CurrentPage.TextOut(72, 700, 0, 'Prepared by the finance team');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Događaj OnVariableFontInstance okida se pri stvaranju svake instance i izvještava o korištenim vrijednostima osi, što je najjeftiniji način da se u zapisniku dokaže što određeni PDF zapravo sadrži. Budući da svaki različit skup koordinata daje drugačiji font program, tretirajte odabire osi kao dio ključa predmemorije fontova; mehanika predmemoriranja opisana je u trajnoj predmemoriji podskupova fontova
Kako se instanciranje isprepliće s podskupljivanjem i oblikovanjem
Instanciranje se izvodi prije podskupljivanja, i taj je redoslijed ispravan. Instancirani font je obično statično TrueType pismo, pa ga uobičajeni alat za podskupljivanje tretira kao svako drugo: izračunava zatvaranje glifova, zadržava glifove koje dokument stvarno koristi i odbacuje ostale. Interakcija koju treba imati na umu jest da su dva različita odabira osi iste obitelji dva različita font programa, pa dokument koji miješa debljinu 400 i debljinu 620 ugrađuje dva podskupa, a ne jedno dijeljeno pismo s dvije instance
Oblikovanje u načelu nije pogođeno, ali se u praksi isplati provjeriti. Značajke rasporeda žive u GSUB-u i GPOS-u, koje instanciranje čuva, pa ligature i stilske alternative i dalje rade kako je opisano u OpenType GSUB stilskim alternativama. Ono što se mijenja jest pozicioniranje: sužena instanca ima uže pomake od zadane, pa je svaki raspored koji je mjerio tekst prije instanciranja mjerio pogrešne širine. Mjerite s istim odabirom osi s kojim ćete renderirati, i razlika nestaje
Posljednja obrambena napomena iz implementacije, korisna svima koji proširuju ovaj put. Fontovi bez okomitih metrika ipak procjenjuju argumente dinamičkih polja na mjestu poziva u Delphiju, pa se polja u trenutku raščlambe uvijek alociraju umjesto oslanjanja na provjeru HasVerticalMetrics koja bi preskočila prazan indeks. To je vrsta detalja na razini jezika koji naizgled zaštićenu granu pretvara u kršenje pristupa memoriji upravo na fontovima koje niste testirali
Podrška za varijabilne fontove uklapa se u isti font pipeline kao ugrađivanje, podskupljivanje i zatvaranje glifova, što je detaljnije opisano u zatvaranju podskupa fontova i oblikovanim glifovima. Cjelokupni skup tipografskih značajki za Delphi i C++Builder naveden je na stranici HotPDF Delphi PDF komponente