Erweiterte Unicode-Zeichen

Ursprünglich war Unicode für maximal 65536 Zeichen ausgelegt (Nummern 0 - 65535). Mittlerweile gibt es aber viele Zeichen mit grösseren Nummern. Vor allem finden sich dort Zeichen für selten verwendete Schriftsysteme, und selten verwendete chinesische Schriftzeichen, aber auch Spezialzeichen wie z.B. für Notensatz.

Bei Schriften, die wir nach der Unicodemethode eingebunden haben, kommen wir nicht an diese Zeichen heran. Dies, weil wir ja nur einen uint16 für die Adressierung haben, dessen höchstmöglicher Wert 65535 ist. Beim Direktzugriff hingegen können wir diese Zeichen ansprechen, soweit sie in der Schrift sind, da wir hier ja nicht die Unicode-Nummer, sondern die GID angeben. Die GID muss in einer TrueType/OpenType Schrift immer ein Wert von 0 - 65535 sein. Dementsprechend kann übrigens keine Schrift alle möglichen Zeichen von Unicode abdecken.

Allerdings müssen wir die GID noch ermitteln. Bisher haben wir im cmap-Block einen Unterblock nach Format 4 ausgewertet. Wenn wir dessen Definition betrachten, stellen wir aber fest, dass die Unicodenummern wiederum als uint16 abgelegt sind. Folglich können dort keine Nummern grösser 65535 abgelegt sein. Dafür brauchen wir einen anderen Unterblock im Format 12.

Ein weiteres Feature von Unicode sind Zeichenvarianten. Manche Unicode-Nummern verweisen auf Zeichen, für die es verschiedene Varianten mit grundsätzlich identischer Bedeutung gibt. Mittels Variantenselektoren, die nach dem eigentlichen Zeichen geschrieben werden, kann ausdrücklich eine Variante gewählt werden.

Beispiel:

0x3468 0x0E0100

0x3468 ist die Unicode-Nummer. 0x0E0100 definiert die Variante.

Eine TrueType/OpenType Schrift kann mehrere Varianten eines Zeichens ablegen. Die Varianten sind in diesem Fall in einem weiteren cmap-Unterblock abgelegt, welcher im Format 14 ist.

Format 12 Unterblock

Enthält eine Schrift Zeichen mit Unicode-Nummern oberhalbt 65535, so muss neben dem bekannten Unterblock nach Format 4 noch ein weiterer Unterblock nach Format 12 vorhanden sein. Im Verzeichnis der Unterblocks hat dieser ebenfalls als „Plattform“ 3 abgelegt, die „Kodierung“ hingegen ist auf 10 gesetzt.

Der Unterblock enthält eine komplette Liste der Unicode-Nummern und der zugehörigen GIDs. Wir brauchen also den Format 4 Unterblock nicht auszuwerten, wenn ein Format 12 Unterblock existiert. Ähnlich wie beim Format 4 sind auch im Format 12 Segmente von Unicode-Nummern definiert. Glücklicherweise wurde der Block diesmal aber wesentlich einfacher aufgebaut:

PostionLänge Typ Inhalt
02 Byteuint16Format
22 Byteuint16unbenutzt
44 Byteuint32Länge
84 Byteuint32Sprache
124 Byteuint32Anzahl Segmente

Davon interessiert uns eigentlich nur die Anzahl Segmente. Direkt darauf folgt eine Liste der Segmente, deren Einträge folgendermassen aufgebaut sind:

PositionLänge Typ Inhalt
04 Byteuint32Startcode
44 Byteuint32Endcode
84 Byteuint32erste GID

Startcode und Endcode sind die erste bzw. letzte Unicode-Nummer innerhalb des Segments. Der ersten Unicode-Nummer ist die erste GID zugeordnet. Von da an wird die GID für die restlichen Unicode-Nummern des Segments einfach hochgezählt. Die zweite Unicode-Nummer des Segments hat also zum Beispiel die erste GID plus eins.

Bei manchen Schriften ist der Unterblock im Format 13. Der Aufbau von Format 12 und Format 13 ist identisch. Der einzige Unterschied besteht darin, dass die GID beim Format 13 nicht hochgezählt wird, sondern für alle Zeichen innerhalb des Segments gilt.

Übrigens: Auch wenn die GID als uint32 angegeben wurde, so kann sie trotzdem nur einen Wert von 0 bis 65535 haben. Höhere Zahlen sind ein Fehler.

Format 14 Unterblock

Dieser Block, falls vorhanden, enthält eine Liste der von dieser Schrift unterstützten Selektorcodes. Für jeden Code ist zudem eine Liste abgelegt, für welche Zeichen er eine Variante festlegen kann, sowie die GID dieser Variante.

Im Verzeichnis der cmap-Unterblocks ist dieser Unterblock mit „Plattform“ 0 und „Kodierung“ 5 abgelegt, womit er etwas aus der Reihe tanzt. Zudem verwendet dieser Unterblock einen weiteren Datentyp:

uint24vorzeichenlose 24-Bit Zahl

Der Unterblock ist folgendermassen aufgebaut:

PositionLänge Typ Inhalt
02 Byteuint16Format
24 Byteuint32Länge
64 Byteuint32Anzahl Selektorcodes

Darauf folgt eine Liste der Selektorcodes. Jeder Eintrag ist folgendermassen aufgebaut:

PositionLänge Typ Inhalt
03 Byteuint24Unicode-Nummer Selektor
34 Byteuint32Position Standardliste
74 Byteuint32Position Abweichungsliste

Die Standardliste enthält eine Liste von Unicode-Nummern, deren GID-Zuordnung von diesem Selektor nicht verändert wird. Die Liste ist rein informativ, und wird meist weggelassen. In dem Fall ist als Position 0 abgelegt. Für uns ist die Liste nicht interessant.

Was wir brauchen ist die Abweichungsliste. Die Position ist ab dem Anfang des Unterblocks gerechnet. Ist die Position 0, so existiert keine Abweichungsliste. In dem Fall können wir diesen Selektorcode ignorieren.

Die Abweichungsliste beginnt folgendermassen:

PositionLänge Typ Inhalt
04 Byteuint32Anzahl Abweichungen

Danach folgt die eigentliche Liste der Abweichungen. Jeder Eintrag ist folgendermassen aufgebaut:

PositionLänge Typ Inhalt
03 Byteuint24Unicode-Nummer
32 Byteuint16GID

Damit können wir alle von dieser Schrift abgedeckten Kombinationen ermitteln, bei denen ein Alternativzeichen gesetzt werden soll. Bei anderen Kombinationen mit einem Selektorcode sollten wir den Selektor ignorieren. Selektoren haben immer Unicodenummern in einem der Bereiche 0xFE00 - 0xFE0F oder 0x0E0100 - 0x0E01EF.

ToUnicode

Bisher haben wir im ToUnicode Stream jeweils von GIDs auf 2-Byte Unicode-Nummern verwiesen. Genaugenommen verweist die Definition aber nicht auf Unicode-Nummern, sondern auf UTF-16BE Strings in Hexschreibweise. UTF-16 hat eine standardisierte Methode, Zeichen mit Unicode-Nummern jenseits 65535 anzusprechen, die wir hier verwenden können. Ebenso können wir bei Variantenzeichen den Selektor miteinbeziehen.

So erstellte Strings sind 4 bis 8 Byte lang, haben also 8 bis 16 Hexziffern. Analoge Segmente sind möglich. In diesem Fall wird das letzte Byte des UTF-16 Strings hochgezählt. Die restlichen Bytes müssen innerhalb des gesamten Segments identisch sein.

Nicht alle PDF Programme können allerdings mit diesen Strings etwas anfangen. In dem Fall wird die Suche bzw. Copy&Paste der betroffenen Zeichen nicht funktionieren. Die eigentliche Darstellung sollte hingegen nicht beeinträchtigt sein.