Voller Zeichenzugriff

Mit den Schriftobjekten, so wie wir sie kennen, können wir mit nichtsymbolischen Schriften Texte in „Windows westlich“ setzen. Was aber, wenn wir Zeichen aus anderen Zeichensätzen benötigen? Das Schriftobjekt kennt zwar zusätzliche Parameter, mit der andere Kodierungen definiert werden können. Die Möglichkeiten sind aber eingeschränkt, und funktionieren bei TrueType-Schriften nur halbwegs. Zudem wären wir nach wie vor auf 256 Zeichen beschränkt.

Im Zeitalter von Unicode mit seinen über 100'000 Zeichen ist dies nicht mehr zeitgemäss. TrueType/OpenType Schriften können bis zu 65'536 Zeichen enthalten, und so zumindest einen grossen Teil von Unicode abdecken. Glücklichlicherweise enthält der PDF Standard ein alternatives Schriftsystem, welches uns Zugriff auf den vollen Zeichenumfang einer Schrift gibt, nämlich das Kompositschriftsystem. Unglücklicherweise war dieses System ursprünglich für Postscript Kompositschriften vorgesehen, die inzwischen praktisch verschwunden sind. Dementsprechend sind wir mit einigen Seltsamheiten konfrontiert.

Als Lohn der Mühe wartet aber nicht nur die Möglichkeit, die Schriften voll auszunutzen. Wir können damit auch OpenType CID Schriften einbinden. Diesen Schrifttyp habe ich bisher nicht beschrieben, weil er sich leider nur über Kompositschriftobjekte einbinden lässt.

Unicode in Metadaten und Inhaltsverzeichnis

Bevor wir zur Einbindung und Verwendung der Schriften kommen: In den Metadaten und im Inhaltsverzeichnis können die Texte ganz einfach mit UTF-16BE statt PDFDoc kodiert abgelegt werden. Um den Text als UTF-16BE zu markieren, muss das Unicodezeichen 0xFEFF am Anfang eingefügt werden. Dieses Zeichen (BOM) ist als „Leerzeichen mit Breite 0“ definiert, und wird normalerweise verwendet, um zwischen UTF-16LE und UTF-16BE zu unterscheiden. In PDFDoc entspricht es der Zeichenkombination „þÿ“, deren Auftreten unwahrscheinlich ist.

Am einfachsten ist es wohl, solche Texte als Hexstring einzusetzen. Wie in den Grundlagen unter Platz sparen erläutert, können die Texte aber auch mit normalen Strings eingesetzt werden, sofern man an der richtigen Stelle mit Backslashes, \n oder \r arbeitet. Dabei braucht man sich keine Sorgen zu machen, dass dies die Kodierung durcheinanderbringt: Die zusätzlichen Codes werden entfernt bzw. ersetzt, bevor der Text als UTF-16BE interpretiert wird.

Unicode und direkter Zugriff

Das Kompositschriftsystem ist recht flexibel, und es gibt sehr viele verschiedene Möglichkeiten, wie genau wir die Schriften einbinden wollen. Davon sind zwei aber besonders verbreitet: Die Unicodemethode und der Direktzugriff.

Bei der Unicodemethode wird die Schrift so eingebunden, dass wir die Texte in Unicode nach UCS-2 (Big Endian) angeben können. Das ist recht bequem, aber mit ein paar Nachteilen verbunden. Erstens funktioniert diese Methode nur mit TrueType Schriften (nicht mit OpenType Type1 oder CID). Zweitens können wir keine Zeichen mit Unicode-Nummern grösser 65535 ansprechen. Drittens haben wir keinen Zugriff auf die in vielen Schriften enthaltenen Alternativzeichen und Ligaturen.

Beim Direktzugriff wird die Schrift so eingebunden, dass wir die Texte als Liste von GIDs angeben müssen. Die Textsatzanweisungen (Tj usw.) bekommen dabei einen binären String, in dem für jedes darzustellende Zeichen die entsprechende GID als uint16 in Big Endian Anordnung enthalten ist. Das ist natürlich eine ganze Ecke komplizierter. Dafür unterliegt diese Methode keiner der beim Unicodezugriff aufgezählten Einschränkungen.

Komposit- und Teilschriftobjekt

Anstelle eines einzelnen Schriftobjektes haben wir bei diesem System deren zwei: Ein Kompositschriftobjekt und ein Teilschriftobjekt. Das ist ein Überbleibsel von den Postscript Kompositschriften. Diese waren nämlich über mehrere Dateien verteilt, und für jede Datei brauchte es ein Teilschriftobjekt. Vor derartigen Basteleien bleiben wir zum Glück verschont.

das Kompositschriftobjekt

Dieses Objekt ist ähnlich aufgebaut, wie das normale Schriftobjekt. Es handelt sich um ein Dictionary mit folgenden Einträgen:

/Type immer /Font
/Subtype immer /Type0
/BaseFont Name der Schrift
/Encoding immer /Identity-H
/DescendantFonts Array mit Referenz auf das Teilschriftobjekt
/ToUnicode Referenz auf das ToUnicode Programm

Der /Subtype ist hier immer /Type0. Dabei ist egal, ob es sich um eine TrueType, eine Type1 oder eine CID Schrift handelt.

/DescendantFonts muss ein Array mit genau einem Eintrag sein, welcher auf das Teilschriftobjekt verweist.

Der /ToUnicode Eintrag ist etwas spezieller. Es handelt sich um eine Referenz auf einen Stream. Dieser Stream enthält eine Definition, ob und wie die in den Strings enthaltenen Zeichencodes in Unicodes umgewandelt werden müssen. Dementsprechend ist die Definition abhängig von der verwendeten Methode, und darum in den Unterkapiteln erklärt. Der Eintrag kann weggelassen werden. In diesem Fall sind aber im PDF die Volltextsuche sowie Copy&Paste von Texten nicht möglich.

Die Zeichenbreiten und die Referenz auf das Deskriptorobjekt sind hier nicht enthalten. Diese befinden sich im Teilschriftobjekt.

das Teilschriftobjekt

Auch das Teilschriftobjekt ähnelt dem normalen Schriftobjekt:

/Type immer /Font
/Subtype technischer Typus der Schrift
/BaseFont Name der Schrift
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/DW Standardzeichenbreite
/W Zeichenbreiten
/FontDescriptor Referenz auf das Schriftdeskriptorobjekt
/CIDToGIDMap GID-Tabelle für Unicode-Methode

Der technische Typus ist hier /CIDFontType2 für TrueType oder /CIDFontType0 für Type1 oder CID.

Für /CIDSytemInfo habe ich hier einen Standardwert angegeben, der eigentlich immer verwendet werden kann. Bei OpenType CID ist es aber empfehlenswert, diesen Eintrag individuell anhand der Schrift zu setzen.

Die /CIDToGIDMap wird nur für die Unicode-Methode benötigt, und ist dort erklärt.

Mittels der Einträge /DW und /W werden die Zeichenbreiten hinterlegt. Um Platz zu sparen, wurde dabei ein anderes Format gewählt, als bei den normalen Schriften. Ähnlich wie beim cmap-Block ist die Grundidee, dass die Zeichen in Segmente aufgeteilt werden. Die Segmente können mit einer gemeinsamen Zeichenbreite oder individuellen Zeichenbreiten bestückt werden. Zusätzlich gibt es eine Standardbreite, die für alle Zeichen ausserhalb dieser Segmente gilt. Die Zeichennummern für die Definition der Segmente sind dabei abhängig von der gewählten Methode: Bei der Unicodemethode sind es die Unicodenummern, beim Direktzugriff hingegen die GIDs.

/DW hat als Wert eine Ganzzahl, welche die Standardzeichenbreite festlegt. Typischerweise setzt man die Breite der GID 0 ein, da dies das Zeichen ist, welches gedruckt wird, wenn man versucht, ein nicht in der Schrift vorhandenes Zeichen zu drucken.

/W hat als Wert ein Array mit den Segmenten. Ein Segment mit gleichmässiger Zeichenbreite wird dabei definiert, indem drei Ganzzahlen geschrieben werden: Das erste Zeichen des Segments, das letzte Zeichen des Segments, und die Zeichenbreite der Zeichen im Segment. Ein Segment mit unregelmässigen Zeichenbreiten wird definiert, indem eine Zahl gefolgt von einem Unterarray geschrieben wird. Die Zahl bezeichnet das erste Zeichen des Segments, das Unterarray enthält nacheinander die Zeichenbreiten der Zeichen des Segments.

Beispiel:

/DW 500
/W [32 255 300 256 [600 700 300 400 800]]

Damit ist der Bereich 32 - 255 auf eine Breite von 300 festgelegt, die Zeichen 256 - 260 haben nacheinander die Breiten 600, 700, 300, 400 und 800, alle anderen Zeichen haben die Breite 500.

Bei Fixbreitenschriften kann man auch auf den /W Eintrag verzichten. In dem Fall gilt der /DW Eintrag für alle Zeichen.

Schriftdeskriptorobjekt und Schriftstream

Das Schriftdeskriptorobjekt wird genau gleich geschrieben, wie bisher. Beim Schriftstream gibt es aber einen Unterschied bei OpenType Type1 und OpenType CID: Der Eintrag /Subtype muss auf /CIDType0C gesetzt werden (statt /Type1C).

Textsatz

Für den eigentlichen Textsatz verwenden wir wie gehabt die Tj, TJ oder ' Anweisung. Der String (bzw. bei TJ die Strings) enthalten weiterhin den darzustellenden Text, aber natürlich nicht in der „Windows westlich“ Kodierung. Bei der Unicodemethode muss der Text mit UCS-2 in der Big-Endian Variante abgelegt sein (ohne 0xFEFF am Anfang). Beim Direktzugriff enthalten die Strings eine Abfolge der GIDs der darzustellenden Zeichen, wobei diese jeweils als uint16 in Big-Endian Anordnung geschrieben werden müssen.

Auch hier gilt, dass man am Einfachsten Hexstrings nimmt, aber alternativ wie unter Platz sparen erwähnt auch normale Strings verwenden kann, solange man korrekt Backslashes, \n und \r setzt.

Eine Schwierigkeit gibt es noch bei Blocksatz. Die Tw Anweisung funktioniert bei über das Kompositschriftsystem eingebundenen Schriften leider nicht (die Tc Anweisung hingegen schon). Wir können aber die unter Unterschneidung beschriebene TJ Anweisung verwenden, um die Leerschläge zu verbreitern. Nicht vergessen: Bei TJ muss die Angabe in Promille der Schriftgrösse gemacht werden, und für die Verbreiterung eines Abstands braucht es eine negative Zahl.

Diskussion

Geben Sie Ihren Kommentar ein. Wiki-Syntax ist zugelassen:
D M A M Q
 
typographie/vollzugriff/start.txt · Zuletzt geändert: 2013/06/23 22:57 (Externe Bearbeitung)
 
Falls nicht anders bezeichnet, ist der Inhalt dieses Wikis unter der folgenden Lizenz veröffentlicht: CC0 1.0 Universal
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki