Zum Inhalt springen
  • Rendering

Schriften in Headless Chromium: was Ihr PDF wirklich enthält

Das Template verlangt Segoe UI oder Inter, das PDF enthält stillschweigend Liberation Sans. Worauf ein Linux-Render-Server ausweicht, wie Sie prüfen, welche Schrift ein PDF eingebettet hat, was eine Google-Schrift beim ersten Rendern kostet und danach, und warum ein Häkchen aus einer dritten Schrift kommen kann.

Philipp Staudt

6 Min. Lesezeit

Eine Rechnungszeile, wie ihr PDF sie enthält, Bezahlt ✓ · Offen ✗ · Seite → 2, mit Häkchen und Kreuz als DejaVu Sans markiert und dem Pfeil als Liberation Sans. Darüber: Sie haben Inter verlangt. Ihr PDF enthält drei Schriften.

Im Editor sieht das Template richtig aus, dann kommt das PDF zurück, und der Text ist etwas breiter, etwas runder, und die Zeile, die eben noch passte, bricht um. Fehlgeschlagen ist nichts. Kein Fehler, keine Warnung, keine Logzeile. Das PDF enthält einfach eine andere Schrift als die, die das Template verlangt.

Das kann bei jedem HTML-zu-PDF-Dienst passieren, der Chromium auf einem Linux-Server betreibt, bei uns auch. Wir haben vier einzeilige Templates mit unserem Render-Worker gerendert (Chromium 153, das Image, das wir in Produktion betreiben) und ausgelesen, welche Schriften jedes PDF eingebettet hat.

Vier Textzeilen aus dem Render-Worker: die ersten beiden sehen gleich aus, die dritte ist in Inter gesetzt, die vierte mischt Inter mit anderen Schriften für Häkchen, Kreuz und Pfeil

Das Template sagt Das PDF enthält
font-family: "Segoe UI", Helvetica, sans-serif Liberation Sans
font-family: Inter, sans-serif, nichts geladen Liberation Sans
font-family: Inter, sans-serif, <link> zu Google Fonts Inter
dasselbe, Text mit ✓, ✗ und → Inter, DejaVu Sans für ✓ und ✗, Liberation Sans für →

Ein Schriftname ist ein Wunsch

font-family ist eine Liste von Namen, und der Browser nimmt den ersten, den er hat. Auf einem Windows-Laptop ist das Segoe UI. Ein Linux-Server hat weder Segoe UI noch Helvetica, also geht Chromium die Liste hinunter, landet bei sans-serif, und das System gibt ihm Liberation Sans. Das ist keine schlechte Schrift: Sie wurde mit den Breiten von Arial gebaut, eine für Arial gesetzte Zeile behält also ihre Länge. Es ist nur nicht die Schrift, die im Template steht.

Die zweite Zeile ist die, bei der man hängen bleibt. Inter sieht aus wie eine Schrift, die das Template hat. Auf dem Rechner der Designerin ist sie installiert, die Vorschau im Editor zeigt Inter, alle sind zufrieden. Der Server hat sie nicht, und nichts im Template sagt Chromium, woher er sie bekommt. Das PDF kommt in Liberation Sans, und die ersten beiden Zeilen im Bild sind dieselbe Zeile.

Die Abhilfe: Jede Schrift laden, die man nennt. Entweder ein <link> zu Google Fonts oder einem anderen Webfont-Dienst im Head des Templates, oder eine @font-face-Regel mit der Datei. Für eigene Schriften — eine lizenzierte Hausschrift — nimmt Formfeed die Dateien einmal pro Organisation unter Schriften entgegen und fügt die @font-face-Regel in jedes Rendering ein, das die Familie nennt, auch in Kopf- und Fußzeilen, deren eigenes Dokument das Stylesheet des Templates nie sieht (ab Starter).

Das PDF prüfen, nicht die Vorschau

Die Vorschau im Browser verwendet die Schriften Ihres Rechners, sie kann also nicht zeigen, was dem Server fehlt. Das PDF kann es. Es führt jede eingebettete Schrift auf:

  • pdffonts rechnung.pdf aus den poppler-utils gibt eine Zeile pro Schrift aus.
  • In Acrobat oder Acrobat Reader: Datei → Eigenschaften → Schriften.
  • Der PDF-Viewer von Chrome hat keine solche Liste; öffnen Sie die Datei in einem der obigen.

Die Namen haben ein Präfix aus sechs Buchstaben wie ABCDEF+Inter-Regular. Das heißt, das PDF enthält eine Teilmenge: nur die Zeichen, die das Dokument verwendet, damit es klein bleibt. Steht in der Liste LiberationSans, DejaVuSans oder NotoSans, obwohl Ihr Template etwas anderes nennt, wurde entweder eine Schrift nie geladen, oder einige Zeichen fehlten in ihr (dazu unten mehr).

Was eine Google-Schrift kostet

Der Worker muss eine Webschrift holen, bevor er drucken kann, und er wartet auf document.fonts.ready; eine Schrift, die noch nicht da ist, wird also nie übergangen. Das Holen kostet Zeit. Wir haben dreimal einen frischen Worker mit leerem Cache gestartet, eine schlichte Seite einmal zum Aufwärmen gedruckt und dreimal zum Messen, dann das Inter-Template einmal und danach noch dreimal. Der Worker meldet seine Renderzeit selbst.

Renderzeit (Median)
Seite ohne Webschriften 58 ms
Inter, erstes Rendering, leerer Cache 318 ms
Inter, jedes Rendering danach 72 ms

Das erste Rendering hat Googles Stylesheet und die Schriftdateien geholt; die folgenden fanden beides im Disk-Cache des Workers und kosteten 14 ms mehr als eine Seite ganz ohne Webschrift. In Produktion liegt dieser Cache auf einem Datenträger, der Neustarts und Deployments überdauert und eine Datei eine Woche behält, geholt wird also einmal pro Server und Woche, nicht einmal pro Dokument. Organisationsschriften kommen aus unserem eigenen Speicher und laufen durch denselben Cache.

Das sind die Zahlen eines Laptops in Deutschland, der mit Google spricht, ohne dass daneben etwas Schweres lief; neben drei laufenden Builds dauerten dieselben Läufe vier- bis fünfmal so lange, im selben Verhältnis. Es geht um das Muster, nicht um die Millisekunden. Ein Dienst ohne solchen Cache zahlt die erste Zeile bei jedem Rendering.

Ein Häkchen aus einer dritten Schrift

Die letzte Zeile ist die unauffälligste. Inter wurde geladen, die Wörter sind Inter, und trotzdem bettet das PDF drei Schriften ein. Die Inter-Dateien, die Google für diese Anfrage geliefert hat, enthalten kein ✓ und kein ✗, also hat Chromium jedes dieser Zeichen in den auf dem Server installierten Schriften gesucht und in DejaVu Sans gefunden; der Pfeil kam aus Liberation Sans. Sehen Sie aufs Bild: Das Häkchen ist kräftiger als die Buchstaben daneben, der Pfeil sitzt tiefer.

Chromium entscheidet das Zeichen für Zeichen, stillschweigend, und das Ergebnis hängt davon ab, was auf dem Server installiert ist — unser Image bringt DejaVu, Liberation und die Noto-Familien mit, leere Kästchen gibt es also nicht, aber durchaus ein anderes Design. Drei Auswege:

  • Eine Schrift wählen, die die verwendeten Symbole hat, und sie laden.
  • Eine zweite Schrift nur für die Symbole laden (etwa Noto Sans Symbols 2) und sie nach der Textschrift nennen: font-family: Inter, "Noto Sans Symbols 2", sans-serif.
  • Statuszeichen als Inline-SVG zeichnen, über das keine Schrift entscheidet.

Kurz gesagt

  • Nur Schriften nennen, die man lädt, und jede Schrift laden, die man nennt.
  • Die Schriftenliste des PDFs lesen, nicht das Aussehen der Vorschau.
  • Das erste Rendering mit einer Webschrift ist langsamer; danach sollte ein Cache es kostenlos machen.
  • Symbole fallen Zeichen für Zeichen zurück. Wenn es auf sie ankommt, eine Schrift mitbringen, die sie hat.

Die vier PDFs zum Selbstprüfen: Segoe UI, Inter nicht geladen, Inter von Google Fonts, mit Symbolen. Die Dokumentation beschreibt Schriften in Templates und das Brand Kit, dessen Überschrift- und Textschrift jedes Template als CSS-Variablen erreicht.

Heute mit dem Rendern beginnen

Der kostenlose Plan enthält 100 Einheiten im Monat und kostenlose Testrenderings. Wechseln Sie den Plan, wenn Sie mehr brauchen.