Zum Inhalt springen

Schriften: der schwierige Teil

Evidence: Mixed evidence

Schriften sind der Bereich, in dem ein PDF völlig korrekt aussehen und dennoch unbemerkt defekt sein kann. Eine Seite kann die richtigen Glyphen darstellen und trotzdem nicht durchsuchbar, nicht als Text kopierbar und nicht konform mit einem Archivierungsprofil sein. All das kann gleichzeitig geschehen, ohne dass etwas Sichtbares Sie warnt. Auf dieser Seite geht es um die drei Dinge, die korrekt sein müssen — Einbettung, Subsetting, Kodierung — und darum, was NextPDF jeweils dafür leistet.

„Es sieht gut aus“ ist der gefährlichste Satz bei der Arbeit mit PDFs, und bei Schriften richtet er den größten Schaden an. Drei voneinander unabhängige Dinge müssen zutreffen:

  1. Einbettung — das Schriftprogramm reist in der Datei mit, sodass es auf einem Rechner, der die Schrift nicht installiert hat, gleich gerendert wird.
  2. Subsetting — nur die tatsächlich verwendeten Glyphen werden mitgeführt, sodass eine 20 MB große CJK-Schrift nicht jedes Dokument aufbläht.
  3. Kodierung — es gibt eine korrekte Zuordnung von den Zeichencodes auf der Seite zurück nach Unicode, sodass der Text durchsucht, kopiert, indiziert und von assistiver Technologie gelesen werden kann.

Die visuelle Darstellung belegt nur das Erste, und auch das nur teilweise. Ein Dokument kann perfekte Glyphen zeigen und dennoch das Dritte vollständig verfehlen — der Text ist dann nur ein Bild von Wörtern, keine Wörter. Das ist das Versagen, das jede „Sieht-gut-aus“-Prüfung besteht und dann ein Compliance-Audit oder eine Beweisanforderung scheitern lässt.

  • Eine Schrift in einem PDF ist ein Dictionary und in der Regel zusätzlich ein Stream mit einem eingebetteten Schriftprogramm.
  • Subsetting schreibt dieses Programm so um, dass es nur die verwendeten Glyphen enthält. Der Name einer Subset-Schrift erhält ein Tag aus sechs Großbuchstaben und ein +, damit Reader sie als eigenständig behandeln.
  • Kodierung ist das separate Problem, Zeichencodes nach Unicode abzubilden. Eine /ToUnicode-CMap ist das, was Text durchsuchbar und kopierbar macht — und sie ist unabhängig davon, ob die Glyphen richtig aussehen.
  • Richtig aussehender Text ohne (oder mit falscher) /ToUnicode ist das klassische stille Versagen: perfekt auf dem Bildschirm, in der Praxis aber nicht durchsuchbar.
  • NextPDF erstellt Subsets von TrueType-Schriften, bewahrt die Glyphenidentität für korrektes Rendering und gibt eine /ToUnicode-CMap aus, damit die Extraktion funktioniert — und kann die PDF-2.0-Einbettungsregel erzwingen, statt nur zu warnen.

Subsetting. FontSubsetter (src/Typography/FontSubsetter.php) parst das ursprüngliche TrueType-Tabellenverzeichnis und liest die cmap, um Unicode-Codepunkte auf Glyphen-IDs abzubilden. Es verarbeitet sowohl BMP-Format 4 als auch das vollständige Unicode-Format 12, das CJK benötigt. Anschließend führt es den Schritt aus, den naive Subsetter übersehen: Es löst Abhängigkeiten zusammengesetzter Glyphen auf, indem es ihre transitive Hülle bildet. Eine akzentuierte Glyphe, die aus einem Grundbuchstaben plus einem kombinierenden Zeichen aufgebaut ist, referenziert andere Glyphen als Komponenten. Werden diese Komponenten weggelassen, wird die Glyphe falsch gerendert. Der Subsetter durchläuft diesen Graphen, bis keine neue Komponente mehr auftaucht, mit einem Zyklusschutz, damit eine fehlerhafte Schrift nicht endlos in der Schleife hängen bleibt.

Zwei Entwurfsentscheidungen in dieser Datei sind erwähnenswert. Erstens werden Glyphen-IDs bewahrt, nicht neu zugeordnet — ungenutzte Slots werden in glyf/loca mit Nullen gefüllt, sodass die ursprünglichen Glyphenindizes des Content-Streams unter CIDToGIDMap /Identity gültig bleiben. Eine Neuzuordnung wäre kleiner, würde aber das Umschreiben jeder Glyphenreferenz erfordern. Diese Identitätsbewahrung ist konstruktionsbedingt korrekt. Zweitens ist die Traversierung sortiert (gid-aufsteigend), sodass das Subset byte-deterministisch ist — dieselbe Schrift und dieselben verwendeten Glyphen erzeugen dieselben Subset-Bytes, was für reproduzierbare Builds erforderlich ist. Wenn Subsetting weniger als ~10 % der Datei einsparen würde, wird das Original unverändert zurückgegeben. Der Mehraufwand ist einen marginalen Gewinn nicht wert.

Einbettung. Eine explizite Richtlinie entscheidet, ob ein Schriftprogramm überhaupt mitgeführt wird — niemals auf Verdacht. Pdf20FontEmbeddingPolicy (src/Writer/Pdf20FontEmbeddingPolicy.php) hat zwei Modi. Unter dem PDF-2.0-Profil lehnt Strict eine nicht eingebettete Standard-Type-1-Referenz („Base14“) mit einer typisierten Ausnahme ab — das aus Konformitätssicht korrekte Verhalten. AllowBase14 bewahrt den historischen Warnpfad. Als Migrationsfenster gibt es den minimalen Schriftdeskriptor aus, den der Standard weiterhin verlangt, und löst eine Warnung aus, statt eine Ausnahme zu werfen. Der Aufrufer trifft die Wahl explizit auf Dokumentebene; sie wird niemals aus der Schrift abgeleitet.

Kodierung. Für zusammengesetzte (Type-0-)Schriften gibt EmbeddedTtfFontDictBuilder (src/Writer/EmbeddedTtfFontDictBuilder.php) die CIDFontType2-Nachkommenschrift, das Type0-Elterndictionary und einen /ToUnicode-CMap-Stream aus, sodass Zeichencodes nach Unicode zurückaufgelöst werden. Der /ToUnicode-Stream darf nur in einem einzigen Fall legitim fehlen: wenn eine selbstbeschreibende vordefinierte CJK-CMap dem Reader bereits die Zeichen-zu-Unicode-Zuordnung liefert. Dort ist die CMap die Kodierung, sodass das einfache Profil einen redundanten /ToUnicode-Stream weglässt, um Bytes zu sparen. Außerhalb dieses Falls ist der /ToUnicode-Stream das, was Text Text bleiben lässt.

BelangWas es garantiertWas es nicht garantiertStilles Versagen, wenn falsch
EinbettungGleiches Rendering ohne installierte SchriftDass Text durchsuchbar istErsatzschrift; falsche Metriken auf einem anderen Rechner
SubsettingKleine Datei; nur verwendete GlyphenIrgendetwas zur KodierungFehlende zusammengesetzte Komponenten → defekte akzentuierte Glyphen
Kodierung (/ToUnicode)Durchsuchbarer, kopierbarer, barrierefreier TextDass Glyphen korrekt gerendert werdenPerfekt aussehende Seite, aber nicht durchsuchbar / beim Kopieren verstümmelt

Die drei Schriftbelange sind unabhängig voneinander. Bei Einbettung und Subsetting geht es um Erscheinungsbild und Größe; bei der Kodierung geht es um Bedeutung. Eine Seite kann die ersten beiden Anforderungen erfüllen und die dritte verfehlen, ohne dass etwas Sichtbares es anzeigt.

Die Subset-Benennungsregel ist normativ und präzise. Spec: ISO 32000-2, §9.9.2 verlangt, dass der PostScript-Name eines Schrift-Subsets — der BaseFont und der FontName des Deskriptors — mit einem Tag aus genau sechs Großbuchstaben beginnt, darauf ein Pluszeichen und anschließend der PostScript-Name der Originalschrift folgt. Sie verlangt außerdem, dass unterschiedliche Subsets derselben Schrift in einer Datei unterschiedliche Tags verwenden. Diese Regel ermöglicht es einem Reader, zwei Subsets auseinanderzuhalten und Dokumente korrekt zusammenzuführen. Evidence: Standard-backed

Kodierung ist von der Darstellung getrennt geregelt. Spec: ISO 32000-2, §9.10.3 definiert /ToUnicode als einen Stream, der eine CMap enthält, die Zeichencodes auf Unicode-Werte abbildet, und die Textextraktionsprozedur in Spec: ISO 32000-2, §9.10.2 verwendet diese CMap, um Zeichencodes für Suche und Indizierung nach Unicode zu konvertieren. Nichts in der Glyphen-Zeichen-Mechanik berührt /ToUnicode — genau deshalb kann Text richtig aussehen und dennoch falsch extrahiert werden.

Zur Einbettung legt der Standard fest, dass die meisten Schrift-Dictionaries einen Schriftdeskriptor enthalten, dessen eingebetteter Font-File-Stream optional, aber dringend empfohlen ist. PDF 2.0 verschärft dies speziell für die vierzehn Standard-Type-1-Schriften. Die Strict-Richtlinie von NextPDF ist die aus Konformitätssicht korrekte Auslegung dieser Verschärfung. AllowBase14 ist die explizite Opt-in-Ausnahme für Abwärtskompatibilität — die Engine nimmt niemals stillschweigend eine Herabstufung vor.

Strict PDF 2.0 font-embedding enforcement — edition availability
Edition Availability
Core

Verfügbar. Subsetting, /ToUnicode-Ausgabe und die explizite Strict- / AllowBase14-Einbettungsrichtlinie sind Verhalten der Kern-Engine.

Pro

Ergänzt auf Profilebene eine tiefere Konformitätsdurchsetzung und Berichterstattung rund um die Schrifteinbettung.

Enterprise

Ergänzt dieselbe Konformitätsdurchsetzung über die operative Enterprise- Oberfläche.

Hier sind die beiden Hälften einer korrekt eingebetteten, mit Subset versehenen, durchsuchbaren zusammengesetzten Schrift. Das Subset-Tag folgt der Sechs-Buchstaben-Regel des Standards; die /ToUnicode-Referenz ist das, was den Text extrahierbar hält.

% The Type 0 (composite) font dictionary
20 0 obj
<< /Type /Font /Subtype /Type0
/BaseFont /ABCDEF+NotoSans % six-letter subset tag + '+'
/Encoding /Identity-H
/DescendantFonts [21 0 R]
/ToUnicode 23 0 R >> % the map that makes text searchable
endobj
% The descendant CIDFontType2 (carries the subsetted program)
21 0 obj
<< /Type /Font /Subtype /CIDFontType2
/BaseFont /ABCDEF+NotoSans
/CIDToGIDMap /Identity % glyph IDs preserved, not remapped
/FontDescriptor 22 0 R >>
endobj

Das /ToUnicode 23 0 R in Objekt 20 ist der Unterschied zwischen einem durchsuchbaren Dokument und einem Bild davon. Wird es weggelassen (außerhalb des Falls einer vordefinierten CMap), wird jede Glyphe weiterhin perfekt gezeichnet, doch eine Suche nach einem beliebigen Wort auf der Seite findet nichts.

Die Falle, schlicht ausgedrückt: Dass Glyphen korrekt gerendert werden, sagt nichts darüber aus, ob Text tatsächlich Text ist. Das Rendering folgt dem Pfad von der Kodierung zur Glyphe. Suche und Kopieren folgen dem Pfad vom Code zu Unicode (/ToUnicode). Es sind unterschiedliche Mechanismen, die unterschiedliche Teile des Schrift-Dictionarys lesen. So kann ein Dokument eine makellose visuelle Ausgabe und eine fehlende oder falsche /ToUnicode haben. Das Ergebnis ist eine Seite, die verbindlich wirkt und funktional nicht durchsuchbar ist — das Versagen, das jede visuelle Prüfung übersteht, weil es per Definition nichts zu sehen gibt.

Eine verwandte Falle: anzunehmen, „die Schrift ist eingebettet, also sind wir für die Archivierung gerüstet.“ Einbettung ist notwendig, aber nicht hinreichend. Ein Profil wie PDF/A erwartet außerdem Subsets, die nach der Sechs-Buchstaben-Regel benannt sind, und eine korrekte Kodierung. Eine eingebettete Schrift ohne Durchsuchbarkeit scheitert dennoch.

Der Subsetter von NextPDF ist speziell ein TrueType-Subsetter. Er benötigt die wesentlichen TrueType-Tabellen und gibt die Originalschrift unverändert zurück, wenn sie fehlen oder der Gewinn unter der ~10-%-Schwelle liegt. Subsetting und eine /ToUnicode-CMap machen Text extrahierbar, können aber keine Quellschrift retten, der die Information fehlt, eine Glyphe auf ein bedeutungsvolles Zeichen zurückabzubilden. Wo kein Unicode-Wert ermittelt werden kann, erfindet auch keine CMap-Ausgabe einen.

Auf dieser Seite geht es darum, korrekte Schriftstrukturen in Dokumenten zu erzeugen, die NextPDF schreibt. Es ist kein Schriftreparatur-Werkzeug für beliebige eingehende PDFs. Und die Ausgabe eines konformen Subsets und einer konformen Kodierung zertifiziert ein Dokument nicht automatisch für ein vollständiges Archivierungsprofil — das ist eine separate, umfassendere Prüfung.

Warum das Sechs-Buchstaben-Tag — warum nicht der Schriftname? Damit ein Reader zwei unterschiedliche Subsets derselben Schrift auseinanderhalten und Dokumente zusammenführen kann, ohne dass ihre Glyphensätze kollidieren. Unterschiedliche Subsets verwenden unterschiedliche Tags; so schreibt es die Regel vor.

Wann ist es akzeptabel, keine /ToUnicode zu haben? Nur wenn eine selbstbeschreibende vordefinierte CJK-CMap die Zeichen-zu-Unicode-Zuordnung bereits bereitstellt. Dort ist die CMap die Kodierung. Eine separate /ToUnicode wäre redundant. In allen anderen Fällen ist ihr Fehlen ein Mangel.

Schadet Subsetting jemals? Nur, wenn es falsch gemacht wird. Das Weglassen von Komponenten zusammengesetzter Glyphen zerstört akzentuierte Glyphen. Das Neuzuordnen von Glyphen-IDs ohne Umschreiben der Referenzen zerstört das Rendering. NextPDF vermeidet beides, indem es die Komponentenhülle auflöst und die Glyphenidentität bewahrt.

  • Eingebettetes Schriftprogramm — die eigentliche Schriftdatei (TrueType/CFF/Type 1), die als Stream im PDF mitgeführt wird, sodass das Rendering nicht von den installierten Schriften des Readers abhängt.
  • Subsetting — das Umschreiben eines Schriftprogramms, sodass es nur die Glyphen enthält, die das Dokument verwendet, um die Größe zu reduzieren.
  • Subset-Tag — das obligatorische Präfix aus sechs Großbuchstaben plus + am Namen einer Subset-Schrift (zum Beispiel ABCDEF+NotoSans).
  • /ToUnicode — ein CMap-Stream, der Zeichencodes auf Unicode-Werte abbildet und PDF-Text durchsuchbar, kopierbar und barrierefrei macht.
  • Zusammengesetzte Glyphe — eine Glyphe, die durch Verweise auf andere Glyphen als Komponenten aufgebaut ist; ihre Komponenten müssen beim Subsetting erhalten bleiben.
  • CIDToGIDMap /Identity — der Modus, in dem die Glyphenindizes des Content-Streams unverändert den Glyphen-IDs der Schrift entsprechen; NextPDF bewahrt die Glyphenidentität, um dies gültig zu halten.
  • Base14 — die vierzehn Standard-Type-1-Schriften; PDF 2.0 erwartet, dass Schriften eingebettet und nicht nur namentlich referenziert werden.