Exporter en image (TeX2img/dvisvgm/ImageMagick)

Une figure dessinée en LaTeX est déjà une image vectorielle avant tout export : les axes existent comme des courbes, les étiquettes comme des glyphes d'une fonte. Pourtant, dès qu'on l'exporte en image, cette information se perd avec une facilité déconcertante. Et ce qui décide de sa perte se joue bien plus tôt qu'on ne le croit : à l'unique choix de passer par DVI ou par PDF. Le manuel de dvisvgm le dit sans détour : le texte présent dans les fichiers PDF et PostScript est toujours converti en éléments de tracé. Passez par un PDF et les lettres de votre figure cessent d'être des lettres. Cette page dispose standalone, pdfcrop, dvisvgm et la pixellisation autour de ce pivot précis.

Mettre la seule figure sur une page : la classe standalone

La première étape de l'export consiste à donner au papier la taille de la figure. La classe standalone de Martin Scharrer (v1.3b dans TeX Live 2024) fixe les dimensions de la page à celles du contenu. En ne mettant ici que $\displaystyle \int_{-\infty}^{\infty} e^{-x^2}\,dx = \sqrt{\pi}$ dans \documentclass[border=2pt,preview]{standalone} et en lançant pdflatex, le PDF obtenu avait une page de 85.779 × 27.993 pt — exactement le contour de la formule. Sans border, la valeur par défaut est 0pt sur les quatre côtés. La classe elle-même fixe le curieux 0.50001bp — destiné à empêcher un arrondi de rogner le bord d'un glyphe — mais le fichier standalone.cfg livré avec elle l'écrase par \standaloneconfig{border=0pt} juste avant le traitement des options. Pour un dessin TikZ, on écrit \documentclass[tikz,border=2pt]{standalone} et l'on place le tikzpicture juste après \begin{document}. Pour découper un fragment de texte courant qui doit se replier, on lui donne une largeur, par exemple varwidth=10cm. Le paquet preview que standalone utilise en dessous a d'abord été écrit pour preview-latex, dans AUCTeX sous Emacs : l'idée de ne composer qu'une tranche de document vient de là.

latex
% fig.tex — a figure that is its own page
\documentclass[tikz,border=2pt]{standalone}
\begin{document}
\begin{tikzpicture}
  \draw[thick,->] (0,0) -- (3,0) node[right] {$x$};
  \draw[thick,->] (0,0) -- (0,2) node[above] {$y$};
  \draw[blue,thick] (0,0) .. controls (1,2) .. (3,1);
\end{tikzpicture}
\end{document}

Rogner les marges d'un PDF existant : pdfcrop

Quand la figure se trouve dans un document ordinaire et ne peut être reconstruite, pdfcrop fait l'affaire. C'est un script Perl de Heiko Oberdiek (v1.42 dans TeX Live 2024) qui calcule la boîte englobante du contenu de la page et y ramène la boîte de rognage. Mesuré ici : un document d'une page au format letter de 612 × 792 pt est ressorti de pdfcrop doc.pdf doc-crop.pdf en 345 × 539 pt. Si la marge ne doit pas être nulle, --margins 10 en redonne 10 pt sur chaque côté, soit 365 × 559 pt. Une réserve : pdfcrop appelle Ghostscript — l'en-tête du script l'annonce, « Requirements: Perl5, Ghostscript ». Sans gs installé, il ne fonctionne pas. Et si la figure peut de toute façon être produite avec standalone, pdfcrop devient inutile : ne pas créer la marge est plus rapide et plus précis que de la découper.

terminal
pdfcrop doc.pdf doc-crop.pdf              # 612x792 pt becomes 345x539 pt
pdfcrop --margins 10 doc.pdf doc-crop.pdf # keep 10 pt on every side
pdfcrop --hires doc.pdf doc-crop.pdf      # use the high-resolution bounding box

Produire un SVG : dvisvgm, et pourquoi la voie DVI l'emporte

Pour une figure destinée au web, SVG est le premier candidat. Le dvisvgm de Martin Gieseking (3.2.2 dans TeX Live 2024) convertit DVI, EPS et PDF en SVG — mais le résultat dépend de la porte par laquelle on est entré. En plaçant \def\pgfsysdriver{pgfsys-dvisvgm.def} avant \documentclass, en produisant un DVI avec latex puis en lançant dvisvgm fig.dvi, le SVG obtenu contenait les axes et la courbe sous forme d'éléments <path> et les étiquettes $x$, $y$ et $y=f(x)$ sous forme d'éléments <text> — les lettres restées lettres, renvoyant à des fontes vectorielles intégrées dans <defs>. En entrant par un PDF, rien de tel. Le manuel de dvisvgm affirme explicitement que le texte présent dans les fichiers PDF et PostScript est toujours converti en éléments de tracé. De fait, en passant le PDF de la même figure par pdftocairo -svg de poppler, le SVG obtenu comptait zéro élément <text>.

latex
% figdvi.tex — the DVI route, which keeps the labels as real text
\def\pgfsysdriver{pgfsys-dvisvgm.def}
\documentclass[tikz,border=2pt]{standalone}
\begin{document}
\begin{tikzpicture}
  \draw[thick,->] (0,0) -- (3,0) node[right] {$x$};
  \draw[blue,thick] (0,0) .. controls (1,2) .. (3,1);
\end{tikzpicture}
\end{document}
terminal
latex figdvi.tex        # produce a DVI, not a PDF
dvisvgm figdvi.dvi      # SVG with <text> elements and vector paths

# the PDF route needs a helper and outlines all text:
dvisvgm --pdf fig.pdf   # requires mutool with Ghostscript 10.01 or newer

Le passage de PDF à SVG se heurte à un autre obstacle, très concret. dvisvgm --pdf confiait autrefois le PDF à Ghostscript, mais selon le manuel le nouvel interpréteur PDF introduit dans Ghostscript 10.01.0 a rendu ce chemin inutilisable ; dvisvgm cherche désormais mutool, issu de MuPDF. Sur la machine de cet article (Ghostscript 10.03.0, sans mutool), dvisvgm --pdf fig.pdf s'arrête sur ERROR: can't retrieve number of pages from file fig.pdf. La voie PDF réclame donc une dépendance supplémentaire ; et dès que c'est Ghostscript qui traite le fichier, la règle du manuel s'applique et le texte est de toute façon converti en contours — deux raisons de préférer la voie DVI. Une autre option mérite d'être retenue : -e (--exact-bbox). Par défaut, la boîte englobante se déduit des métriques TFM ; un glyphe qui les déborde réellement peut donc être rogné. Si des lettres sont amputées au bord d'une figure, commencez par là.

Que faire des fontes dans le SVG : --font-format et --no-fonts

Conserver <text> est une bonne chose, mais il reste une décision à prendre. Par défaut, dvisvgm emploie des fontes SVG<font> et <glyph> intégrés dans <defs> —, qui existent dans la spécification mais sont loin d'être prises en charge partout ; le manuel de dvisvgm indique lui-même, à l'entrée --no-fonts, que la sortie en tracés est « plus compatible avec la plupart des applications qui ne gèrent pas les fontes SVG ». Comparaison des trois variantes sur la même figure TikZ : les fontes SVG par défaut donnent 5 790 octets, --font-format=woff2 donne 4 815 octets (un WOFF2 en URI de données dans le src d'une règle @font-face), et --no-fonts donne 8 290 octets avec zéro élément <text>, chaque glyphe devenu un <path>. La règle pratique est simple. Pour le web : --font-format=woff2 — le texte reste sélectionnable et tous les navigateurs savent l'afficher. Pour un transfert vers Illustrator, Inkscape ou PowerPoint : --no-fonts — plus volumineux, mais plus rien ne peut s'afficher de travers.

OptionTexte dans le SVGTaille pour la même figureUsage adapté
--font-format=svg<text> et fontes SVG (par défaut)5 790 octetsprise en charge inégale ; rarement le bon choix
--font-format=woff2<text> et un WOFF2 intégré via @font-face4 815 octetspublication web ; texte sélectionnable, fichier le plus petit
--no-fontsaucun <text> ; chaque glyphe est un <path>8 290 octetstransfert vers un autre logiciel de dessin ; rien ne peut mal s'afficher

Pixelliser en PNG, pour les diapositives et les vieux outils

Bien des destinations refusent encore le SVG ; on se rabat alors sur le PNG. La résolution se règle avec -r : considérez 300 dpi comme un plancher et 600 dpi comme la cible pour l'impression ou les écrans à forte densité. Pixelliser à 600 dpi le PDF de formule de 85.779 × 27.993 pt construit plus haut a donné un PNG transparent d'environ 715 × 233 pixels, aussi bien avec Ghostscript (gs -sDEVICE=pngalpha -r600) qu'avec pdftocairo -png -r 600 -transp de poppler. Comme 72 pt font un pouce, 85.779 ÷ 72 × 600 ≈ 715 ; vérifier que le calcul tombe juste est la façon de s'assurer que l'option de résolution a bien pris. Sans transparence, -sDEVICE=png16m (ou pdftocairo sans -transp) donne un fond blanc. Beaucoup de textes recommandent ImageMagick avec magick -density 300 in.pdf out.png, mais ImageMagick délègue le rendu du PDF à Ghostscript. Il ne fait pas partie de TeX Live et n'était pas installé sur la machine utilisée ici : son comportement n'a donc pas été vérifié. Puisque c'est Ghostscript qui dessine réellement, l'appeler directement fait une dépendance de moins.

terminal
# Ghostscript, transparent background, 600 dpi
gs -q -dNOPAUSE -dBATCH -sDEVICE=pngalpha -r600 \
   -dTextAlphaBits=4 -dGraphicsAlphaBits=4 \
   -sOutputFile=eq.png eq.pdf

# poppler, same result, shorter to type
pdftocairo -png -r 600 -transp -singlefile eq.pdf eq

De la source au PNG en une commande : le convert= de standalone et --shell-escape

Si taper trois commandes à chaque fois agace, confiez le travail à l'option de classe convert= de standalone. Dès la composition terminée, la classe lance elle-même une commande de conversion vers le shell. Le moteur peut être imagemagick (par défaut), ghostscript ou pdf2svg, et la résolution par défaut est density=300. Même sans ImageMagick, indiquer ghostscript fonctionne : avec \documentclass[border=2pt,convert={ghostscript,density=600,outext=.png}]{standalone} et pdflatex --shell-escape eqc.tex, le journal affichait gs -dSAFER -dBATCH -dNOPAUSE -sDEVICE=png16m -r600 -sOutputFile=eqc.png eqc.pdf et un PNG de 715 × 233 est sorti de cette seule commande. Comme un programme externe est lancé, l'échappement shell restreint ne suffit pas : il faut --shell-escape. Sur un projet riche en figures, mieux vaut garder la conversion dans un script de construction, pour que --shell-escape ne devienne pas une habitude.

latex
% eqc.tex — build the PNG in the same run
\documentclass[border=2pt,convert={ghostscript,density=600,outext=.png}]{standalone}
\usepackage{amsmath}
\begin{document}
$\displaystyle \int_{-\infty}^{\infty} e^{-x^2}\,dx = \sqrt{\pi}$
\end{document}

% then: pdflatex --shell-escape eqc.tex

Tout ce qui précède — composer le seul fragment, le rogner, puis le porter en vectoriel ou en matriciel — c'est ce que TeX2img enveloppe dans une interface graphique. On y colle une formule, on choisit un format et une résolution, et le programme s'occupe de la transparence et de l'anticrénelage. Pour un export ponctuel, c'est d'une rapidité imbattable ; pour un document comptant des dizaines de figures et traversant de nombreuses versions, il est finalement plus commode d'intégrer les commandes des sections précédentes à la chaîne de construction. TeX2img est une application indépendante, qui ne fait pas partie de TeX Live et n'était pas installée sur la machine utilisée ici : son comportement n'a donc pas été vérifié.

Vers quel format exporter

  • Une figure destinée au web → SVG. Produisez un DVI avec latex et lancez dvisvgm --font-format=woff2. Le texte reste dans des <text> et rien ne se dégrade au zoom.
  • Une figure à réintégrer dans un document LaTeX → laissez-la en PDF. Produite avec standalone, elle n'a pas de marge et passe directement dans \includegraphics.
  • Diapositives, Word, réseaux sociaux → PNG, via gs -sDEVICE=pngalpha -r600 ou pdftocairo -png -r 600 -transp. N'abandonnez la transparence que si un fond blanc est voulu.
  • Une figure à retoucher dans Illustrator ou Inkscape → SVG avec --no-fonts. Les formes tiennent même là où la fonte manque.
  • Une figure contenant une photographie → JPEG pour la seule photographie ; dessin au trait et étiquettes en SVG ou PNG. Tout passer en JPEG salit le bord des lettres.
  • Quand dvisvgm --pdf refuse de fonctionner → basculez d'abord sur la voie DVI. S'il faut absolument partir d'un PDF, installez mutool de MuPDF.