|
OpenType GSUB-vervangingsengine Oppervlak voor glyphsubstitutiemogelijkheden (v2.119.43 - v2.119.50)
|
Arabische vorming CFF / OpenType-subsetting |
|
De OpenType GSUB-engine (Glyph SUBstitution) in HotPDF laat aanroepers elk type glyphsubstitutie opvragen, aansturen en inbedden dat een OpenType-lettertype declareert - ligaturen, stilistische alternatieven, contextuele varianten, Arabische / Indic-vormingsvormen, CJK-alternatieve vormen en meer. Elke OpenType GSUB LookupType 1 t/m 8 is geïmplementeerd en beschikbaar als een query-oppervlak voor alleen mogelijkheden; de aanroeper stuurt de tekstuitvoer en beslist welke vervangende glyph naar de inhoudsstroom van de pagina wordt geschreven
Openbare API type TGSUBStringArray = array of AnsiString;
// LookupType 1 - Enkele substitutie (one glyph -> one glyph) function GetSingleSubstituteGlyph(InputGID: Word; const FeatureTag: AnsiString): Word;
// LookupType 2 - Meervoudige substitutie (one glyph -> sequence of glyphs) function GetMultipleSubstituteGlyphs(InputGID: Word; const FeatureTag: AnsiString; var OutGIDs: array of Word): Boolean;
// LookupType 3 - Alternatieve substitutie (one glyph -> one of N alternates) function GetAlternateGlyphCount(InputGID: Word; const FeatureTag: AnsiString): Integer; function GetAlternateGlyph(InputGID: Word; const FeatureTag: AnsiString; AlternateIndex: Integer): Word;
// LookupType 4 - Ligatuur-substitutie (N glyphs -> one ligature) function ApplyLigatureSubstitution(const InputGIDs: array of Word; StartIndex: Integer; const FeatureTag: AnsiString; out OutGID: Word; out ConsumedCount: Integer): Boolean;
// LookupType 5 + 6 - Contextuele / keten-contextuele substitutie function ApplyContextualSubst(const InputGIDs: array of Word; StartIndex: Integer; const FeatureTag: AnsiString; var OutGIDs: array of Word; out ConsumedLen: Integer): Boolean;
// LookupType 8 - Omgekeerde keten-contextuele enkele substitutie function ApplyReverseChainedContextualSubst(const InputGIDs: array of Word; StartIndex: Integer; const FeatureTag: AnsiString; out OutGID: Word): Boolean;
// Script / LangSys-selectie (fase 7) procedure SetGSUBScript(const ScriptTag: AnsiString); procedure SetGSUBLanguage(const LangTag: AnsiString); function GetGSUBScripts: TGSUBStringArray; function GetGSUBLanguages(const ScriptTag: AnsiString): TGSUBStringArray; function GetGSUBFeatures(const ScriptTag, LangTag: AnsiString): TGSUBStringArray;
// TTF-subsetterafsluiting (fase 9) procedure MarkUnicodeGlyphUsed(GID: Word);
Beschrijving De engine activeert nadat
Overal geldt een defensief contract: lettertypen zonder GSUB-tabel, featuretags die geen 4 bytes lang zijn, features die het geselecteerde script / de geselecteerde taal niet adverteren, GID's die geen subtable dekt en invoer-glyphs die door LookupFlag worden genegeerd geven allemaal een veilige no-op terug (False / OutGID = InputGID / lege OutGIDs / ConsumedCount = 1), zodat aanroepers nooit uitzonderingen zien voor de gewone gevallen waarin "geen substitutie van toepassing is"
LookupType-matrix LookupType 1 (Enkele substitutie) - een glyph wordt één vervangende glyph. Canonieke features: LookupType 2 (Meervoudige substitutie) - een glyph splitst in een reeks vervangende glyphs. Canonieke toepassing: LookupType 3 (Alternatieve substitutie) - een glyph wordt één van N alternatieven. Canonieke features: LookupType 4 (Ligatuur-substitutie) - N invoerglyphs smelten samen tot één ligatuur. Canonieke features: LookupType 5 (Contextuele substitutie) + LookupType 6 (Geketende contextuele substitutie) - matcht een invoerglyphreeks en stuurt geneste lookups aan op specifieke posities binnen de match. Alle drie Format-varianten (1 letterlijke reeks, 2 ClassDef-reeks, 3 Coverage-reeks) zijn geïmplementeerd; de SequenceLookupRecord-dispatcher gaat opnieuw de LookupList in en behandelt geneste lookups voor Enkele / Meervoudige / Alternatieve (eerste) / Ligatuur-substitutie met live bijhouden van MatchPositions. Canonieke features: LookupType 7 (Extensiesubstitutie) - een zuivere indirectielaag die de OpenType-specificatie voorschrijft voor lettertypen waarvan de substitutiesubtabel buiten het 16-bits bereik van de LookupList ligt. Elke publieke API volgt transparant de 32-bits Offset32-doorverwijzing naar de echte LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8-subtabel. Ontgrendelt omvangrijke CJK / Indic-lettertypen (Noto Sans CJK, Noto Sans Devanagari) waarvan GSUB groter is dan 64 KB. Geen aparte API - het uitpakken gebeurt automatisch LookupType 8 (Omgekeerde keten-contextuele enkele substitutie) - contextbewuste 1:1-substitutie waarvan het onderscheidende kenmerk is dat aanroepers deze in OMGEKEERDE scanvolgorde over een multi-glyph-run moeten toepassen (einde -> begin), omdat elke substitutie kan afhangen van TOEKOMSTIGE lookahead-context die nog niet mag zijn gesubstitueerd. Canoniek gebruik: contextuele alternatieven voor Arabisch / Syrisch / N'Ko / Indic waarvan de finale vorm afhangt van de volgende glyph. Gebruik
Script / LangSys-selectie Standaard geeft de engine de voorkeur aan het
Strikte versus fallback-semantiek: een onbekende
LookupFlag-honor en GDEF Elke query leest de LookupFlag van elke Lookup-tabel (en de optionele afsluitende markFilteringSet uint16 wanneer
TTF-subsetterafsluiting (MarkUnicodeGlyphUsed) De TTF-subsetter van HotPDF v2.84.0 leidt zijn gebruikte glyph-set af uit
Nadat je een GID die is teruggegeven door
Typische workflow (Latin small caps)
PDF.RegisterUnicodeTTF('myFont', 'C:\\Windows\\Fonts\\arial.ttf'); PDF.SetGSUBScript('latn'); PDF.SetGSUBLanguage(''); // default LangSys SmallCapGID := PDF.GetSingleSubstituteGlyph(InputGID, 'smcp'); if SmallCapGID <> InputGID then begin // schrijf SmallCapGID naar de paginainhoudsstroom PDF.MarkUnicodeGlyphUsed(SmallCapGID); // opnemen in subset end;
Typische workflow (Arabic LAM-ALEF ligature)
PDF.SetGSUBScript('arab'); Run := [LamGID, FathaGID, AlefGID]; // post-cmap GIDs if PDF.ApplyLigatureSubstitution(Run, 0, 'rlig', LigGID, ConsumedCount) then begin // emit LigGID + advance by ConsumedCount PDF.MarkUnicodeGlyphUsed(LigGID); end;
Bereik en beperkingen De engine is een query-oppervlak voor alleen mogelijkheden: hij antwoordt "wat zou GSUB hier doen", maar draait geen automatische vormingspipeline (Harfbuzz-klasse lay-out, clusterbewuste herordening voor Indic, BiDi-resolutie, GPOS-positionering, markbevestiging). Aanroepers zijn verantwoordelijk voor het sturen van de scanlus, het kiezen welke vervangende glyph of alternatieve glyph moet worden uitgegeven, het aanroepen van
De vorming aan de producer-kant voor Arabisch / Perzisch / Urdu (LAM-ALEF-verplichte ligatuur + Arabic Presentation Forms-A) is geïmplementeerd als een aparte ingebouwde pipeline die automatisch draait tijdens tekstuitvoer - zie Arabische / Perzische / Urdu-vorming
Versietrace v2.119.43 Enkele substitutie + fase 1. v2.119.44 Meervoudige + alternatieve substitutie (fase 2). v2.119.45 Ligatuur (fase 3). v2.119.46 Extensie + GDEF + LookupFlag-honor (fase 4). v2.119.47 Contextuele + geketende contextuele substitutie + SequenceLookupRecord-dispatcher (fase 5). v2.119.48 Omgekeerde geketende contextuele substitutie - LookupType 1-8-matrix afgesloten (fase 6). v2.119.49 Script / LangSys-selectie-API (fase 7). v2.119.50 TTF-subsetterafsluiting via
Zie ook: Arabische / Perzische / Urdu-vorming, CFF / OpenType-lettertypesubsettingfuncties, THotPDF.EnableFontSubsetting |