Generar PDF (pdfTeX / dvipdfmx)

Un documento LaTeX que contiene solo la palabra «Hello» ocupa 252 bytes como archivo DVI. Esa misma página convertida en PDF por pdflatex ocupa 11.287. Casi todos esos once kilobytes de más no son texto sino la propia fuente: un programa Type 1 recortado a los cinco glifos realmente usados se lleva 9.002 bytes. Generar un PDF con LaTeX es, en el fondo, una cadena de decisiones sobre qué viaja dentro del archivo. Esta página recorre esa cadena —las dos rutas hacia el PDF, el ajuste de la versión y la compresión, cómo se registra de verdad el tamaño del papel y cómo comprobar la incrustación de fuentes con pdffonts— con cifras medidas en todo momento.

Dos rutas hacia el PDF: salida directa y vía DVI

O bien el motor escribe el PDF él mismo, o bien un programa aparte convierte un archivo DVI. En la ruta directa, pdflatex (pdfTeX) y lualatex (LuaTeX) emiten operadores PDF mientras componen la página. En la ruta DVI, latex o el (u)platex japonés escriben primero un DVI que dvipdfmx traduce. El caso interesante es xelatex: parece un solo comando, pero pertenece en realidad a la segunda familia — XeTeX escribe un DVI extendido llamado .xdv y se lo entrega a xdvipdfmx. Mirar la instalación real de TeX Live 2024 lo deja claro: dvipdfmx es un enlace simbólico a xdvipdfmx, de modo que la ruta DVI japonesa y la ruta .xdv de XeTeX las atiende un único binario. La prueba queda en la salida: un PDF creado con xelatex declara como Producer xdvipdfmx (20240305).

terminal
# TeX Live 2024: one binary serves both DVI routes
$ ls -l $(which dvipdfmx)
lrwxr-xr-x  1 root  wheel  9 May  4  2024 .../dvipdfmx -> xdvipdfmx

# direct
$ pdflatex paper.tex
# via DVI
$ latex paper.tex && dvipdfmx paper.dvi
# via DVI, the Japanese way
$ uplatex paper.tex && dvipdfmx paper.dvi

Pase el mismo manuscrito por cinco rutas: el resultado es siempre «una página A4», pero el interior difiere. La cadena Producer cambia, claro; lo que merece atención son la versión de PDF por defecto y los valores de MediaBox. El ancho A4 de 210 mm equivale exactamente a 595,2755905… puntos, y cada conversor redondea a su manera: pdfTeX y LuaTeX siguen \pdfdecimaldigits=3 y escriben 595.276, dvipdfmx escribe 595.28 y Ghostscript (vía ps2pdf) redondea hasta el entero 595. En la práctica casi nunca importa, pero es la razón por la que dos archivos A4 supuestamente idénticos no coinciden al compararlos.

ComandoPrograma que escribe el PDFVersión PDF por defectoAncho MediaBox A4
pdflatexel propio pdfTeX1.5595.276
lualatexel propio LuaTeX1.5595.276
xelatexxdvipdfmx, mediante un .xdv1.5595.28
latex + dvipdfmxdvipdfmx1.5595.28
uplatex + dvipdfmxdvipdfmx; la ruta japonesa habitual1.5595.28
latex + dvips + ps2pdfGhostscript1.4595

«pdflatex no puede usar EPS» ya no es cierto

En TeX Live 2024, escribir \usepackage{graphicx} con \includegraphics{fig.eps} y ejecutar pdflatex basta para que la figura entre, sin más configuración. No es que pdfTeX haya aprendido a leer EPS: el archivo controlador pdftex.def carga epstopdf-base por su cuenta, siempre que LaTeX esté en marcha, que el escape de shell esté activo (el modo restricted por defecto de TeX Live es suficiente) y que \DoNotLoadEpstopdf no esté definido. Al ejecutarlo aparece junto al fuente un archivo intermedio llamado fig-eps-converted-to.pdf, y es ese el que se incluye. Ya no hace falta escribir \usepackage{epstopdf} uno mismo. A la inversa, con -no-shell-escape la conversión no ocurre y la figura desaparece sin más, sin error ni aviso. Ese fallo silencioso es el peligroso.

Esta conversión automática tiene su trampa, y el propio comentario de pdftex.def la señala: «This can be wrong!» Si existen a la vez fig.pdf y fig.eps y el PDF es el original verdadero, quedará sobrescrito por una versión regenerada desde el EPS. El remedio es poner \newcommand{\DoNotLoadEpstopdf}{} incluso antes de la línea \documentclass. La ruta DVI (dvipdfmx) ha manejado EPS desde siempre, llamando a Ghostscript por detrás para convertirlo, y sin dejar archivo intermedio. Por eso un flujo de trabajo antiguo lleno de EPS sigue encajando bien en la ruta DVI.

latex
% keep a hand-made fig.pdf from being overwritten by fig.eps
\newcommand{\DoNotLoadEpstopdf}{}
\documentclass{article}
\usepackage{graphicx}
\begin{document}
\includegraphics{fig}   % extension omitted: pdf, png, jpg are tried first
\end{document}

¿De verdad se detecta solo el controlador de salida?

Para graphicx y color la respuesta es sí. Ambos necesitan conocer el controlador de salida (pdftex, luatex, xetex, dvipdfmx, dvips, dvisvgm) para emitir las instrucciones de bajo nivel correctas, y el archivo de configuración graphics.cfg averigua el motor sondeando \pdfoutput, \XeTeXversion y \luatexversion, y decide entonces si lee pdftex.def, luatex.def, xetex.def o dvips.def. Por eso no conviene escribir a mano una opción de controlador: una fijada de antemano se vuelve falsa en cuanto se cambia la forma de compilar.

Pero hyperref es la excepción. Produzca DVI con (u)platex escribiendo solo \usepackage{hyperref} y el registro dirá Package hyperref Info: Driver (default): hdvips.: emite \special pensados para dvips. Entregue ese DVI a dvipdfmx y aparecerá una ristra de dvipdfmx:warning: Unknown token "SDict" y un PDF sin enlaces ni marcadores. En esta ruta, indíquelo explícitamente: \usepackage[dvipdfmx]{hyperref}. «No nombres nunca el controlador» es un consejo sobre graphicx y no se extiende a hyperref en la ruta DVI; la historia completa está en «Marcadores y metadatos».

Fijar la versión del PDF: dónde funciona realmente \pdfminorversion

\pdfminorversion pertenece solo a pdfTeX. Bajo LuaTeX produce ! Undefined control sequence.; XeTeX da el mismo error. LuaTeX reagrupó sus primitivas en un espacio de nombres, así que allí se escribe \pdfvariable minorversion=4. XeTeX no tiene primitiva equivalente —quien escribe el PDF es xdvipdfmx—, de modo que se le pasa al controlador: -output-driver="xdvipdfmx -V 4". En la ruta DVI es lo más sencillo: dvipdfmx -V 4 paper.dvi. Incluso se puede rastrear de dónde sale el valor por defecto: el pdftexconfig.tex de TeX Live contiene \pdfminorversion = 5, y ahí está toda la explicación de «por defecto, PDF 1.5».

A estas alturas de 2024, sin embargo, apenas hace falta distinguir esas tres grafías. Coloque el punto de entrada más reciente del núcleo de LaTeX, \DocumentMetadata{pdfversion=2.0}, antes de \documentclass, y obtendrá PDF 2.0 igual con pdflatex, lualatex o xelatex (medido: los tres informan PDF version: 2.0). Mientras \pdfminorversion solo toca el número menor, pdfversion fija también el mayor: \pdfminorversion=0 solo da PDF 1.0 y nunca llegará a 2.0.

Motor o rutaCómo fijar la versión del PDFNota
\pdfminorversion=5pdfTeX (pdflatex)En LuaTeX/XeTeX da ! Undefined control sequence.
\pdfvariable minorversion=5LuaTeX (lualatex)la misma grafía llega a compresslevel y afines
dvipdfmx -V 4ruta DVI y XeTeXpara XeTeX: -output-driver="xdvipdfmx -V 4"
\DocumentMetadata{pdfversion=2.0}los tres motoresfija también el número mayor; va antes de \documentclass

Compresión del PDF: \pdfcompresslevel y \pdfobjcompresslevel, medidos

Subir el nivel de compresión hasta 9 ahorra dos bytes frente a 6. Medido sobre un documento de ocho páginas hecho con \lipsum[1-40]: \pdfcompresslevel=0 da 79.508 bytes, =1 da 45.730, =6 da 43.323 y =9 da 43.321. Solo cuenta el salto de 0 a 1; más allá es ruido. La otra perilla, \pdfobjcompresslevel, responde a un mecanismo distinto: no comprime el contenido de las páginas sino las definiciones de objetos del propio PDF, agrupadas en flujos de objetos. En el mismo documento eso baja de 43.321 a 41.019 bytes, alrededor de un cinco por ciento.

Aquí está la trampa que enlaza ambas cosas. Los flujos de objetos aparecieron con PDF 1.5, así que bajar a \pdfminorversion=4 para un visor antiguo desactiva en silencio \pdfobjcompresslevel. En realidad no tan en silencio: el registro dice pdfTeX warning (Object streams): \pdfobjcompresslevel > 0 requires PDF-1.5 or greater. Object streams disabled now. Y la medición coincide: la salida con \pdfminorversion=4 iguala byte a byte a la de \pdfobjcompresslevel=0 (43.321 en ambos casos). Cuando un archivo engorda un poco tras bajarle la versión, esta es casi siempre la razón. dvipdfmx sigue la misma lógica: añadir -V 4 convierte un PDF de 8.310 bytes en uno de 10.055. Su fuerza de compresión se ajusta con -z 0 a -z 9, y también ahí la diferencia entre -z 6 y -z 9 fue de seis bytes.

latex
% pdfTeX defaults, as set by TeX Live in pdftexconfig.tex
\pdfminorversion     = 5
\pdfcompresslevel    = 9   % 0 = off; 1 already captures most of the gain
\pdfobjcompresslevel = 2   % object streams; needs PDF 1.5 or later

% LuaTeX spells the same knobs differently
\pdfvariable minorversion    = 5
\pdfvariable compresslevel   = 9
\pdfvariable objcompresslevel = 2

Cuando quiera leer con sus propios ojos el PDF generado, lo más rápido es desactivar la compresión por completo. En vez de escribir primitivas propias de cada motor, basta una línea: \DocumentMetadata{uncompress} (medido: un PDF de 52.622 bytes pasa a 91.347 y se abre en un editor de texto). Úselo para examinar los operadores que produjo la compilación o para rastrear qué paquete insertó qué objeto.

Escribió [letterpaper] y salió A4: dónde se decide de verdad el tamaño del papel

La opción de clase no decide el tamaño de papel del PDF. En TeX Live 2024, pase \documentclass[letterpaper]{article} por pdflatex y pdfinfo informa Page size: 595.276 x 841.89 pts (A4). La razón es sencilla: la MediaBox del PDF se escribe a partir de \pdfpagewidth y \pdfpageheight, y letterpaper no las toca: solo fija la mancha de texto (\textwidth y afines). Mientras tanto, el pdftexconfig.tex de TeX Live ya ha fijado al arrancar \pdfpageheight = 297 true mm y \pdfpagewidth = 210 true mm. La clase acaba componiendo una caja de texto tamaño carta sobre una hoja A4.

Hay tres arreglos fiables. Cargar geometry (\usepackage[letterpaper]{geometry} se ocupa también de \pdfpagewidth); escribir la primitiva a mano (\pdfpagewidth=8.5in, que XeTeX también acepta); o, en la ruta DVI, indicarlo al convertir (dvipdfmx -p letter paper.dvi). Los tres dieron, medidos, 612 x 792 pts (letter). Y hay una cuarta respuesta, la más moderna: con \DocumentMetadata{}, la MediaBox se escribe desde \paperwidth y \paperheight en lugar de \pdfpagewidth, de modo que la opción de clase por fin gana. El mismo archivo fuente da A4 o carta según esté o no esa única línea. Pasarlo por alto en una migración cuesta más que un número de página desplazado.

terminal
# TeX Live 2024, same source, four ways of asking for US letter
$ pdflatex letter.tex     && pdfinfo letter.pdf  | grep "Page size"
Page size:       595.276 x 841.89 pts (A4)      # [letterpaper] alone: ignored

$ pdflatex geom.tex       && pdfinfo geom.pdf    | grep "Page size"
Page size:       612 x 792 pts (letter)         # \usepackage[letterpaper]{geometry}

$ latex letter.tex && dvipdfmx -p letter letter.dvi
Page size:       612 x 792 pts (letter)         # decided by the converter

$ pdflatex dm.tex         && pdfinfo dm.pdf      | grep "Page size"
Page size:       612 x 792 pts (letter)         # \DocumentMetadata{} present

¿Están incrustadas las fuentes? Cómo leer pdffonts

Si todas las filas de la columna emb de pdffonts paper.pdf dicen yes, las fuentes están incrustadas. Hay una segunda pista en los propios nombres: una fuente incrustada se llama algo así como OREBYP+CMR10, con un prefijo de seis mayúsculas y un +. Eso marca un subconjunto —solo se recortaron los glifos que el documento usó de verdad—, así que un CMR10 desnudo, sin prefijo, es un fuerte indicio de que la fuente no se incrustó. Abra el PDF de «Hello» del principio y el descriptor de la fuente incrustada dice /CharSet (/H/e/l/o/one): H, e, l, o y el uno del número de página. Eso es el subconjunto.

terminal
$ pdffonts paper.pdf
name                          type       encoding  emb sub uni object ID
----------------------------- ---------- --------- --- --- --- ---------
OREBYP+CMR10                  Type 1     Builtin   yes yes yes      4  0
PTKKKD+CMTI10                 Type 1     Builtin   yes yes yes      5  0

# the same source through latex + dvipdfmx: Type 1C instead of Type 1
$ pdffonts paper-dvipdfmx.pdf
FUYUFD+CMR10                  Type 1C    Builtin   yes yes yes      4  0

# a font that was NOT embedded: bare name, emb = no
Helvetica                     Type 1     Standard  no  no  no       7  0

La columna type también informa. Comparando la misma página «Hello», la salida de pdflatex dice Type 1 y la de dvipdfmx dice Type 1C. Son exactamente el mismo subconjunto de Computer Modern con los mismos cinco glifos y, sin embargo, los programas de fuente incrustados miden 9.002 bytes frente a 720: más de doce veces. dvipdfmx recodifica el Type 1 en CFF (Compact Font Format, llamado Type 1C dentro de un PDF) antes de incrustarlo, y ese solo hecho explica casi toda la diferencia de tamaño señalada al principio: 2.145 bytes por la vía DVI frente a 11.287 de pdflatex. LuaTeX y XeTeX usan por defecto la versión OpenType de Latin Modern, que entra como CID Type 0C. Todas están realmente incrustadas y sirven igual para imprenta que para una entrega.

Qué comprobar antes de enviar el archivo a una imprenta o a una revista

Dos comandos lo resuelven. pdffonts confirma que todas las fuentes están incrustadas y pdfinfo da las dimensiones de página y la versión del PDF. La comprobación se acaba ahí. Los incidentes son previsibles: un no colado en la columna emb (lo más fácil es traerlo con una figura PDF producida fuera), un archivo en carta cuando se esperaba A4, o una versión de PDF más reciente de lo que permiten las normas de entrega. Como la línea Page size de pdfinfo no revisa todas las páginas, se le puede dar un intervalo —pdfinfo -f 1 -l 99 paper.pdf— para verificar que las dimensiones no cambian a mitad de camino.

  • pdffonts paper.pdf: ¿todas las filas de emb dicen yes y todos los nombres llevan un prefijo ABCDEF+?
  • pdfinfo paper.pdf: ¿es Page size lo previsto y queda PDF version dentro de lo que permiten las normas de entrega?
  • Sobre todo inglés y con prisa → ruta directa (pdflatex). Los valores por defecto no piden reflexión.
  • Fuentes del sistema, texto con mucho Unicodelualatex o xelatex (ruta directa).
  • Japonés con (u)platex → ruta DVI (dvipdfmx); el papel con -p y la versión de PDF con -V.
  • Un gran fondo de EPS → la ruta DVI lo incorpora sin dejar archivos intermedios; la ruta directa convierte sola, pero siembra el directorio de *-eps-converted-to.pdf.