Schriftsystem (NFSS / Codierung)

Die Zeichenfolge OT1/cmr/m/n/10 in einer LaTeX-Warnung ist kein Rätsel, sondern eine Adresse. LaTeX benennt eine Schrift nie direkt, sondern zeigt mit fünf Koordinaten auf sie: Kodierung, Familie, Serie, Form, Größe. Dieses Verfahren heißt NFSS. Diese Seite verfolgt die fünf Koordinaten bis in den Quelltext und die Logdatei: warum \bfseries die Serie bx und nicht b anfordert, ob nach \fontseries{c} ein Fettbefehl tatsächlich bei bc landet, und was die Ersetzungswarnung Font shape ... undefined wirklich mitteilt.

NFSS: Eine Schrift ist fünf Koordinaten

Die Schriftauswahl in LaTeX2e läuft über das NFSS (New Font Selection Scheme), dessen zentrale These lautet: Jede Textschrift ist vollständig durch fünf Attribute bestimmtKodierung, Familie, Serie, Form, Größe. Entworfen wurde NFSS von Frank Mittelbach und Rainer Schöpf; der Copyright-Vermerk der Kernelquelle ltfssbas.dtx reicht bis 1989 zurück. Davor, in LaTeX 2.09, ließen sich \bf und \it nicht einmal kombinieren – Stärke und Buchstabenform waren noch nicht als unabhängige Achsen gedacht.

  • Kodierung — die Reihenfolge der Glyphen in der Schrift, also welchem Slot jedes Eingabezeichen zugeordnet wird. Für Text sind OT1 (TeX text) und T1 (TeX extended text, das Cork-Encoding) maßgeblich. Details weiter unten.
  • Familie — eine Gruppe von Schriften mit gemeinsamer Buchstabenform. Computer Modern Roman ist cmr, die Serifenlose cmss, die Schreibmaschine cmtt; bei den kommerziellen Schriften Times ptm, Helvetica phv, Courier pcr.
  • Serie — eine einzige Achse, die Stärke und Breite zusammenfasst: m (medium), b (bold), bx (bold extended), c (condensed), bc (bold condensed), sb (semibold) und so weiter.
  • Form — die Gestalt der Buchstaben: n (aufrecht), it (kursiv), sl (geneigt), sc (Kapitälchen). Selten auch ui, eine Kursive ohne Neigung.
  • Größe — die Entwurfsgröße, eine Dimension wie 10pt; ohne Einheit wird pt angenommen.

Die einzige Stelle, an der man hängen bleibt, ist die Verschmelzung von Stärke und Breite zu einem Serienwert. Im Standardschema reichen die Stärken von ul bis ub (ultra light bis ultra bold), die Breiten von uc bis ux (ultra condensed bis ultra expanded); beide werden verkettet, wobei m entfällt – außer wenn Stärke und Breite beide medium sind, dann bleibt ein einzelnes m. Also heißt „fett, normale Breite“ b, „bold extended“ bx, „normale Stärke, schmal“ c und „fett schmal“ bc. Die fünf Werte, geschrieben als encoding/family/series/shape/size, sind der formale Schriftname in LaTeX; \showthe\font gibt den jeweils aktuellen aus.

log
% \showthe\font in a default article, and what the log answers:
> \OT1/cmr/m/n/10 .

% the same five values head every overfull-box report:
Overfull \hbox (121.83368pt too wide) detected at line 3
\OT1/cmr/m/n/10 Supercalifragilisticexpialidocious

% and the first four of them name a shape that had to be substituted:
LaTeX Font Warning: Font shape `T1/cmss/bx/sc' undefined
(Font)              using `T1/cmss/bx/n' instead on input line 4.

Warum \bfseries die Serie bx verlangt und nicht b

Die Antwort lautet: \bfseries liest \bfdefault überhaupt nicht. Das \bfdefault des Kernels ist tatsächlich b, doch \bfseries prüft zuerst, ob die aktuelle Familie mit \rmdefault, \sfdefault oder \ttdefault übereinstimmt; trifft das zu, verwendet es stattdessen einen eigenen Standardwert: \bfseries@rm, \bfseries@sf oder \bfseries@tt. Und latex.ltx initialisiert alle drei mit bx. \bfdefault kommt nur zum Zug, wenn die aktuelle Familie keiner der drei entspricht – solange also \bfseries in der Grundschrift steht, wird \bfdefault schlicht übergangen.

latex.ltx
% TeX Live 2024, latex.ltx (the LaTeX2e kernel), abridged
\def\bfseries@rm{bx}
\def\bfseries@sf{bx}
\def\bfseries@tt{bx}

\DeclareRobustCommand\bfseries{%
  \not@math@alphabet\bfseries\mathbf
  \expand@font@defaults
  \maybe@update@bfseries@defaults
  \ifx\f@family\rmdef@ult      \fontseries\bfseries@rm
  \else\ifx\f@family\sfdef@ult \fontseries\bfseries@sf
  \else\ifx\f@family\ttdef@ult \fontseries\bfseries@tt
  \else                        \fontseries\bfdefault
  \fi\fi\fi
  \UseHook{bfseries}%
  \selectfont
}

Warum aber ist bx die Vorgabe? Weil es darauf ankommt, wie viele Schnitte Knuth tatsächlich geschnitten hat. Zählt man die Computer-Modern-Metriken in TeX Live 2024, so existiert das schlichte Fett als genau eine Datei, cmb10.tfm. Bold extended dagegen gibt es als cmbx5, cmbx6, cmbx7, cmbx8, cmbx9, cmbx10 und cmbx12 – sieben Entwurfsgrößen. Nur cmbx kann Fettes bis hinunter zu Fußnoten und Indizes ordentlich setzen, also verlangt NFSS bei Computer Modern bx.

So weit ist das eine Eigenheit von Computer Modern, doch der Kernel räumt hinter sich auf. Bei \begin{document} läuft \init@series@setup und setzt \bfseries@rm auf b herab, sofern \rmdefault nicht zu cmr, cmss, cmtt, lcmss, lcmtt, lmr, lmss, lmtt gehört. bx ist also ein Erbe allein von Computer Modern und Latin Modern: Sobald auf Times oder TeX Gyre umgestellt wird, verlangt \bfseries still und leise b. Die Messung bestätigt es: Mit \renewcommand\rmdefault{ptm} liefern sowohl \bfseries@rm als auch die resultierende Serie b.

Einstellung im DokumentVon \bfseries verlangte SerieGrund
article (default)bx\rmdefault ist cmr, der Anfangswert von \bfseries@rm bleibt erhalten
\usepackage{lmodern}bxlmr steht ebenfalls auf der Computer-Modern-Liste des Kernels
\renewcommand\rmdefault{ptm}b\init@series@setup erkennt es als nicht gelistet und senkt \bfseries@rm
\fontseries{b}\selectfontbein direkt angegebener Wert läuft nicht über die Standardmakros
\DeclareFontSeriesDefault[rm]{bf}{sb}sbder vorgesehene Weg, nur das Fett einer Meta-Familie umzustellen

Die praktische Folgerung ist eindeutig: Wer ändern will, was fett bedeutet, greift besser zu \DeclareFontSeriesDefault[rm]{bf}{b} als zu \renewcommand{\bfdefault}{b}. Letzteres funktioniert zwar – wird \bfdefault umgeschrieben, überschreibt \maybe@update@bfseries@defaults alle drei eigenen Standardwerte –, kann aber weder die Roman- noch die Serifenlose allein ansprechen. Und beim klassischen Symptom „fett angefordert, nichts wurde fett“ ist genau diese Übereinstimmung der erste Verdacht: Vielleicht hat die Schrift schlicht kein bx.

Serienwerte verschmelzen: c plus b ergibt bc

Seit dem LaTeX2e-Release von 2020 (\IncludeInRelease{2020/02/02} in latexrelease.sty) verschmilzt eine Serienanforderung, statt zu überschreiben. Wer im schmalen Schnitt (c) Fett anfordert, bekommt nicht b, sondern bc, fett schmal. Die Tabelle dahinter entsteht mit \DeclareFontSeriesChangeRule; der Kernel enthält über zweihundert Zeilen solcher Regeln. {c}{b}{bc}{} liest sich als „ist die aktuelle Serie c und wird b verlangt, gehe zu bc; kein Ersatz“.

latex.ltx
% the rule table (latex.ltx, from ltfssaxes.dtx), a handful of the 200-odd entries
\def\DeclareFontSeriesChangeRule#1#2#3#4{%
  \@namedef{series@#1@#2}{{#3}{#4}}}
\DeclareFontSeriesChangeRule {c}{b}{bc}{}     % condensed + bold      -> bc
\DeclareFontSeriesChangeRule {b}{c}{bc}{b}    % bold + condensed      -> bc, else b
\DeclareFontSeriesChangeRule {bx}{c}{bc}{bx}  % bold extended + cond. -> bc, else bx
\DeclareFontSeriesChangeRule {m}{b}{b}{bx}    % medium + bold         -> b,  else bx

Die Regeln greifen allerdings nicht bedingungslos. \selectfont verschmilzt zuerst ohne Ersetzung und prüft dann, ob die entstandene Kombination encoding/family/series/shape tatsächlich existiert; falls nicht, stellt es die alten Werte wieder her und wiederholt die Verschmelzung im Ersetzungsmodus. Computer Modern besitzt gar keinen schmalen Schnitt, daher warnt \fontseries{c}\selectfont und fällt auf m zurück, und ein anschließendes Fett kommt nur bis b – genau deshalb schließt man leicht, es finde gar keine Verschmelzung statt. Mit einer Familie, die wirklich einen schmalen Schnitt hat, funktionieren die Regeln. Helvetica (phv) liefert in T1 m, c, b und bc, das Beispiel unten zeigt es in echt.

document.tex
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{helvet}          % sets \sfdefault to phv
\begin{document}\makeatletter
\sffamily                    % -> phv/m   (Helvetica)
\fontseries{c}\selectfont    % -> phv/c   font file phvr8tn (Helvetica Narrow)
\bfseries                    % -> phv/bc  font file phvb8tn (Helvetica Bold Narrow)
\typeout{[series] \f@series\space -> \fontname\font}
\makeatother\end{document}

% [series] bc -> phvb8tn
%
% The same document with Computer Modern instead reports:
%   LaTeX Font Warning: Font shape `OT1/cmr/c/n' undefined
%   [series] m  (the condensed request was substituted away before bold arrived)

Low-Level-Selektoren und \selectfont

Low-Level-Selektoren setzen je ein Attribut: \fontencoding{T1}, \fontfamily{ptm}, \fontseries{b}, \fontshape{it}, \fontsize{12}{14}. Es gibt genau eine Regel – Setzen allein bewirkt nichts, bis \selectfont aufgerufen wird –, und der vorige Abschnitt zeigt den Grund. \fontseries schreibt den Wert nirgendwohin, sondern legt ihn auf eine Warteliste namens \delayed@f@adjustment; Verschmelzung, Existenzprüfung und Ersetzung erledigt \selectfont in einem Zug. Fehlt das \selectfont zwischen Einstellung und Text, wird dieser Text noch in der alten Schrift gesetzt.

document.tex
\documentclass{article}
\usepackage[T1]{fontenc}
\begin{document}
% Correct: set the attributes, commit with \selectfont, then the text
{\fontfamily{ptm}\fontseries{b}\selectfont Bold Times}

% Wrong: the words before \selectfont are still in the old font
{\fontfamily{ptm} Some \fontseries{b}\selectfont text.}

% \usefont gives four attributes at once and commits on the spot
{\usefont{T1}{ptm}{b}{it} Bold italic Times}

% Change only the size; reuse the current baselineskip
\makeatletter
{\fontsize{14}{\f@baselineskip}\selectfont Fourteen point}
\makeatother
\end{document}

Die Abkürzung, die vier der fünf Attribute auf einmal übergibt, ist \usefont{encoding}{family}{series}{shape}; die Größe wird aus dem aktuellen Wert übernommen, und die Änderung wird sofort wirksam. In einer Gruppe { } bleibt die Wirkung lokal. Das interne Makro \f@baselineskip als zweites Argument von \fontsize zu übergeben, ist das übliche Idiom, um die Schriftgröße ohne Änderung des Zeilenabstands zu wechseln (interne Makros nie umschreiben, aber ihren Wert auslesen und weiterreichen ist unbedenklich). Allerdings – all das schreibt man selten selbst. \textbf ruft nur \fontseries auf, \sffamily nur \fontfamily; auf die untere Ebene steigt man nur herab, um eine bestimmte Schrift zu benennen oder eine neue Schrift in eine Klasse oder ein Paket einzubinden.

Die Standardmakros: \rmdefault und Verwandte

Welche Familie \textrm oder \rmfamily wählt, ist nicht fest verdrahtet, sondern steckt in einem Makro. Es gibt drei – \rmdefault (Roman), \sfdefault (Serifenlos), \ttdefault (Schreibmaschine) – mit den Standardwerten cmr, cmss, cmtt in der article-Klasse. Zum Wechseln der Grundschrift schreibt man also diese Makros um, nicht die Befehle. Und wie der vorige Abschnitt zeigte, bestimmen diese drei Werte auch, was Fett anfordert; treffender betrachtet man sie daher nicht als Aliase, sondern als Schriftpolitik des Dokuments.

preamble.tex
% Re-point the three meta-families for the whole document
\renewcommand{\rmdefault}{ptm}  % roman   -> Times
\renewcommand{\sfdefault}{phv}  % sans    -> Helvetica
\renewcommand{\ttdefault}{pcr}  % mono    -> Courier

% The body font itself is these four (defaults: OT1, \rmdefault, m, n)
%   \encodingdefault \familydefault \seriesdefault \shapedefault
% and \familydefault points at \rmdefault, so the line above changes the body.

% Retarget bold and medium per meta-family (LaTeX2e 2020-02-02 and later)
\DeclareFontSeriesDefault[rm]{bf}{b}
\DeclareFontSeriesDefault[sf]{md}{l}

.fd-Dateien und \DeclareFontShape: wo Koordinaten auf echte Dateien treffen

Was die fünf Koordinaten mit echten Schriftdateien verbindet, ist die Schriftdefinitionsdatei (.fd). Ihr Name besteht aus der kleingeschriebenen Kodierung und der Familie – ot1cmr.fd für cmr in OT1, t1phv.fd für phv in T1 – und LaTeX lädt sie automatisch, sobald sie gebraucht wird. Wo sie liegt, verrät kpsewhich ot1cmr.fd. Darin steht eine \DeclareFontFamily-Zeile und danach je ein \DeclareFontShape pro Serien-Form-Kombination.

ot1cmr.fd
% TeX Live 2024, tex/latex/base/ot1cmr.fd (excerpt)
\DeclareFontFamily{OT1}{cmr}{\hyphenchar\font45 }
\DeclareFontShape{OT1}{cmr}{m}{n}%
     {<5><6><7><8><9><10><12>gen*cmr%
      <10.95>cmr10%
      <14.4>cmr12%
      <17.28><20.74><24.88>cmr17}{}
%%%%%%% bold series
\DeclareFontShape{OT1}{cmr}{b}{n}
     {%
      <5><6><7><8><9><10><10.95><12>%
      <14.4><17.28><20.74><24.88>cmb10%
      }{}
%%%%%%%% bold extended series
\DeclareFontShape{OT1}{cmr}{bx}{n}
   {%
      <5><6><7><8><9>gen*cmbx%
      <10><10.95>cmbx10%
      <12><14.4><17.28><20.74><24.88>cmbx12%
      }{}

Man liest sie, indem man den Größenbereichen in spitzen Klammern folgt. <5><6><7><8><9>gen*cmbx heißt: „bei 5 bis 9 Punkt die reale Schrift verwenden, deren Name aus Stamm plus Größe besteht (cmbx5, cmbx6, …)“; <12><14.4>...cmbx12 heißt: „ab 12 Punkt cmbx12 skalieren“. Der b-Block oben zeigt die zuvor beschriebene Ein-Schnitt-Lage: Jede Größe von 5 bis 24.88 Punkt ist gedehntes cmb10. Daneben gibt es ssub (stille Ersetzung) und sub (Ersetzung mit Warnung); t1phv.fd etwa enthält \DeclareFontShape{T1}{phv}{bx}{n}{<->ssub * phv/b/n}{} – Helvetica hat kein bx, also wird stillschweigend b geliefert.

Die Warnung Font shape ... undefined lesen

Diese Warnung ist ein Bericht: Diese Kombination stand nicht in der .fd, also wurde eigenmächtig die nächstbeste genommen. Sie erscheint stets zweizeilig – in der ersten Zeile die vier angeforderten Koordinaten, in der zweiten die tatsächlich verwendeten samt Eingabezeilennummer. Es ist kein Fehler, der Lauf endet also normal; das entstandene PDF entspricht nur nicht der Anforderung. In den Beispielen oben hat Computer Modern keinen schmalen Schnitt, also wurde aus c ein m, und T1/cmss besitzt keine Kapitälchen, also wurde aufrechtes n gesetzt.

log
% a missing shape inside a family that does exist
LaTeX Font Warning: Font shape `T1/cmss/bx/sc' undefined
(Font)              using `T1/cmss/bx/n' instead on input line 4.

% a family that does not exist at all: \DeclareFontSubstitution kicks in
LaTeX Font Warning: Font shape `T1/nosuchfont/m/n' undefined
(Font)              using `T1/cmr/m/n' instead on input line 4.

% and at the end of the run, the summary line that is easy to miss
LaTeX Font Warning: Some font shapes were not available, defaults substituted.

Es gibt nur drei Ursachen. (1) Die Schrift besitzt diesen Schnitt schlicht nicht – Helvetica hat keine Kursive, also springt sl ein. Was nicht da ist, lässt sich nicht herbeizaubern; also andere Schrift wählen oder den Ersatz akzeptieren. (2) Der Familienname ist falsch geschrieben – taucht in der zweiten Zeile cmr auf, hat die letzte Rückfallebene von \DeclareFontSubstitution gegriffen, meist wegen eines Tippfehlers oder eines vergessenen Pakets. (3) Die Kodierung passt nicht – etwa eine Anfrage in T1 an eine Familie, die nur eine OT1-.fd hat. Und die eine Zusammenfassungszeile am Ende, Some font shapes were not available, defaults substituted., überliest man leicht – steht sie da, ist irgendeine Passage in einer nicht gewählten Schrift gesetzt.

Schriftkodierungen: OT1, T1 und TU im Vergleich

Eine Schriftkodierung ist die Vereinbarung darüber, welchem Slot (Glyphen) der Schrift jedes Eingabezeichen zugeordnet wird. Sie ist das erste der fünf Attribute und das einzige ohne Autorenbefehl wie \textbf – das Umschalten ist Sache eines Pakets, nämlich fontenc. OT1 ist Knuths ursprüngliches 7-Bit-„TeX text“ (der Standard). Da nur 128 Zeichen Platz finden, entstehen é und ñ durch Zusammensetzen von Grundbuchstabe und Akzent (\accent), und genau diese Zusammensetzung sorgt dafür, dass akzentuierte Wörter nicht getrennt werden und beim Kopieren aus dem PDF verstümmelt herauskommen. T1 (TeX extended text, nach der TUG-Tagung 1990 in Cork auch Cork-Kodierung) ist eine 8-Bit-Kodierung mit 256 Glyphen, die jeden akzentuierten Buchstaben als eigenen Glyphen führt – womit beide Probleme auf einmal verschwinden.

Nichts zeigt besser, dass eine Kodierung nur eine Vereinbarung über die Slot-Reihenfolge ist, als das Pfundzeichen in OT1. OT1 besitzt keinen Slot für Sterling, also greift \textsterling in ot1enc.def auf den Dollar-Slot der kursiven Schrift zu (in Computer Modern steht dort das £). Und hat die aktuelle Schrift keine Neigung, wird zuvor auf \fontshape{ui} umgeschaltet – sonst käme allein das £ schräg heraus. Deshalb trägt die ui-Deklaration in ot1cmr.fd einen Warnkommentar: Diese Definition werde für LaTeXs \pounds gebraucht und dürfe nicht entfernt werden.

TU (TeX Unicode) erlaubt es, systeminstallierte OpenType-Schriften direkt über Unicode-Codepunkte anzusprechen, und ist der Standard unter XeLaTeX und LuaLaTeX. Es löste die älteren EU1 (für XeTeX) und EU2 (für LuaTeX) ab: Laut Änderungsprotokoll von fontspec kam TU in v2.5 am 30. Januar 2016 und wurde in v2.5c am 20. Januar 2017 zum Standard. In TeX Live 2024 finden sich die Zeichenketten EU1 und EU2 nirgends mehr in fontspec.sty. Daneben gibt es T2A (Kyrillisch), LGR (Griechisch) und TS1 (die Text-Companion-Kodierung: Währungs-, Copyright- und andere Textsymbole); für Mathematik OML (Mathematikkursiv), OMS (Mathematiksymbole) und OMX (große Mathematiksymbole). Die TS1-Symbolbefehle wanderten 2020 in den Kernel, weshalb das heutige Paket textcomp überhaupt keine Symbole mehr definiert – nachzulesen auf der Symbolseite.

KodierungAbdeckungBreite / Hinweise
OT1Knuths ursprüngliches TeX text (Standard)7 Bit; Akzente zusammengesetzt, daher keine Trennung
T1TeX extended text (Cork); westliche Sprachen8 Bit, 256 Glyphen; Akzente einzeln, Trennung funktioniert
TUTeX Unicode; OpenType-Schriften direkt adressiertStandard bei Xe/LuaLaTeX; ersetzte EU1 / EU2
T2AKyrillisch8 Bit (T2B / T2C gehören dazu)
LGRGriechischDie heute für Griechisch übliche 256-Glyphen-Kodierung
TS1Text Companion (Textsymbole)Währung, Copyright usw.; die Befehle wanderten 2020 in den Kernel
OML / OMS / OMXMathematikkursiv / Mathematiksymbole / große MathematiksymboleNur für Mathematik, nie für Fließtext

inputenc und fontenc: der Weg hinein und hinaus

Zwei leicht verwechselbare Dinge, sauber getrennt. Die Eingabekodierung regelt, wie die Bytes der .tex-Quelle als Zeichen gelesen werden (UTF-8 und Verwandtes) – historisch Aufgabe des Pakets inputenc. Die Schriftkodierung regelt, in welchen Glyphen der Ausgabeschrift diese Zeichen fließen, und ist Aufgabe von fontenc. Merkt man sich Weg hinein (inputenc), Weg hinaus (fontenc), verwechselt man sie nicht mehr. Modernes pdfLaTeX liest die Quelle standardmäßig als UTF-8, inputenc muss also kaum noch ausdrücklich geladen werden. Die Schriftkodierung zu setzen lohnt dagegen weiterhin. fontenc ist ein Paket für pdfLaTeX; unter XeLaTeX und LuaLaTeX nutzt man fontspec, und da dort TU Standard ist, stellt sich das Problem kaum.

Unter pdfLaTeX \usepackage[T1]{fontenc} schreiben

Wer mit pdfLaTeX setzt, schreibt üblicherweise \usepackage[T1]{fontenc} in die Präambel. Das stellt die Schriftkodierung des Dokuments auf T1 und beseitigt die Nachteile der OT1-Vorgabe: akzentuierte Wörter, die nicht getrennt werden, und Text, der beim Kopieren aus dem PDF verstümmelt. Die fontenc-Dokumentation sagt genau das: Sie unterstützt verbreitete westliche Sprachen wie Französisch, Deutsch, Italienisch und Polnisch, und damit trennt LaTeX auch Wörter mit Akzentbuchstaben, während sich die Ausgabe kopieren lässt. Werden mehrere Kodierungen als Optionen aufgeführt, wird die zuletzt genannte zur Voreinstellung (\encodingdefault wird darauf gesetzt) – für ein Dokument mit griechischen Einschüben also \usepackage[LGR,T1]{fontenc}: Der Grundtext bleibt T1, nur wo nötig wird auf LGR umgeschaltet.

document.tex
\documentclass{article}
\usepackage[T1]{fontenc}   % font encoding -> T1 (Cork)
% Input is UTF-8 by default on pdfLaTeX, so inputenc is usually unneeded.
\begin{document}
% With T1 these words hyphenate and survive copy-and-paste out of the PDF.
Na\"ive r\"esum\"e, \"uberfl\"ussig, Stra\ss{}e.
\end{document}