fontspec (Xe/Lua)

Le même préambule de trois lignes passe sous LuaLaTeX et s’arrête sous XeLaTeX sur ! Package fontspec Error: The font "TeX Gyre Termes" cannot be found. Rien n’est cassé : c’est fontspec tel qu’il est conçu. fontspec est le paquet qui permet à LaTeX d’appeler une police par son nom ; une seule ligne \setmainfont change la fonte du corps. Mais à qui ce nom est demandé varie selon le moteur, et c’est précisément là que les documents se cassent pour de bon. Cette page place cette divergence au centre, puis parcourt \setmainfont, \newfontfamily, la sélection par fichier et les clés de fonctionnalités OpenType, mesures à l’appui.

Sur quels moteurs fontspec fonctionne, et pourquoi pdfLaTeX en est exclu

fontspec fonctionne sur exactement deux moteurs, XeLaTeX et LuaLaTeX ; sous pdfLaTeX, c’est la ligne \usepackage{fontspec} elle-même qui échoue. La raison est historique. Le TeX des années 1980 ne connaît que ses propres métriques TFM et les fontes Type 1 / METAFONT. OpenType, et l’idée même d’une base de polices à l’échelle du système, sont venus après TeX. XeTeX et LuaTeX sont des moteurs reconstruits de l’extérieur pour ce monde-là : ils traitent nativement l’entrée Unicode et les fontes OpenType. fontspec est la couche qui traduit ces capacités récentes en vocabulaire LaTeX — et pdfTeX n’a aucune capacité de ce genre à traduire.

Le chargement tient en une ligne, \usepackage{fontspec}. Les classes et paquets destinés à XeLaTeX et LuaLaTeX (bxjsarticle, unicode-math, luatexja-fontspec, etc.) le chargent généralement avant vous, et l’écrire à nouveau explicitement ne pose pas de problème. Lors du portage d’un document pdfLaTeX, pensez à supprimer \usepackage[T1]{fontenc} et \usepackage[utf8]{inputenc} : le premier est superflu puisque fontspec bascule sur l’encodage TU, le second n’a aucun sens sur un moteur Unicode.

Changer la fonte du corps avec \setmainfont, \setsansfont, \setmonofont

Trois commandes portent un document : \setmainfont{…} (la romaine, fonte par défaut du corps), \setsansfont{…} (ce que sélectionnent \textsf et \sffamily) et \setmonofont{…} (la monospace derrière \texttt et \ttfamily). L’argument est un nom de police ou un nom de fichier. À partir de là, fontspec retrouve tout le quatuor — romain, gras, italique, gras italique — et le relie à \textbf, \textit et \emph : la façon d’écrire le corps ne change en rien. Constituer ce quatuor automatiquement est le travail central de fontspec ; comme on le verra, on n’écrit de réglage supplémentaire que lorsque cette automatisation échoue.

document.tex
% compile with lualatex (or xelatex — see the next section)
\documentclass{article}
\usepackage{fontspec}
\setmainfont{TeX Gyre Termes}   % roman / body
\setsansfont{TeX Gyre Heros}    % sans serif
\setmonofont{TeX Gyre Cursor}   % monospaced
\begin{document}
Body text, \textbf{bold}, \textit{italic}, \textsf{sans}, \texttt{mono}.
\end{document}

Par principe, ces commandes vont dans le préambule, pour une seule raison : LaTeX fige ses fontes mathématiques à \begin{document}. Exécutez \setmainfont dans le préambule et la même fonte atteint aussi les romaines des maths, comme \mathrm ; exécutez-la dans le corps et seul le texte change, la romaine mathématique restant en arrière. La fonte mathématique elle-même échappe à fontspec : elle relève de \setmathfont d’unicode-math. Retenez que le texte et les maths sont pilotés par deux commandes distinctes.

The font "…" cannot be found. : XeLaTeX et LuaLaTeX ne cherchent pas au même endroit

Si ! Package fontspec Error: The font "…" cannot be found. n’apparaît que sous XeLaTeX, ce n’est pas une faute de frappe dans le nom, mais une différence d’interlocuteur. XeTeX interroge la base de polices du système d’exploitation et ne voit donc que les polices que l’OS considère installées. LuaTeX construit son propre index via luaotfload, et cet index couvre aussi l’arborescence TeX. Les polices livrées par TeX Live ne sont pas enregistrées auprès de l’OS : cet écart devient directement l’écart de résultat. Sur le TeX Live 2024 de cette machine, un fichier identique a compilé sous LuaLaTeX et s’est arrêté sous XeLaTeX.

terminal
$ xelatex t1.tex
! Package fontspec Error: The font "TeX Gyre Termes" cannot be found.

$ lualatex t1.tex
Output written on t1.pdf (1 page, 3697 bytes).

$ pdffonts t1.pdf
name                            type          encoding    emb sub uni
NNOCLB+TeXGyreTermes-Regular    CID Type 0C   Identity-H  yes yes yes

La ligne passe entre « police livrée avec TeX » et « police du système ». Mesuré sur cette machine, les polices installées côté système — Hiragino Mincho ProN, Hiragino Sans, YuMinchose résolvent bien sous XeLaTeX. En revanche, les polices que TeX Live distribue sous texmf-dist/fonts/opentype/public/ sont invisibles à XeLaTeX par leur nom ; dans TeX Live 2024, ce répertoire contient 125 paquets (1 499 fichiers .otf réels). La logique de conception des moteurs relève de /learn/engines/xetex et /learn/engines/luatex. Ce qu’il faut ici, c’est la manœuvre qui remet un document cassé en état de compiler.

Deux correctifs existent. (1) Compiler avec lualatex. Aucune modification du source n’est nécessaire : c’est le plus court dans la plupart des cas. (2) Écrire le nom de fichier au lieu du nom de police. \setmainfont{texgyretermes-regular.otf} passe bien sous XeLaTeX — mais au prix suivant : désigné par fichier, fontspec ne peut plus deviner les membres gras et italique. Avec \textbf, on obtient LaTeX Font Warning: Font shape 'TU/texgyretermes-regular.otf(0)/b/n' undefined et le passage censé être gras sort en maigre. C’est l’échec silencieux typique : un avertissement, pas une erreur, donc facile à manquer. Les noms de fichiers sont aussi sensibles à la casse : avec TeXGyreTermes-Regular.otf, la même police revient à cannot be found.

Sélectionner par fichier : Path=, Extension=, BoldFont=

La forme complète par fichier assigne les quatre styles à la main. Le répertoire vient de Path=, le suffixe (.otf ou .ttf) d’Extension=, puis chaque fichier est associé à UprightFont=, BoldFont=, ItalicFont=, BoldItalicFont=. L’astérisque * dans ces valeurs est un joker remplacé par le nom de base commun donné en premier argument. Le gras et l’italique disparus à la section précédente reviennent dès que ces quatre lignes sont écrites : à la mesure, la version complète a produit zéro avertissement Font shape … undefined, et pdffonts a listé côte à côte Regular, Bold, Italic et BoldItalic.

document.tex
\usepackage{fontspec}
% XeLaTeX-safe: name the files, and name all four styles
\setmainfont{texgyretermes}[
  Extension      = .otf ,
  UprightFont    = *-regular ,
  BoldFont       = *-bold ,
  ItalicFont     = *-italic ,
  BoldItalicFont = *-bolditalic ,
]

% fonts shipped inside the project directory
\setsansfont{LibreBaskerville}[
  Path        = ./fonts/ ,
  Extension   = .otf ,
  UprightFont = *-Regular ,
  BoldFont    = *-Bold ,
]

Le choix se ramène à une question pratique : qui va composer ce document ? Pour un brouillon que vous serez seul à lire, le nom de police est plus rapide. Quand le même PDF doit sortir sur la machine d’autrui — coauteurs, soumission, CI, Docker —, embarquer les polices dans le projet et les désigner via Path= est à peu près la seule réponse fiable. Avec Path=, fontspec regarde directement ce chemin relatif plutôt que le chemin de recherche de TeX, et le dépôt entier voyage d’un bloc.

MéthodeÉcritureQuand l’utiliserAtteint les polices livrées sous XeLaTeX ?
By name\setmainfont{TeX Gyre Termes}Brouillons et documents personnels ; gras et italique s’apparient seulsNon — seulement les polices enregistrées dans l’OS
By file, upright only\setmainfont{texgyretermes-regular.otf}Quand il faut juste que ça compile ; on perd le grasOui — mais \textbf reste maigre sans avertir
By file, all fourPath / Extension / UprightFont / BoldFont / ItalicFont / BoldItalicFontCollaboration, soumission, CI, polices maison — quand la reproductibilité primeOui — et aucun avertissement Font shape … undefined

Ajouter une quatrième et une cinquième fonte avec \newfontfamily

Une fonte qui ne rentre pas dans le trio romain/sans/mono s’ajoute en créant sa propre bascule avec \newfontfamily. Le premier argument est le nom de commande souhaité, le second la police, et les mêmes options que \setmainfont sont acceptées. La commande créée est déclarative, comme \rmfamily : elle s’applique à tout ce qui suit. Pour en limiter la portée, entourez-la d’accolades, {\titlefont …}.

document.tex
\usepackage{fontspec}
\newfontfamily\titlefont{TeX Gyre Bonum}
\newfontfamily\quotefont{TeX Gyre Schola}[Scale = MatchLowercase]
% ...
\titlefont A heading in Bonum

{\quotefont A quoted passage in Schola.}

Pour une fonte employée une seule fois, on peut sauter la définition et appliquer \fontspec{Nom de police} comme déclaration locale. Mais \fontspec recharge la fonte à chaque appel : l’utiliser pour quelque chose de récurrent, des titres de chapitre par exemple, allonge insidieusement le temps de compilation. À partir de deux usages, passez par \newfontfamily. Notez aussi que \newfontfamily échoue si une commande de ce nom existe déjà : évitez les noms courts déjà pris par LaTeX comme \sc ou \it, et choisissez un nom parlant, par exemple \titlefont.

Activer les fonctionnalités OpenType : Ligatures, Numbers, Scale

Une police OpenType contient déjà des glyphes alternatifs — ligatures, variantes de chiffres, petites capitales — et fontspec les fait sortir par des options key=value. L’effet se mesure plus vite qu’il ne se juge à l’œil, voici donc des valeurs relevées sur TeX Gyre Pagella en 10 pt. Avec Numbers=OldStyle, la profondeur de 0123456789 passe de 0.19998pt à 2.37999pt : le fait que les chiffres elzéviriens donnent une descendante au 3 et au 9 apparaît directement dans la mesure.

  • Ligatures= — ligatures et conversion de saisie. Ligatures=TeX active la façon TeX de taper : -- devient un tiret demi-cadratin, --- un tiret cadratin, ` et '' des guillemets courbes. (Mesuré : --- passe de 9,99 pt de « trois traits d’union » à exactement 10,0 pt — un cadratin — en vrai tiret cadratin.) Autres valeurs : Common (ligatures fi, fl…), NoCommon pour les couper (mesuré : fi s’élargit de 6,05 pt à 6,35 pt), Rare/Discretionary et Historic`.
  • Numbers= — style des chiffres. Combinez OldStyle (chiffres elzéviriens, qui vivent dans la prose) ou Lining (chiffres modernes de hauteur uniforme) avec Proportional ou Monospaced. Les chiffres d’un tableau s’alignent verticalement dès que Lining,Monospaced est posé.
  • Letters=SmallCaps — de vraies petites capitales. Mesuré sur Libertinus Serif, Abc descend de 6,98 pt à 6,58 pt de haut et passe de 16,26 pt à 16,94 pt de large. Attention : si la police n’a pas de table smcp, fontspec ne fait rien et ne dit rien — sur TeX Gyre Pagella la largeur est restée à 17,6 pt. Des valeurs comme Letters=Uppercase existent aussi.
  • SmallCapsFeatures= — un lot de fonctionnalités à n’appliquer qu’en petites capitales, par exemple SmallCapsFeatures={Numbers=OldStyle}. Sur le même modèle, UprightFeatures=, BoldFeatures= et ItalicFeatures= permettent de régler chaque style séparément.
  • Scale= — facteur d’échelle : un nombre, ou Scale=MatchLowercase (aligner la hauteur d’x sur la fonte principale) ou Scale=MatchUppercase (aligner la hauteur des capitales). À la mesure, la hauteur d’x de TeX Gyre Heros, 5,24 pt, est descendue à 4,68999 pt face au texte Pagella — exactement les 4,69 pt de Pagella.
  • StylisticSet= — choisit par numéro un jeu stylistique de variantes fourni par la police. RawFeature= est l’échappatoire pour les fonctionnalités sans clé dédiée, en transmettant directement une balise OpenType ; RawFeature={+onum} donne le même résultat que Numbers=OldStyle (mesuré : la même profondeur de 2,37999 pt).
  • Script= / Language= — choisissent le système d’écriture et la langue (Script=Arabic, Language=Turkish, etc.). Renderer= désigne le moteur de mise en forme ; sous XeTeX on peut choisir AAT, OpenType ou Graphite. Sous LuaTeX, c’est luaotfload qui s’en charge, et la clé ne sert donc presque jamais.
document.tex
\usepackage{fontspec}
\setmainfont{TeX Gyre Pagella}[
  Ligatures = TeX ,
  Numbers   = OldStyle ,
  SmallCapsFeatures = {Numbers = Lining} ,
]
% match the sans to the body x-height
\setsansfont{TeX Gyre Heros}[Scale = MatchLowercase]

Pour ajouter une fonctionnalité à un seul endroit plutôt qu’à tout le document, utilisez \addfontfeature{…} (ou \addfontfeatures{…} pour plusieurs). La commande surcharge localement la fonte courante avec la fonctionnalité indiquée et n’agit qu’à l’intérieur des accolades englobantes. Le cas d’école : un document composé en chiffres elzéviriens où les nombres d’un tableau doivent s’aligner.

latex
Set in old-style figures, but this column
{\addfontfeature{Numbers={Lining,Monospaced}} 01234 56789}
lines up digit by digit.

Ce que fontspec ne couvre pas : les maths et le japonais

fontspec ne prend en charge que le texte latin du corps ; les maths et le japonais suivent des voies distinctes. Pour les maths, chargez unicode-math et confiez à \setmathfont{…} une police mathématique OpenType : Latin Modern Math, STIX Two Math, NewCM Math. Changer \setmainfont ne déplace pas les maths d’un pouce ; un document dont le texte et les formules jurent n’est donc pas un problème propre à pdfLaTeX. Le choix de la police mathématique relève de la page sur les fontes mathématiques.

Le japonais suit la même figure. \setmainfont ne change que la fonte latine ; kanji et kana ne bougent pas. Sous LuaLaTeX, on charge luatexja-fontspec, en pratique le pendant japonais de fontspec, et l’on utilise ses commandes en « j » : \setmainjfont{…} (Mincho, fonte japonaise du corps), \setsansjfont{…} (Gothic), \newjfontfamily. La syntaxe des options est pour ainsi dire identique : tout ce que vous savez de Scale= et Path= se transpose. Composer du japonais sur un moteur Unicode revient donc à faire rouler deux voies en parallèle. Les polices japonaises disponibles sont traitées sur la page qui leur est consacrée.