PDF Library for Delphi accepterar de typsnitt ett webbprojekt redan levererar. Den importerar WOFF2-behållare, räknar upp ett variabelt typsnitts designaxlar som JSON, och instansierar en vald uppsättning axelkoordinater till ett statiskt typsnitt som de vanliga vägarna för inbäddning, delmängdsbildning och extraktion hanterar utan att veta något om variationer. Både TrueType-konturer och CFF2-konturer täcks
Situationen detta adresserar är vanlig och irriterande. Ett varumärkes typografi definieras i ett designsystem, designsystemet levererar variabla WOFF2-filer, och PDF-generatorn kan varken läsa behållaren eller variationsdatan. Den vanliga lösningen — att be typsnittsgjuteriet om statiska TTF-instanser av varje vikt som faktiskt används — tar veckor och producerar filer ingen håller synkroniserade
Varför är WOFF2 inte bara ett komprimerat typsnitt?
Att behandla WOFF2 som ett Brotli-omslag och packa upp det ger dig byte som inte är en giltig sfnt. Formatet tillåter också transformerade och omordnade tabeller: glyf, loca och hmtx kan lagras i en omarrangerad form som måste återställas innan typsnittet går att tolka. En generell uppackare klarar inte det
På Windows har plattformen tillhandahållit behållaranalys och uppackning sedan Windows 10 version 1703, så biblioteket använder systemimplementationen snarare än att leverera ytterligare en avkodare. Det beslutet håller driftsättningen fri från en extra DLL och innebär att transformåterställningen hanteras av samma kod operativsystemets egen textstack använder. På andra plattformar går WOFF1 fortfarande en ren Pascal-väg och WOFF2 rapporterar uttryckligen som ej stött, vilket är ett ärligt svar snarare än ett tyst korrumperat typsnitt
Importvägen validerar både innan den avkodar och efteråt: det 48-byte stora huvudet, behållarlängden, de reserverade fälten, den deklarerade sfnt-storleken och ett 512 MiB-tak kontrolleras alla först, och den avkodade strömstorleken jämförs mot deklarationen efteråt. Ett webbtypsnitt är nedladdat innehåll, och de två felläge värda att blockera är en storleksavvikelse och en uppackningsbomb
uses
PDFlibrary;
var
Lib: TPDFlib;
FontID, InstanceID: Integer;
AxesJSON: WideString;
begin
Lib := TPDFlib.Create;
try
Lib.NewDocument;
Lib.SetPageSize('A4');
Lib.NewPage;
// WOFF2, WOFF1, TTF, OTF och TTC går alla in via samma anrop
FontID := Lib.AddOpenTypeFontFromFile('Inter.woff2', 0);
if FontID <= 0 then
raise Exception.Create('font could not be imported');
// Vad kan det här typsnittet faktiskt göra?
if Lib.GetFontVariationAxes(FontID, AxesJSON) = 1 then
Log(AxesJSON); // taggar, minimum, standard, maximum per axel
// Bränn in en designposition till ett statiskt typsnitt
InstanceID := Lib.CreateOpenTypeFontVariation(FontID,
'wght=620,wdth=87.5');
Lib.DrawOpenTypeText(56, 760, InstanceID, 24, 'Quarterly results', 0);
Lib.SaveToFile('report.pdf');
finally
Lib.Free;
end;
end;
Vad instansiering måste bygga om, och vad den tar bort
Ett variabelt typsnitt lagrar en standardkontur per glyf plus deltan indexerade efter position i designrymden. Att producera en statisk instans innebär att interpolera dessa deltan vid de begärda koordinaterna, flytta punkterna, och sedan omberäkna allt som härletts från dem
För TrueType-konturer betyder det att parsa fvar, avar, gvar, HVAR och MVAR, tillämpa tupeldeltan med delad och privat punktnumrering, och interpolera de punkter som inte bär något explicit delta. Horisontella fantompunkter tillsammans med HVAR avgör förskjutningsbredd och vänster sidoavstånd. Sammansatta glyfer behöver få sina komponentberoenden och punktmappningar upplösta först, sedan tillämpas translation, skala, matris och fästpunktsoffset — med djupgränser och cykeldetektering, eftersom en illvillig komponentgraf annars skulle rekursera utan slut
Metadata flyttas också, och det är delen de flesta implementationer hoppar över. MVAR uppdaterar de globala metrikerna i hhea, OS/2 och post, så radavstånd, understrykningsposition och kursivvinkel matchar instansen snarare än standardvärdet. Axlarna wght, wdth, ital och slnt uppdaterar dessutom viktklassen, breddklassen, urvalsflaggorna, macStyle och kursivvinkeln, så ett verktyg som inspekterar det statiska typsnittet rapporterar den stil du bad om. Ett typsnitt vars geometri är fet och vars metadata säger normal kommer att felmärkas överallt nedströms
Utdatan plattar sedan till sammansatta konturer och tar bort de tabeller som inte längre gäller: variationstabellerna, hintar, enhetstabeller och eventuell signatur. Glyfgränser, hhea-sammanfattningsmetriker, maxp-hinttaken, tabellvisa kontrollsummor och kontrollsumman för hela typsnittet omberäknas alla
CFF2 tar en annan väg till samma plats
CFF2 kan inte bäddas in direkt som ett PDF-typsnittsprogram: dess charstrings bär inga bredder, och det förlitar sig på de omgivande OpenType-tabellerna för glyfordning och metriker. Så att instansiera ett CFF2-typsnitt producerar istället ett CID-nyckelbaserat CFF OpenType-typsnitt, vilket de befintliga vägarna för ritning, inbäddning och delmängdsbildning redan hanterar
Att ladda ett CFF2-typsnitt producerar omedelbart en statisk instans med standardkoordinater för det aktuella dokumentet, medan det ursprungliga CFF2-sfnt:et behålls på typsnittsobjektet så att axeluppräkning och senare instansiering fortfarande ser hela designrymden. Varje glyf av-subrutiniseras individuellt under instansiering, vilket helt tar bort variationsaritmetiken och låter den befintliga delmängdsbildaren arbeta oförändrad. Priset är att en statisk instans kan bli något större än en som behöll delade subrutiner — ett rimligt pris för att slippa en andra delmängdsbildningsimplementation
Att verifiera en instans innan du litar på den
Instansiering är den sortens funktion som kan bli subtilt fel på sätt inget undantag rapporterar. Tre kontroller fångar nästan allt
Exportera instansen och öppna den i ett typsnittsverktyg. SaveFontToFile skriver det behållna typsnittsprogrammet, så en instans i minnet kan dumpas utan att först producera en PDF. Den exporterade filen bör tolkas rent, inte innehålla några variationstabeller, och rapportera den stilmetadata du begärde
Jämför förskjutningar vid en icke-standardposition. Om din pipeline kan producera samma instans på ett annat sätt, jämför förskjutningsbredder och kurvgränser glyf för glyf; referensimplementationen här matchade en oberoende instansiering av ett tvåaxligt typsnitt med 313 glyfer med en maximal skillnad på noll över varje glyf
Och extrahera texten ur den genererade PDF:en igen. En instans som bäddas in men inte producerar någon extraherbar text har förlorat sin ToUnicode-mappning, vilket spelar roll för sökning och tillgänglighet långt efter att den visuella kontrollen godkändes. Den bredare extraktionsvägen täcks i text-, bild- och typsnittsextraktion
// Dumpa en genererad instans för inspektion eller återanvändning
Lib.SaveFontToFile('Inter-620-87.ttf');
// Be om koordinater utanför det deklarerade intervallet och de klipps av,
// så läs axel-JSON:en snarare än att anta ett typsnitts gränser
// {"axes":[{"tag":"wght","min":100,"default":400,"max":900}, ...]}
Praktiska anmärkningar för en varumärkestypsnittspipeline
Cacha instanser efter koordinatuppsättning. Varje unik uppsättning koordinater är ett distinkt typsnittsprogram, så ett dokument som blandar vikt 400 och vikt 620 bäddar in två delmängder snarare än ett delat typsnitt. Att generera samma instans upprepade gånger är bortkastat arbete; att generera dussintals nästan identiska vikter är bortkastad filstorlek
Mät med den instans du kommer att rita med. En kondenserad instans har smalare förskjutningar än standardvärdet, så varje layout som mätte innan instansiering mätte fel bredder. Detta är den enskilt vanligaste orsaken till text som svämmar över sin ruta bara i produktion
Behåll en reservväg för de glyfer ditt varumärkestypsnitt saknar. Ett variabelt varumärkestypsnitt täcker vanligtvis latin och lite annat, och en rapport som innehåller ett kyrilliskt kundnamn kommer annars att visa saknade glyfer; den automatiska reservmekanismen beskrivs i automatisk typsnittsreserv för saknade glyfer. Och när målet är en mindre fil snarare än en specifik vikt gör delmängdsbildning mer nytta än instansiering, vilket täcks i optimering av PDF-filstorlek och delmängdsbildning av typsnitt
Import av webbtypsnitt, variabel instansiering, delmängdsbildning och reservtypsnitt är delar av samma typsnittspipeline för Delphi, C++Builder och Free Pascal; den fullständiga funktionslistan finns på sidan för PDF Library for Delphi