Direktzugriff

Diese Methode funktioniert mit allen TrueType/OpenType Schriften, ist aber natürlich mit mehr Aufwand verbunden.

Aus der Schrift müssen wir für alle Unicode-Nummern die GID und Schriftbreite ermitteln. Zudem müssen wir eine umgekehrte Tabelle von den GIDs auf die Unicode-Nummern erstellen (zumindest, wenn wir den ToUnicode-Stream befüllen wollen). Die GID 0 kann man dabei ignorieren. Ist eine GID mehreren Unicode-Nummern zugeordnet, so sollte man die Kleinste nehmen.

das Teilschriftobjekt

Im Eintrag /W müssen die Zeichenbreiten nach GID sortiert angegeben werden.

Es gibt keinen Eintrag /CIDToGIDMap.

der Schriftstream

Bei OpenType Type1 und OpenType CID wird /Subtype auf /CIDType0C gesezt.

der ToUnicode Stream

Grundlagen

Mit dem ToUnicode Stream teilen wir dem PDF Interpreter mit, wie er von den GIDs in den Strings auf Unicode-Nummern kommen soll. Hierfür werden mehrere Segmente von GIDs definiert, und die Unicodes der GIDs in diesem Segment angegeben. Für die Segmente gelten folgende Regeln:

  1. GIDs, zu denen wir den Unicode nicht wissen, sollten in keinem Segment sein.
  2. GIDs und Unicodenummern werden in Big-Endian Anordnung notiert.
  3. Das jeweils erste Byte der ersten und der letzten GID eines Segments muss identisch sein.

Punkt 3 der Liste bedeutet, dass wir zum Beispiel ein Segment 0x1000 - 0x10A0 definieren können, aber nicht ein Segment 0x10A0 - 0x1110. Dies zu ignorieren ist einer der häufigsten Fehler.

Es gibt zwei Arten von Segmenten: Mit analogen oder nicht-analogen Unicode-Nummern. „Analog“ bedeutet in diesem Fall, dass die Unicode-Nummern gleich wie die GIDs ansteigen. Ein Beispiel wäre ein GID Segment 0x1000 - 0x10A0 mit Unicode-Nummern 0x2030 - 0x20D0. Leider muss hier auch das erste Byte der ersten und der letzten Unicode-Nummer identisch sein. Ein Segment mit Unicode-Nummern 0x20A0 - 0x2140 können wir also nicht definieren, sondern wir müssen dies auf zwei Segmente aufteilen.

Jeweils bis zu 100 Segmente werden zu einem Segmentblock zusammengefasst. Es können beliebig viele Segmentblocks verwendet werden.

Neben den Segmenten können auch Zuweisungen für einzelne GIDs definiert werden. Das macht Sinn, wenn ein Segment ansonsten aus einem einzelnen Eintrag bestehen würde. Jeweils bis zu 100 Einzelzuweisungen werden zu einem Block zusammengefasst. Es können beliebig viele Einzelzuweisungsblocks verwendet werden.

Streaminhalt

Der ToUnicode-Stream beginnt immer mit folgenden Zeilen:

/CIDInit /ProcSet findresource begin
12 dict begin
begincmap

Daraufhin folgt eine Zeile, welche die GID-Anordnung der Schrift eindeutig benennt. Es gibt verschiedene Arten, dies zu formulieren, aber eine gängige Methode geht so:

/CIDSystemInfo << /Registry (FontSpecific) /Ordering (Schriftname) /Supplement 0 >> def

Wobei Schriftname identisch zu /BaseFont gesetzt werden sollte (aber als String, nicht als Namenobjekt). Direkt danach folgt eine Zeile, welche der ToUnicode Definition einen eindeutigen Namen gibt. Diese kann man zum Beispiel so setzen:

/CMapName /FontSpecific-Schriftname def

Wenn wir also zum Beispiel eine Schrift „MyFont“ haben, so sieht dies so aus:

/CIDSystemInfo << /Registry (FontSpecific) /Ordering (MyFont) /Supplement 0 >> def
/CMapName /FontSpecific-MyFont def

Nun folgen immer folgende Zeilen:

/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange

Danach kommen nacheinander die Einzelzuweisungsblocks und Segmentblocks. Die Reihenfolge ist egal.

Jeder Einzelzuweisungsblock beginnt mit folgender Zeile:

x beginbfchar

Wobei x die Anzahl Zuweisungen innerhalb des Blocks ist. Der Block endet mit der Zeile:

endbfchar

Innerhalb des Zuweisungsblocks schreibt man für jede Zuweisung eine Zeile. Auf diese Zeile kommen zwei durch einen Leerschlag getrennte Einträge. Der erste Eintrag ist die GID als Hexstring, der zweite Eintrag die Unicode-Nummer als Hexstring. Da sowohl GIDs wie auch Unicode-Nummern in einer 2-Byte Kodierung sind, braucht es immer 4 Hexziffern.

Beispiel:

1 beginbfchar
<0003> <0020>
endbfchar

Die GID 3 zeigt also auf die Unicode-Nummer 0x20.

Segmentblocks sind ähnlich aufgebaut. Sie beginnen mit folgender Zeile:

x beginbfrange

Wobei x die Anzahl Segmente innerhalb des Blocks ist. Der Block endet mit einer Zeile:

endbfrange

Innerhalb des Segmentblocks schreibt man für jedes Segment eine Zeile. Auf diese Zeile kommen drei durch Leerschläge getrennte Einträge.

Der erste Eintrag ist die erste GID des Segments als Hexstring. Der zweite Eintrag ist die letzte GID des Segments als Hexstring. Der dritte Eintrag ist entweder ein Array mit Unicode-Nummern (falls nicht-analog) oder die Unicode-Nummer der ersten GID (falls analog).

Auch hier gilt: Da GID und Unicode-Nummern mit 2 Bytes kodiert sind, braucht es immer 4 Hexziffern.

Beispiel:

2 beginbfrange
<0010> <00A0> <2030>
<10B0> <10B3> [<2040> <2050> <2060> <2070>]
endbfrange

Das heisst, dass im GID-Segment 0x0010 - 0x00A0 die Unicode-Nummern von 0x2030 nach 0x20C0 aufsteigen, während im GID-Segment 0x10B0 - 0x10B3 die Unicode-Nummern nacheinander 0x2040, 0x2050, 0x2060 und 0x2070 sind.

Nachdem alle Blöcke definiert sind, kommen noch fix folgende Zeilen:

endcmap
CMapName currentdict /CMap defineresource pop
end
end

Das gesamte Beispiel:

/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (FontSpecific) /Ordering (MyFont) /Supplement 0 >> def
/CMapName /FontSpecific-MyFont def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
1 beginbfchar
<0003> <0020>
endbfchar
2 beginbfrange
<0010> <00A0> <2030>
<10B0> <10B3> [<2040> <2050> <2060> <2070>]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end