Schriften

Bisher haben wir nur mit den Standardschriften gearbeitet. Es ist aber auch möglich, beliebige andere Schriften zu verwenden, sofern sie in einem von PDF unterstützten Format sind. Um sicherzustellen, dass unser Dokument immer noch überall gleich aussieht, müssen wir diese Schriften aber einbetten.

Die Einbettung per se ist nicht allzu kompliziert. Es gibt aber zwei Schwierigkeiten: Zum einen müssen wir die Zeichenbreiten der einzelnen Zeichen der Schrift kennen, um die Breite von Texten berechnen zu können. Andererseits erwartet PDF zu jeder verwendeten Schrift (ausser eben den Standardschriften) eine Reihe von Metadaten. Diese Metadaten sollen dazu dienen, eine Ersatzschrift zu wählen, sollte die eingebettete Schrift aus irgend einem Grund nicht verwendbar sein.

Formate

Schriften liegen in Fontdateien, welche verschiedene Formate haben können. Auf folgende Formate gehen wir ein:

PDF kennt noch ein zwei weitere Formate:

CID Schriften sind eine Variante von Type1 Schriften, die mehr als 256 Zeichen enthalten kann. Leider ist die Einbindung ziemlich kompliziert, und darum im Teil für Fortgeschrittene unter Voller Zeichenzugriff erklärt.

PDF Type3 Schriften (nicht zu verwechseln mit den nicht unterstützten Postscript Type3 Schriften) sind ein Spezialfall für Sonderzwecke. Man sollte sie grundsätzlich nicht verwenden, wenn man nicht genau weiss, was man tut. Ich gehe darum nicht darauf ein.

die Objekte

Bisher sind wir mit einem Objekt für jede Schrift ausgekommen, nämlich dem Schriftobjekt. Für eingebettete Schriften brauchen wir aber deren drei: Das Schriftobjekt, das Schriftdeskriptorobjekt, und ein Streamobjekt mit dem Inhalt der Schriftdatei.

das Schriftobjekt

Dieses ist grundsätzlich gleich aufgebaut wie das Schrifobjekt für Standardschriften. Es wird auch auf die genau gleiche Weise im Resourcendictionary eingebunden. Bei eingebetteten Schriften hat es aber ein paar Einträge mehr:

/Type immer /Font
/Subtype technischer Typus der Schrift
/BaseFont Name der Schrift
/Encoding Zeichenkodierung im Dokument
/FirstChar Code des ersten Zeichens
/LastChar Code des letzten Zeichens
/Widths Liste der Zeichenbreiten
/FontDescriptor Referenz auf das Schriftdeskriptorobjekt

/Subtype ist hier entweder /Type1 oder /TrueType.

/BaseFont ist wieder der Name der Schrift, in Form eines Namensobjekts.

/Encoding sollte bei normalen Schriften auf /WinAnsiEncoding gesetzt, bei symbolischen Schriften weggelassen werden.

/FirstChar und /LastChar geben den tiefstmöglichen bzw. höchstmöglichen Zeichencode an. Normalerweise setzt man einfach 0 bzw. 255 ein.

/Widths ist ein Array mit den Zeichenbreiten1) für alle möglichen Zeichencodes (vom tiefstmöglichen zum höchstmöglichen Code). Die Zeichenbreiten werden als Ganzzahlen in Promille der Schriftgrösse angegeben.

/FontDescriptor ist eine Referenz auf das Schriftdeskriptorobjekt.

das Schriftdeskriptorobjekt

Dieses Objekt enthält Metadaten, welche hauptsächlich dazu dienen sollen, im Notfall eine Ersatzschrift zu wählen. Es ist folgendermassen aufgebaut:

/Type immer /FontDescriptor
/FontName wie /BaseFont
/Ascent die Oberlänge
/Descent die Unterlänge
/CapHeight die Versalhöhe
/FontBBox der Zeichenumfang
/ItalicAngle die Schrägung
/StemV die Stammdicke
/Flags Zusatzdaten
/FontFile Postscript Schriftdatei
/FontFile2 TrueType Schriftdatei
/FontFile3 CFF Schriftdatei

/FontFile, /FontFile2 oder /FontFile3 verweisen auf das Streamobjekt mit der Datei. Es muss nur einer der Einträge angegeben werden, nämlich derjenige, der auf das Dateiformat passt. Für „OpenType Type1“ brauchen wir dabei das CFF Format.

Die übrigen Angaben müssen wir aus den Schriftdaten extrahieren. /Ascent, /Descent, /CapHeight und /StemV sind dabei einzelne ganzzahlige Promillewerte (ähnlich wie die einzelnen Zeichenbreiten). /FontBBox ist ein Array mit vier solchen Werten. /ItalicAngle ist eine Winkelangabe in Grad, und darf ein Dezimalbruch sein.

Achtung Typographen: In Postscript und PDF ist die Oberlänge nicht die Distanz der Oberkante zur x-Höhe, sondern zur Grundlinie.

/Flags ist ein Spezialfall. Es ist eine Ganzzahl, in der verschiedene Eigenschaften der Schrift kodiert sind. Die einzelnen Eigenschaften haben je einen Wert, und indem man die Werte der zutreffenden Eigenschaften addiert, erhält man die gewünschte Zahl2). Die einzelnen Werte sind:

Option Wert Hexwert
Festbreitenschrift 1 0x01
Serifenschrift 2 0x02
symbolische Schrift 4 0x04
Schreibschrift 8 0x08
nichtsymbolische Schrift 32 0x20
Schrägschrift 64 0x40
Grossschrift 65536 0x10000
Kapitälchenschrift 131072 0x20000
ForceBold 262144 0x40000

Der Eintrag ForceBold hat dabei nichts damit zu tun, ob es sich um eine Fettschrift handelt. Vielmehr handelt es sich um ein sogenanntes Hintingflag.

Es lässt sich relativ leicht ermitteln, ob eine Schrift eine Festbreitenschrift ist, ob sie symbolisch oder nichtsymbolisch ist, und ob es sich um eine Schrägschrift handelt. Die restlichen Informationen sind leider nicht oder nur mit erheblichem Aufwand aus den Schriftdateien extrahierbar. Üblicherweise werden sie einfach als „nicht zutreffend“ betrachtet.

das Streamobjekt

Dies ist ein normaler Stream, welcher die eigentlichen Schriftdaten enthält. Zusätzlich zu den normalen Einträgen im Dictionary (/Length und allenfalls /Filter), brauchen wir noch ein paar weitere Einträge. Was für welche hängt vom Schriftformat ab.

Postscript Type1

Es gibt drei zusätzliche Einträge /Length1, /Length2 und /Length3. Die Schriftdatei ist nämlich in drei Abschnitte aufgeteilt, und die Länge dieser drei Abschnitte (vor einer allfälligen Kodierung mit ASCII85 oder ASCIIHex) muss angegeben werden.

TrueType

Es gibt einen zusätzlichen Eintrag /Length1 mit der Länge der Datei vor einer allfälligen Kodierung mit ASCII85 oder ASCIIHex.

OpenType Type1

Es gibt einen zusätzlichen Eintrag /Subtype, der auf /Type1C gesetzt werden muss.

1) typographisch korrekt: eine Liste der Dickten
2) Im Grunde ist es ein Bitfeld.