PDF har intet begreb om en variabel skrifttype. En skrifttype indlejret i en PDF-fil er et fast sæt konturer med faste metrics, så en variabel skrifttype skal reduceres til én statisk instans, før den kan indgå i et dokument. HotPDF udfører denne instansiering internt: man inspicerer akserne i en variabel skrifttype, vælger koordinater såsom vægt 620 eller bredde 87,5, og biblioteket bager disse værdier ind i et komplet, selvstændigt skrifttypeprogram, som enhver konform PDF-læser kan gengive
Grunden til, at dette har betydning, er praktisk snarere end teoretisk. Skrifttypeforlag leverer i stigende grad én variabel fil i stedet for et dusin statiske vægte, og designteams vælger værdier, som ingen navngivet instans tilbyder. Uden instansiering falder en rapportgenerator enten tilbage til standardinstansen, hvilket kasserer designbeslutningen, eller indlejrer hele den variable skrifttype og håber, at læseren respekterer akse-koordinater, den ingen mulighed har for at kende, hvilket ingen læser er forpligtet til
Hvad skal instansiering egentlig genopbygge?
En OpenType-variabel skrifttype gemmer én standardkontur pr. glyf plus et sæt deltaer indekseret efter position i designrummet. At anvende en akse-koordinat handler ikke om at skrive et tal ind i et header; det betyder at gennemgå gvar-tabellen, interpolere deltaer for den ønskede placering, flytte punkter og derefter genberegne alt, hvad der var udledt af disse punkter. HotPDF genopbygger glyfkonturerne, den lange loca-tabel, de komplette vandrette og lodrette metrics, skrifttypens globale afgrænsningsboks og sfnt-tjeksumjusteringen
Lige så vigtigt er, hvad der fjernes. En statisk instans må ikke beholde fvar, avar, gvar, HVAR, VVAR, MVAR, STAT eller cvar, og en forældet DSIG skal også fjernes, da de signerede bytes ikke længere findes. At lade nogen af disse blive tilbage giver en skrifttype, der hævder at være variabel, mens den bærer konturer, der allerede er blevet flyttet, og læsere, der rent faktisk anvender variationer, vil så anvende dem en anden gang
Phantom points, og fælden med dobbeltanvendelse
Den mest subtile regel i hele processen vedrører metrics. I gvar dækker punktantallet for en glyf konturpunkterne, eller komponentpunkterne for en sammensat glyf, plus fire phantom points, der koder venstre sidebredde, forskydningsbredden og deres lodrette modstykker. Disse phantom points er selv underlagt deltaer
Så når en skrifttype har en gvar-tabel, udleder HotPDF vandrette og lodrette metrics fra de interpolerede phantom points og anvender ikke desuden HVAR eller VVAR. At lægge begge til er den klassiske fejl: den samme variation bliver anvendt to gange, og hver forskydningsbredde ender med at være en anelse for bred, hvilket viser sig som tekst, der gradvist driver mod højre hen over en lige margen. Kun når en skrifttype ikke har nogen gvar, bager biblioteket metric-variationslageret direkte ind i hmtx eller vmtx
To yderligere detaljer holder geometrien ærlig. Phantom points deltager aldrig i konturinterpolation, så punkter, der ikke er eksplicit angivet for en simpel glyf, udledes med IUP pr. kontur, hvor phantom points er udelukket. Og sammensatte glyffer får deres deltaer anvendt på komponentforskydninger, der bruger XY-parametre, hvorefter underordnede grænser genberegnes rekursivt. Denne rekursion er begrænset i dybde og cyklustjekket, fordi en fjendtlig eller blot fejlbehæftet komponentgraf ellers kan rekursere uden ende
Inspektion af designrummet, før man vælger
Det første kald i enhver instansieringsworkflow er InspectVariableFont, som rapporterer akserne og de navngivne instanser, forlaget definerede. Akseposter bærer fire-byte-tagget, minimums-, standard- og maksimumsværdierne, flag og et navne-ID; navngivne instanser bærer et underfamilie-navne-ID, flag, et valgfrit PostScript-navne-ID og én koordinat pr. akse:
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;
At rapportere akseintervallet betyder noget, fordi akseværdier klemmes fast til det interval, skrifttypen deklarerer, ikke til det interval, din brugerflade tilbyder. En skyder, der lader en bruger anmode om vægt 1000 på en skrifttype, hvis wght-akse stopper ved 900, bør korrigeres i grænsefladen, ikke stiltiende på skrifttypelaget, ellers vil det udskrevne output være i uoverensstemmelse med forhåndsvisningen
Valg af koordinater og udskrivning af dokumentet
Aksevalg er tilstandsbehæftet og gælder for skrifttyper, der registreres efterfølgende. SetVariableFontAxis tager et fire-byte printbart ASCII-tag og en endelig værdi og afviser alt andet med en undtagelse frem for stiltiende at ignorere det. ClearVariableFontAxes nulstiller valget, og GetVariableFontAxisSelections rapporterer, hvad der aktuelt er ventende, hvilket er værd at logge i rapportmotorer, hvor flere kodestier kan have rørt ved det samme dokumentobjekt. Selve familien vælges ved navn via SetFont, nøjagtigt som enhver anden indlejret TrueType-skrifttype ville blive:
begin
Pdf := THotPDF.Create(nil);
try
Pdf.BeginDoc;
Pdf.SetVariableFontAxis('wght', 620); // semibold, ikke en navngivet instans
Pdf.SetVariableFontAxis('wdth', 87.5); // let kondenseret
Pdf.CurrentPage.SetFont('Inter', [], 11);
Pdf.CurrentPage.TextOut(72, 720, 0, 'Quarterly results');
Pdf.ClearVariableFontAxes; // tilbage til standardinstansen
Pdf.CurrentPage.SetFont('Inter', [], 10);
Pdf.CurrentPage.TextOut(72, 700, 0, 'Prepared by the finance team');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Hændelsen OnVariableFontInstance udløses, efterhånden som hver instans produceres, og rapporterer de akseværdier, der blev brugt, hvilket er den billigste måde at bevise i en log, hvad en given PDF rent faktisk indeholder. Fordi hvert distinkt koordinatsæt giver et distinkt skrifttypeprogram, bør aksevalg behandles som en del af din skrifttype-cachenøgle; cache-mekanikken er beskrevet i den persistente skrifttype-subset-cache
Hvordan instansiering samspiller med subsetting og formgivning
Instansiering kører før subsetting, og den rækkefølge er den rigtige. Den instansierede skrifttype er en normal statisk TrueType-skrifttype, så den almindelige subsetter behandler den som enhver anden: den beregner glyf-closure, beholder de glyffer, dokumentet rent faktisk bruger, og dropper resten. Det samspil, man skal være opmærksom på, er, at to forskellige aksevalg af samme familie er to forskellige skrifttypeprogrammer, så et dokument, der blander vægt 400 og vægt 620, indlejrer to subsets, ikke én delt skrifttype med to instanser
Formgivning er i princippet upåvirket og værd at kontrollere i praksis. Layoutfunktioner findes i GSUB og GPOS, som instansiering bevarer, så ligaturer og stilistiske alternativer fortsætter med at virke som beskrevet i OpenType GSUB stilistiske alternativer. Det, der ændrer sig, er positionering: en kondenseret instans har smallere forskydninger end standarden, så ethvert layout, der målte tekst før instansiering, målte de forkerte bredder. Mål med det samme aksevalg, du vil gengive med, og uoverensstemmelsen forsvinder
En sidste defensiv bemærkning fra implementeringen, nyttig for enhver, der udvider denne sti. Skrifttyper uden lodrette metrics evaluerer stadig dynamiske array-argumenter ved Delphi-kaldsstedet, så parse-time-arrays altid allokeres frem for at stole på et HasVerticalMetrics-tjek til at kortslutte forbi et tomt indeks. Det er den slags sprogniveau-detalje, der forvandler en tilsyneladende beskyttet forgrening til en adgangskrænkelse på netop de skrifttyper, man ikke testede med
Understøttelse af variable skrifttyper indgår i den samme skrifttype-pipeline som indlejring, subsetting og glyf-closure, hvilket er beskrevet mere dybdegående i skrifttype-subset-closure og formgivne glyffer. Det fulde typografifunktionssæt til Delphi og C++Builder er angivet på HotPDF Delphi PDF-komponentsiden