Mit OpenType wurde ein neues (auch für TrueType brauchbares) System eingeführt, um die Positionierung von Zeichen präziser zu bestimmen, und diverse Alternativzeichen und Ligaturen zur Verfügung zu stellen. Leider ist dieses System höchst komplex, und es gibt kaum Systeme, die es auch nur grösstenteils unterstützen.
Um das System verwenden zu können, müssen wir es aber auch nicht vollständig unterstützen. Die meisten Schriften nutzen ohnehin nur einen kleinen Teil davon. Problematisch wird es erst bei Schriften, die spezifisch für komplexe Schriftsysteme wie Arabisch oder Tibetanisch erstellt wurden.
Für unsere Zwecke erkläre ich hier nur einen kleinen Teil der Spezifikation, dessen Nutzung aber weit verbreitet ist. Dieser Teil für sich ist schon kompliziert genug.
Grundsätzlich können über das Schriftfeaturesystem vier Dinge beeinflusst werden: Die genaue Positionierung der Zeichen, alternative Zeichen, Sonderregeln für Blocksatz und Sonderregeln für die Grundlinie. Davon werden wir uns folgendes Anschauen:
Ligaturen sind Zeichen, welche aus mehreren Einzelzeichen zusammengesetzt wurden. Damit lassen sich typographisch heikle Zeichenkombinationen besser lösen. Alternativzeichen und Ligaturen können nur bei Direktzugriff verwendet werden, da wir nur dort die volle Kontrolle über die verwendeten GIDs haben.
Die einzelnen Features der Schrift können je nach Schriftsystem und Sprache unterschiedlich definiert werden. Für uns heisst das leider, dass wir uns durch eine hierarchische Struktur hangeln müssen. Der GPOS Block und der GSUB Block, mit denen wir uns beschäftigen werden, haben hierfür drei Tabellen: Die Schrift/Sprachtabelle, die Featuretabelle und die Lookuptabelle.
Diese Tabelle definiert, welche der Features für welche Kombinationen aus Schriftsystem und Sprache verwendet werden können. Die Tabelle beginnt mit einer Liste der unterstützten Schriftsysteme. Jeder Eintrag hat eine Liste dazu passender Sprachen. Jeder Eintrag der Sprachenlisten enthält eine Liste mit den gültigen Featurenummern. Sowohl die Schriftsystemliste wie auch die Sprachenlisten können jeweils einen Standardeintrag haben, der gültig ist, wenn kein Schriftsystem bzw. keine Sprache passt.
Die Position der Schrift/Sprachtabelle wird durch einen Eintrag am Anfang des Blocks vorgegeben, der in den Unterkapiteln erklärt ist. Die Tabelle beginnt mit folgendem Eintrag:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Anzahl Schriftsysteme |
Danach folgt eine Liste der unterstützten Schriftsysteme. Jeder Eintrag ist folgendermassen aufgebaut:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 4 Byte | char | Schriftsystem-ID |
4 | 2 Byte | uint16 | Position Sprachtabelle |
Die möglichen Schriftsystem-IDs sind bei Microsoft einsehbar:
http://www.microsoft.com/typography/developers/opentype/scripttags.aspx
Beispiele für Schriftsystem-IDs:
DFLT | Standard |
---|---|
latn | Lateinische Schrift |
grek | Griechische Schrift |
cyrl | Kyrillische Schrift |
kana | Japanische Silbenschrift |
hani | CJK Wortschrift |
Die Position der Sprachenliste ist gerechnet vom Anfang der Schrift/Sprachtabelle.
Die Sprachenliste beginnt folgendermassen:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Position Standardfeaturenummern |
2 | 2 Byte | uint16 | Anzahl Sprachen |
Danach folgt eine Liste der unterstützten Sprachen. Jeder Eintrag ist folgendermassen aufgebaut:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 4 Byte | char | Sprachen-ID |
4 | 2 Byte | uint16 | Position Featurenummern |
Die möglichen Sprachen-IDs sind bei Microsoft einsehbar:
http://www.microsoft.com/typography/developers/opentype/languagetags.aspx
Beispiele für Sprach-IDs:
dflt | Standard |
---|---|
DEU | Deutsch |
ENG | Englisch |
ELL | Griechisch |
RUS | Russisch |
JAP | Japanisch |
Wie man sieht, bestehen die Sprachen-IDs meist aus drei Zeichen, wohingegen in der Liste jeweils vier Zeichen abgelegt sind. Das vierte Zeichen ist in diesen Fällen immer ein Leerzeichen.
Falls die „Position Standardfeaturenummern“ nicht 0 ist, so hat dies dieselbe Bedeutung wie ein „dflt“ Eintrag. die Position der Featurenummern ist gerechnet vom Anfang der Sprachentabelle.
Die Liste der Schrift/Sprache-Spezifischen Features beginnt folgendermassen:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | unbenutzt |
2 | 2 Byte | uint16 | benötigtes Feature |
4 | 2 Byte | uint16 | Anzahl Features |
Danach folgt für jedes Feature die Featurenummer:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Featurenummer |
Die Angabe unter „benötigtes Feature“ steht normalerweise auf 65535. Ist es eine andere Zahl, so bezeichnet es eine Featurenummer, die unterstützt werden muss, damit die Schrift korrekt dargestellt werden kann.
Diese Tabelle enthält eine Liste der von der Schrift unterstützten Features. Zu jedem Feature sind die zugehörigen Lookupnummern abgelegt.
Die Position der Featuretabelle wird durch einen Eintrag am Anfang des Blocks vorgegeben, der in den Unterkapiteln erklärt ist. Die Tabelle beginnt mit folgendem Eintrag:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Anzahl Features |
Danach folgt eine Liste der Features. Jeder Eintrag ist folgendermassen aufgebaut:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 4 Byte | char | Feature-ID |
4 | 2 Byte | uint16 | Position Lookupnummern |
Die Featurenummer ist nicht explizit aufgeführt. Statt dessen werden die Features in der Liste von 0 an durchnummeriert.
Die möglichen Feature-IDs sind bei Microsoft einsehbar:
http://www.microsoft.com/typography/otspec/featurelist.htm
Wir werden uns folgende Features weiter ansehen:
kern | Unterschneidung |
---|---|
smcp | Kapitälchen |
onum | Mediävalziffern |
liga | Ligaturen |
Anhand der in der Schrift/Sprachtabelle ermittelten Featurenummern und der gewünschten Feature-ID sollte man nun für jedes Feature auf maximal einen Eintrag kommen. Nun können wir die dazugehörigen Lookupnummern ermitteln. Die Position ist gerechnet ab dem Beginn der Featureliste. Die Liste der Lookupnummern beginnt folgendermassen:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | unbenutzt |
2 | 2 Byte | uint16 | Anzahl Lookupeinträge |
Danach folgt für jeden Lookupeintrag die Lookupnummer:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Lookupnummer |
Falls mehrere Lookupeinträge vorhanden sind, müssen sie in der aufgeführten Reihenfolge abgearbeitet werden.
Diese Tabelle enthält die Positionen der eigentlichen Unterblöcke mit den Daten zu den Features.
Die Position der Lookuptabelle wird durch einen Eintrag am Anfang des Blocks vorgegeben, der in den Unterkapiteln erklärt ist. Die Tabelle beginnt mit folgendem Eintrag:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Anzahl Lookupeinträge |
Danach folgt eine Liste der Positionen für jeden Lookupeintrag:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Position Lookupeintrag |
Ähnlich wie bei den Features sind auch die Lookupnummern nicht explizit aufgeführt, sondern die Einträge sind einfach ab 0 durchnummeriert.
Die Position ist jeweils gerechnet ab dem Beginn der Lookuptabelle. Der Eintrag ist folgendermassen aufgebaut:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Typ |
2 | 2 Byte | uint16 | Flags |
4 | 2 Byte | uint16 | Anzahl Unterblocks |
Die Bedeutung der Typnummer hängt davon ab, ob wir im GPOS oder GSUB Block sind, und ist darum in den Unterkapiteln erklärt. Die Flags können wir bei den hier vorgestellten Features ignorieren.
Nun folgt eine Liste der Positionen der Unterblocks:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Position Unterblock |
Die Position ist jeweils gerechnet ab dem Beginn des Lookupeintrags. Der Inhalt des Unterblocks ist abhängig vom Feature, und darum in den Unterkapiteln erklärt.
Falls mehrere Unterblöcke vorhanden sind, müssen sie in der angegebenen Reihenfolge abgearbeitet werden.
Fast jeder Unterblock für Schriftfeatures verweist auf eine Zeichenliste. Dies ist ein spezieller Unterblock, der eine Liste von GIDs definiert. Es gibt zwei Formate. Die jeweils ersten 2 Bytes sind dabei ein uint16 mit der Formatnummer.
Das ist eine einfache Liste. Sie beginnt folgendermassen:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Format (immer 1) |
2 | 2 Byte | uint16 | Anzahl Einträge |
Danach folgt die Liste der GIDs. Jeder Eintrag sieht so aus:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | GID |
Dieses Format definiert die Liste, indem es zusammenhängende Nummernbereiche aufzählt. Der Unterblock beginnt folgendermassen:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Format (immer 2) |
2 | 2 Byte | uint16 | Anzahl Bereiche |
Danach folgt die Liste der Bereiche. Jeder Eintrag sieht so aus:
Position | Länge | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | erste GID |
2 | 2 Byte | uint16 | letzte GID |
4 | 2 Byte | uint16 | erste Indexnummer |
Der Bereich enthält der Reihe nach alle GIDs von der ersten bis und mit der letzten. Die „erste Indexnummer“ ist die Anzahl der von den bisherigen Bereichen abgedeckten GIDs. Wenn wir die GIDs aufzählen, und dabei mit 0 beginnen, ist „erste Indexnummer“ somit die Nummer der ersten GID in diesem Bereich.
Diskussion