Diese Dateien enthalten typischerweise zwei oder mehr Schriften, die viele gemeinsame Zeichen haben. Dabei können enthaltene Blöcke von mehreren Schriften gemeinsam genutzt werden, was Speicherplatz spart. Mit PDF ist es aber leider inkompatibel.
Um eine Schrift einer Collection in PDF nutzen zu können, müssen wir ermitteln, welche Blöcke die Schrift verwendet, und daraus eine normale TrueType-Datei zusammenstellen. Das klingt schlimmer als es ist.
TrueType Collections verwenden die Big-Endian Anordnung. Die Datei beginnt folgendermassen:
Postion | Grösse | Typ | Wert |
---|---|---|---|
0 | 4 Byte | char | Signatur |
4 | 2 Byte | uint16 | Version |
6 | 2 Byte | uint16 | Unterversion |
8 | 4 Byte | uint32 | Anzahl Schriften |
Die Signatur muss der ASCII-String „ttcf“ sein. Die Version ist egal: Es gibt derzeit zwei, aber diese sind zueinander kompatibel.
Daraufhin folgt eine Liste mit folgendem Eintrag für jede Schrift:
Postion | Grösse | Typ | Wert |
---|---|---|---|
0 | 4 Byte | uint32 | Position Blockverzeichnis |
Die Position ist gerechnet ab dem Anfang der Datei.
Das Verzeichnis ist identisch wie bei normalen TrueType Schriften. Die Positionen darin sind ebenfalls ab dem Dateianfang der TrueType Collection gerechnet. Um jetzt eine gültige TrueType-Einzelschrift zu erstellen, müssen wir folgendermassen vorgehen:
Punkt 2b ist wichtig: Laut Standard muss jeder Block an einer durch 4 teilbaren Position sein, und die Länge der gesamten Datei muss ebenfalls durch 4 teilbar sein.
Die Prüfsummenjustierung ist folgendes Feld im „head“-Block, welches wir bisher nur am Rande erwähnt haben:
Postion | Grösse | Typ | Wert |
---|---|---|---|
8 | 4 Byte | uint32 | Prüfsummenjustierung |
Für die Anpassung müssen wir folgendermassen vorgehen:
Danach sollte die Prüfsumme über die gesamte Schrift wieder 0xB1B0AFBA ergeben. Manche Programme verweigern die Verwendung einer Schrift, wo dies nicht der Fall ist.
Diese Dateien enthalten typischerweise 4 Schriften derselben Schriftart, nämlich eine normale, eine fette, eine kursive und eine fettkursive Variante. Anders als TrueType Collections enthalten DFonts dabei für jede Einzelschrift einen Block, dessen Inhalt eine gültige TrueType Schrift ist, die wir direkt in PDF verwenden können. An diesen Block heranzukommen ist allerdings etwas umständlich.
Hinweis: Die offizielle Spezifikation des DFont Formats ist nicht öffentlich. Die nachfolgenden Informationen basieren auf Tipps von Dritten und Analysen der existierenden Dateien.
Die Datei verwendet die Big-Endian Anordnung. Sie beginnt mit folgenden Informationen:
Postion | Grösse | Typ | Wert |
---|---|---|---|
0 | 4 Byte | uint32 | Startposition Blocks |
4 | 4 Byte | uint32 | Position Verzeichnis |
Die Positionen sind gerechnet ab dem Anfang der Datei. Betrachten wir nun das Verzeichnis. Dieses beginnt folgendermassen:
Postion | Grösse | Typ | Wert |
---|---|---|---|
0 | 24 Byte | * | unbekannt |
24 | 2 Byte | uint16 | Position Typenliste |
26 | 2 Byte | uint16 | Startposition Namen |
Die Positionen sind gerechnet ab dem Anfang des Verzeichnisses. Als nächstes müssen wir uns die Typenliste vornehmen. Diese beginnt folgendermassen:
Postion | Grösse | Typ | Wert |
---|---|---|---|
0 | 2 Byte | uint16 | Anzahl Typen - 1 |
Wenn hier also eine 2 steht, so haben wir 3 Typen abgelegt. Es folgt nun eine Liste mit folgendem Eintrag für jeden Typ:
Postion | Grösse | Typ | Wert |
---|---|---|---|
0 | 4 Byte | char | Typ |
4 | 2 Byte | uint16 | Anzahl Blöcke - 1 |
6 | 2 Byte | uint16 | Position Blockliste |
Die Position ist gerechnet ab dem Anfang der Typenliste. Der Typ, den wir suchen, ist mit dem ASCII-String „sfnt“ gekennzeichnet. Die Blöcke dieses Typs sind vollständige, eigenständige TrueType Schriften.
Die Blockliste beginnt direkt mit der eigentlichen Liste. Für jeden Block (meistens 4) ist folgender Eintrag hinterlegt:
Postion | Grösse | Typ | Wert |
---|---|---|---|
0 | 2 Byte | * | unbekannt |
2 | 2 Byte | uint16 | Position Namen |
4 | 1 Byte | * | unbekannt |
5 | 3 Byte | uint24 | Position Block |
8 | 4 Byte | * | unbekannt |
Es muss nicht unbedingt ein Blockname abgelegt sein. Wenn dieser fehlt, so ist als Position 65535 abgelegt. Ansonsten ist die Position gerechnet ab der Startposition Namen. Wir brauchen den Namen nicht wirklich, aber wer will, kann ihn auslesen. Es handelt sich um einen String im Pascalformat. Das heisst, das erste Byte ist ein uint8 mit der Länge in Byte (ohne dieses erste Byte), und der Rest ist der eigentliche String. Die Kodierung ist wahrscheinlich MacRoman.
Die Position des Blocks ist gerechnet ab der Startposition Blocks. An der beschriebenen Position steht ein uint32 mit der Länge des Blocks (ohne diese vier Byte). Darauf folgen die eigentlichen Blockdaten mit der TrueType Schrift.
TrueType Schriften, welche nur den Anforderungen von Apple genügen (aber nicht jenen von Microsoft), unterscheiden sich in den Blöcken „name“, „OS/2“ und „cmap“, von denjenigen, die wir bisher behandelt haben. Im Falle von „name“ und „OS/2“ ist dies lediglich ärgerlich, aber im Falle von „cmap“ haben wir ein echtes Problem. Laut PDF Standard wird nämlich ein Unterblock mit Plattform-ID 3 und Format 4 erwartet, der eine Tabelle von Unicode auf die GIDs enthält. Dieser Unterblock fehlt in der Regel.
Aus Kompatibilitätsgründen haben aber Schriften, die für lateinischen Schriftsatz geeignet sind, einen Unterblock mit Plattform 1 und Kodierung 0. Laut TrueType Standard definiert dieser Unterblock eine Tabelle von MacRoman auf die GIDs. Der Unterblock ist auch in symbolischen Schriften vorhanden, und definiert in diesem Fall eine Tabelle von der schrifteigenen Kodierung auf die GIDs. Laut PDF Standard wird dieser Unterblock als Fallback verwendet. Um Probleme zu vermeiden sollte aber die MacRoman Kodierung anstelle der „Windows westlich“ Kodierung verwendet werden. Ansonsten muss das PDF-Programm erst den Text nach MacRoman konvertieren, und da können subtile Differenzen zu unterschiedlichen Ausgaben führen.
Schriften, die für MacOS 8.5 oder neuer konzipiert wurden, enthalten in der Regel auch noch einen Unterblock für Unicode. Dieser hat aber andere Codes für Plattform und Kodierung, und oft auch ein anderes Format. Für PDF Programme, die nur die Unterblocks nach PDF Standard betrachten, ist dieser Unterblock daher nutzlos. Wir können ihn aber selber auslesen, und die Schrift über das Kompositschriftsystem einbinden. Bei diesem System stützt sich das PDF Programm bekanntlich auf unsere Angaben, statt auf den cmap Block.
Es gibt noch einen Punkt betreffend der Kompatibilität, den wir beachten sollten: Der MacRoman-Unterblock kann im Format 6 sein (siehe unten), und dieses Format wird von manchen PDF Programmen nicht verstanden. Will man solche Schriften verwenden, ist es besser, auf das Kompositschriftsystem auszuweichen.
Hier nun die konkreten Unterschiede, und wie wir an die Daten kommen:
Das Format des Blocks ist identisch, aber die Codes im Verzeichnis, und die Zeichenkodierung der Texte sind unterschiedlich. Folgende Codes werden verwendet:
Plattform | Kodierung | Sprache | Typ | Inhalt |
---|---|---|---|---|
1 | 0 | 0 | 1 | Schriftart |
1 | 0 | 0 | 4 | Schriftname (OS) |
1 | * | * | 6 | Schriftname (Postscript) |
Die Kodierung ist jeweils MacRoman (wobei für den Schriftnamen nach Postscript nur ASCII zulässig ist).
Dieser Block fehlt in der Regel, und wenn er vorhanden ist, ist er häufig in einem inkompatiblen (und für uns unbrauchbaren) Format. Dieses Format ist daran erkennbar, dass der Block nur 68 Byte lang ist.
Fehlt der Block, oder ist er im inkompatiblen Format, so dürfen wir annehmen, dass es keine Einschränkung für die Einbettung gibt, und für die Hoch- und Tiefstellung können wir einfach die Standardwerte verwenden. Was Oberlänge, Unterlänge, Zeilendurchschuss und Versalhöhe betrifft, so müssen wir diese statt dessen aus dem „hhea“ Block holen.
Dieser Block ist identisch. Er enthält aber einige Informationen, die wir bisher ignoriert haben.
Position | Grösse | Typ | Wert |
---|---|---|---|
4 | 2 Byte | int16 | Oberlänge (Apple) |
6 | 2 Byte | int16 | Unterlänge (Apple) |
8 | 2 Byte | int16 | Zeilendurchschuss (Apple) |
34 | 2 Byte | uint16 | Anzahl GIDs mit expliziter Zeichenbreite |
Die Oberlänge und Unterlänge haben dasselbe Format wie jene im „OS/2“ Block. Der Unterschied ist, dass hier die Apple-Definition verwendet wird. Im Unterschied zur Adobe-Definition erlaubt diese keine oben oder unten überhängenden Zeichen, was den Gestaltungsspielraum des Designers etwas einschränkt. Darum sollte man wenn möglich die Werte aus dem „OS/2“ Block verwenden, kann aber wenn nötig auf jene aus dem „hhea“ Block ausweichen.
Die Oberlänge kann als Versalhöhe eingesetzt werden (so wie bei „OS/2“ Blöcken ohne Versalhöhe).
Der Zeilendurchschuss ist ein wenig anders definiert, als bei Adobe. Um den Zeilenabstand zu bekommen, rechnet man folgendermassen:
Zeilenabstand = Zeilendurchschuss + Oberlänge - Unterlänge
Nicht vergessen: Die Unterlänge ist ein negativer Wert, und vergrössert somit den Zeilenabstand.
Grundlagen "cmap" Block
Unterblock Format 12
Der Block an sich ist im selben Format. Es werden aber andere Codes im Verzeichnis verwendet, und die Unterblocks können in anderen Formaten sein. Folgende Codes werden verwendet:
Plattform | Kodierung | Typ |
---|---|---|
1 | 0 | MacRoman / symbolische Schrift |
0 | 0 – 4 | Unicode |
Der Unterblock für MacRoman bzw. symbolische Schriften ist in einem der Formate 0, 4 oder 6.
Der Unterblock für Unicode ist in einem der Formate 4, 6, 8, 10 oder 12. Es können mehrere Unterblocks vorhanden sein. In diesem Fall wählt man am Besten jenen mit der grössten Formatnummer.
Die Formate 4 und 12 kennen wir schon. Hier die Rest:
Dieser Unterblock kann nur Zeichen aus 8-Bit Kodierungen aufnehmen. Er beginnt folgendermassen:
Position | Grösse | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Format (0) |
2 | 2 Byte | uint16 | Grösse |
4 | 2 Byte | uint16 | Sprache |
Darauf folgt ein Eintrag für jeden der möglichen Zeichencodes von MacRoman bzw. der symbolischen Schrift von 0 bis 255:
Position | Grösse | Typ | Inhalt |
---|---|---|---|
0 | 1 Byte | uint8 | GID |
Dieser Unterblock kann, ähnlich wie der Format 4 Unterblock, Unicode-Zeichen bis 65535 aufnehmen. Vom Aufbau her ähnelt er aber eher dem Format 0 Unterblock. Er beginnt folgendermassen:
Position | Grösse | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Format (6) |
2 | 2 Byte | uint16 | Grösse |
4 | 2 Byte | uint16 | Sprache |
6 | 2 Byte | uint16 | Startcode |
8 | 2 Byte | uint16 | Anzahl Zeichen |
Darauf folgt ein Liste von „Anzahl Zeichen“ Länge, welches die möglichen Unicode-Nummern vom Startcode an hochgezählt abdeckt:
Position | Grösse | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | GID |
Dieser Unterblock wurde spezifisch für UTF-16 mit Surrogaten definiert. Er ist mir in freier Wildbahn noch nie begegnet, aber man kann ja nie wissen. Der Block ähnelt dem Format 12 Unterblock, und beginnt folgendermassen:
Position | Grösse | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Format (8) |
2 | 2 Byte | uint16 | unbenutzt |
4 | 4 Byte | uint32 | Grösse |
8 | 4 Byte | uint32 | Sprache |
12 | 8192 Byte | * | Codeflags |
8204 | 4 Byte | uint32 | Anzahl Segmente |
Die Codeflags definieren, welche Codes ein Surrogat-Paar einleiten. Für uns sind sie uninteressant.
Darauf folgt eine Liste mit folgendem Eintrag für jedes Segment:
Position | Grösse | Typ | Inhalt |
---|---|---|---|
0 | 4 Byte | uint32 | Startcode |
4 | 4 Byte | uint32 | Endcode |
8 | 4 Byte | uint32 | erste GID |
Der Startcode erhält die „erste GID“, für die restlichen Codes wird die GID hochgezählt.
Codes mit Wert von 0 bis 65535 sind Unicode-Nummern. Grössere Codes sind Strings in der Kodierung UTF-16BE. Um aus ihnen die Unicode-Nummer zu ermitteln, kann man arithmetisch so vorgehen:
unicode = (floor(utf16 / 0x10000) modulo 0xd800) * 0x400 + (utf16 modulo 0x10000 modulo 0xdc00) + 0x10000
Etwas einfacher geht es mit bitweisen Operatoren:
unicode = (((utf16 >> 16) & 0x3ff) << 10) + (utf16 & 0x3ff) + 0x10000
Dieser Unterblock kann, ähnlich wie der Format 12 Unterblock, den vollen Zeichenumfang von Unicode aufnehmen. Er ähnelt dem Format 0 oder Format 6 Unterblock, und beginnt folgendermassen:
Position | Grösse | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | Format (10) |
2 | 2 Byte | uint16 | unbenutzt |
4 | 4 Byte | uint32 | Grösse |
8 | 4 Byte | uint32 | Startcode |
12 | 4 Byte | uint32 | Anzahl Zeichen |
Darauf folgt ein Liste von „Anzahl Zeichen“ Länge, welches die möglichen Unicode-Nummern vom Startcode an hochgezählt abdeckt:
Position | Grösse | Typ | Inhalt |
---|---|---|---|
0 | 2 Byte | uint16 | GID |
Diskussion