====== Postscript Type1 ====== Dieses Format war einst weit verbreitet, vor allem im professionellen Sektor. Mittlerweile ist es weitgehend durch TrueType und OpenType ersetzt. Trotzdem findet man es aber noch, und es kann relativ leicht eingebunden werden. ===== die Dateien ===== Eine Postscript Type1 Schrift besteht aus mehreren Dateien. Zumindest gibt es eine AFM Datei mit den Metadaten, und eine PFB Datei mit den eigentlichen Schriftdaten. Oft sind noch eine PFM und eine INF Datei vorhanden, welche vom Adobe Type Manager benötigt werden. Wir benötigen lediglich die AFM Datei, um an die Metadaten für das Schriftobjekt und das Schriftdeskriptorobjekt zu kommen, sowie die PFB Datei für das Streamobjekt. Manchmal gibt es statt der PFB Datei eine PFA Datei. Das ist ein leicht anderes Format, welches von PDF nicht unterstützt wird. Zum Glück kann PFA aber leicht in PFB umgewandelt werden. Vorsicht: PFA Dateien können ausser Type1 Schriften auch die nicht unterstützten Type3 oder Type42 Schriften enthalten. Falls die AFM-Datei fehlt, so kann sie z.b. mit dem mit [[http://www.ghostscript.com/|Ghostscript]] mitgelieferten Utility pfb2afm rekonstruiert werden. Viele der Metadaten in einer so erstellten AFM-Datei enthalten aber nur Abschätzungen, und natürlich fehlen jegliche Feinjustierungen durch den Schriftdesigner. **Vorsicht Postscript Umsteiger:** Das "ISOLatin1Encoding" von Postscript setzt den Code 0x2D auf das Zeichen "minus". Das "WinAnsiEncoding" von PDF setzt diesen Code hingegen auf "hyphen". Beide stellen einen einfachen, horizontalen Strich dar, aber "hyphen" ist in vielen Schriften schmaler als "minus". ===== Metadaten ===== Wie gesagt sind die Metadaten in der AFM Datei enthalten. Dabei handelt es sich um eine Textdatei. Normalerweise haben diese Zeilenumbrüche nach Microsoft-Norm (<0D 0A>), gelegentlich aber auch nach Unix-Norm (<0A>). Solche nach der pre Mac OS X Norm (<0D>) sollten mittlerweile ausgestorben sein. Die meisten Programmiersprachen können alle Varianten lesen. Falls aber Schwierigkeiten auftreten, hilft es unter Umständen, die Datei vorgängig in die passende Variante zu konvertieren. Die Informationen sind zeilenweise abgelegt, wobei grundsätzlich eine Information pro Zeile steht. Das erste Wort der Zeile benennt den Typ der Information, der Rest ist die Information selbst. Worte und Werte sind durch ein oder mehrere Leerschläge oder Tabulatoren getrennt. Die erste Zeile ist immer ''StartFontMetrics //v//'', wobei v für eine Versionsnummer steht. Die letzte Zeile ist immer ''EndFontMetrics''. ==== allgemeine Werte ==== Von den in der Datei angegebenen Werten interessieren uns zunächst jene, welche mit folgenden Worten gekennzeichnet sind: ^FontName |Schriftname | ^Ascender |Oberlänge | ^Descender |Unterlänge | ^CapHeight |Versalhöhe | ^FontBBox |Zeichenumfang | ^ItalicAngle |Schrägung | ^StdVW |Stammdicke | ^IsFixedPitch |Fixbreitenschrift | ^CharWidth |Zeichenbreite | ^EncodingScheme |die interne Schriftkodierung | ''FontName'' muss in ein Namenobjekt umgewandelt werden, und kann danach für ''/BaseFont'' im Schriftobjekt und für ''/FontName'' im Schriftdeskriptorobjekt eingesetzt werden. ''Ascender'', ''Descender'', ''CapHeight'', ''ItalicAngle'' und ''StdVW'' können 1:1 in ''/Ascent'', ''/Descent'', ''/CapHeight'', ''/ItalicAngle'' und ''/StemV'' des Schriftdeskriptorobjekts übernommen werden. ''FontBBox'' hat als Wert 4 durch Leerschläge und/oder Tabulatoren getrennte Zahlen. Diese müssen noch mit eckigen Klammern umschlossen werden, um ein Array zu bilden, und können danach für ''/FontBBox'' des Schriftdeskriptorobjekts eingesetzt werden. Für die Flags gilt folgendes: * Kommt ''IsFixedPitch'' vor, und ist als Wert ''true'' angegeben, so ist es eine Fixbreitenschrift, sonst nicht. * Kommt ''EncodingScheme'' vor, und ist als Wert ''FontSpecific'' angegeben, so ist es eine symbolische Schrift, sonst eine nichtsymbolische Schrift. * Kommt ''ItalicAngle'' vor, und ist der Wert nicht ''0'', so ist es eine Schrägschrift, sonst nicht. ''CharWidth'' kann bei Fixbreitenschriften vorkommen. Falls vorhanden, hat es als Wert zwei durch Leerschläge und/oder Tabulatoren getrennte Zahlen, von denen die erste Zahl die Zeichenbreite für alle Zeichen dieser Schrift ist. ==== Schreibrichtungsblöcke ==== Gewisse Angaben können für horizontale und vertikale Schreibrichtung unterschiedlich sein. Für diesen Fall werden in der Datei Abschnitte definiert, die nur für eine Schreibrichtung gültig sind. Ein Schreibrichtungsblock beginnt mit einer Zeile ''StartDirection //d//'', wobei d für die Schreibrichtung steht. 0 ist horizontal, 1 ist vertikal, 2 ist beides. Der Schreibrichtungsblock endet mit einer Zeile ''EndDirection''. Da wir nur die horizontale Schreibrichtung verwenden, können wir es uns einfach machen: Wenn immer wir eine Zeile ''StartDirection 1'' finden, ignorieren wir einfach alle weiteren Zeilen, bis wir eine mit ''EndDirection'' finden. ==== Zeichenbreitenblock ==== Falls wir eine Fixbreitenschrift haben, und CharWidth definiert wurde, können wir die dort angegebene Breite für alle Zeichen übernehmen. Ansonsten müssen wir sie aus dem Zeichenbreitenblock holen. Der Zeichenbreitenblock beginnt mit einer Zeile ''StartCharMetrics //x//'', wobei x für die Anzahl Zeichen steht. Der Block endet mit einer Zeile ''EndCharMetrics''. Die Zeilen innerhalb des Blocks haben ein spezielles Format. Jedes Zeichen hat seine eigene Zeile. Jede Zeile besteht aus verschiedenen Informationen, die mit Strichpunkten voneinander getrennt sind. Die einzelnen Informationen bestehen aus einer Buchstabenkombination, die den Typ festlegt, und einem oder mehreren Werten. Die Typen, Werte und Strichpunkte sind durch ein oder mehrere Leerschläge und/oder Tabulatoren getrennt. Beispiel: C 36 ; WX 556 ; N dollar ; B 32 -126 518 770 ; Von den Informationen interessieren uns folgende: ^N |Name des Zeichens | ^C |Nummer des Zeichens | ^WX oder W0X |Breite des Zeichens | ^W oder W0 |Breite und Höhe des Zeichens | Im Falle von ''WX'' oder ''W0X'' haben wir genau eine Zahl, welche die Zeichenbreite ist. Bei ''W'' oder ''W0'' haben wir zwei Zahlen, von denen die Erste die Zeichenbreite ist. In beiden Fällen ist die Zeichenbreite in Promillen der Schriftgrösse, also schon im richtigen Format. Um bei symbolischen Schriften die Zeichenbreiten zu erhalten, suchen wir für alle möglichen Codes von 0 bis 255 einen Eintrag mit entsprechender Zeichennummer. Um bei normalen Schriften die Zeichenbreiten zu erhalten, ermitteln wir für alle möglichen Codes von 0 bis 255 den passenden Zeichennamen, und suchen anschliessend einen Eintrag mit diesem Namen. Im Anhang ist eine [[/anhang/namen_und_codes|Tabelle mit den Zeichennamen]] für die Zeichen in "Windows westlich". Bei Zeichen, die keinen Namen haben, oder für die wir keinen Eintrag finden, nehmen wir als Breite 0. Die so ermittelten Breiten stellen wir zu einer Liste zusammen. Diese können wir nun für ''/Widths'' im Schriftobjekt verwenden. ==== Kerningblock ==== Die Datei kann einen Kerningblock enthalten. Dieser enthält Angaben zur Unterschneidung. Wir brauchen diese Angaben nicht, müssen aber wissen, wie der Block erkannt und überlesen werden kann. Der Kerningblock, soweit vorhanden, beginnt mit einer Zeile ''StartKernData'', und endet mit einer Zeile ''EndKernData''. Diesen Bereich müssen wir überlesen. ==== falls was fehlt ==== Die meisten Angaben sind optional. Wir müssen sie ersetzen, falls sie nicht in der Datei sind. * Falls Ascender fehlt, können wir statt dessen die vierte Zahl von FontBBox verwenden. * Falls Descender fehlt, können wir statt dessen die zweite Zahl von FontBBox verwenden. * Falls CapHeight fehlt, können wir statt dessen Ascender verwenden. * Falls ItalicAngle oder StdVW fehlt, können wir als Wert 0 annehmen. * Falls IsFixedPitch fehlt, können wir als Wert false annehmen * Falls EncodingScheme fehlt, können wir als Wert AdobeStandardEncoding annehmen. ===== die Schriftdaten ===== Die eigentlichen Schriftdaten sind in einer PFB Datei. Dabei handelt es sich um eine binäre Datei. Zahlen, die mehr als 1 Byte benötigen, sind in **Little-Endian** Anordnung. Es kommen folgende Datentypen zur Anwendung: ^uint8 |vorzeichenlose 8-bit Zahl | ^uint32 |vorzeichenlose 32-bit Zahl | Der Aufbau ist ähnlich wie bei JPEG: Die Datei besteht aus mehreren aufeinanderfolgenden Blöcken, die mit einem 2 Byte langen Marker und einer 4 Byte langen Längenangabe beginnen. In diesem Fall sind es immer exakt drei Blöcke. ^Position ^Grösse ^Typ ^Inhalt ^ | 0|1 Byte |uint8 |immer 0x80 | | 1|1 Byte |uint8 |Inhaltstyp | | 2|4 Byte |uint32 |Datenlänge | | 6|Datenlänge |* |Daten | Der Marker hat als erstes Byte 0x80, und als zweites Byte den Wert 1 oder 2, was den Inhaltstyp festlegt. Der erste und dritte Block sind immer Typ 1, der zweite Block ist immer Typ 2. Auf den Marker folgt ein uint32 Wert mit der Länge des Blocks. Die Längenangabe ist dabei nur für die eigentlichen Blockdaten, ohne die 6 Bytes für Marker und Längenangabe selbst. Nach dem dritten Block folgt ein Marker <80 03> ohne Längenangabe, welcher das Ende der Datei markiert. Wir müssen den Inhalt nicht weiter interpretieren. Wir müssen lediglich die Daten der einzelnen Blöcke extrahieren und aneinanderhängen (ohne Marker und Längenangaben). Diese aneinandergehängten Daten werden als Inhalt des Streamobjekts verwendet. Die drei Längenangaben müssen wir als ''/Length1'', ''/Length2'' und ''/Length3'' in das Dictionary des Streams eintragen. Der dritte Block einer PFB Datei ist immer gleich. Darum ist es uns erlaubt diesen wegzulassen. In dem Fall muss ''/Length3'' einfach auf 0 gesetzt werden. Beispiel: <80 01 B9 12 00 00> (4793 Bytes) <80 02 68 75 00 00> (30056 Bytes) <80 01 14 02 00 00> (532 Bytes) <80 03> Der erste Block ist 0x12B9 (4793) Bytes lang, der zweite 0x7568 (30056) Bytes, und der letzte wie eigentlich immer 0x214 (532) Bytes. Wenn wir nur mit den ersten beiden Blocks arbeiten, sollte das Streamobjekt also etwa so aussehen: 6 0 obj << /Length1 4793 /Length2 30056 /Length3 0 /Length 44145 /Filter /ASCII85Decode >> stream ...~> endstream endobj ==== PFA verarbeiten ==== Falls wir die Datei im PFA Format haben, können wir sie folgendermassen verwenden: PFA Dateien sind Textdateien, nicht binäre Dateien. Auch sie bestehen grundsätzlich aus denselben drei Blöcken. Deren Abgrenzung ist aber nicht mit Blockmarkern festgelegt, sondern ergibt sich aus dem Kontext. Der erste Block geht vom Anfang der Datei bis zum Schlüsselwort ''eexec''((Falls kein Schlüsselwort eexec vorhanden ist, ist es keine Type1 Schrift.)). Er endet nach dem auf eexec folgenden Zeilenumbruch. Der dritte Block ist am Dateiende. Er umfasst 512 Nullen, die von Leerschlägen, Tabulatoren und Zeilenumbrüchen unterbrochen sein können((eigentlich 256 0-Bytes in Hexadezimalschreibweise)), gefolgt vom Schlüsselwort ''cleartomark''. Der zweite Block geht exakt vom Ende des ersten Blocks zum Anfang des dritten Blocks. Es handelt sich um binäre Daten in Hexadezimalschreibweise. Um diesen Block verwenden zu können, müssen wir die binären Daten rekonstruieren. Die meisten Programmiersprachen liefern hierfür eine fertige Funktion mit. Nun hängen wir den ersten Block und den konvertierten zweiten Block aneinander, und verwenden dies als Inhalt des Streamobjekts. ''/Length1'' setzen wir auf die Länge des ersten Blocks, ''/Length2'' auf die Länge des konvertierten zweiten Blocks, und ''/Length3'' auf 0.