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.
Im Eintrag /W
müssen die Zeichenbreiten nach GID sortiert angegeben werden.
Es gibt keinen Eintrag /CIDToGIDMap
.
Bei OpenType Type1 und OpenType CID wird /Subtype
auf /CIDType0C
gesezt.
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:
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.
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
Diskussion