Compile dos veces el mismo documento LaTeX de una página: el DVI ocupa 956 bytes y el PostScript que dvips obtiene de él, 169.769 — un factor de 178. Ni un solo byte de ese aumento es información nueva. La única diferencia está en que el DVI nombra nueve fuentes mientras que el PostScript las lleva dentro. Ese hecho aislado explica casi todo: qué es un DVI, por qué PostScript fue durante dos décadas la parada intermedia y en qué se diferencian hoy las tres rutas hacia el PDF.
Qué hay realmente dentro de un archivo DVI: cajas y nombres de fuentes
Un DVI contiene solo posiciones y referencias a fuentes, ni una sola forma de letra. Pásese por dvitype, que viene con TeX Live, y se lee tal cual. fntdef1 27: cmr10 no es más que una declaración: la fuente número 27 será cmr10; setchar49 no es más que una instrucción: colocar aquí el carácter 49 de la fuente actual. El carácter 49 es la cifra 1. Los push, down4 y right3 intercalados mueven el punto actual. Un DVI es, pues, una lista de órdenes del tipo «pon aquí tal número de carácter de tal fuente con tal nombre», y no tiene la menor idea de qué aspecto tienen esos caracteres.
dvitype -output-level=4 -page-start='*' doc.dvi
# numerator/denominator=25400000/473628672
# magnification=1000; 0.00006334 pixels per DVI unit
# Postamble starts at byte 723.
# Font 27: cmr10---loaded at size 655360 DVI units
# Font 37: cmbx12 scaled 1200---loaded at size 943718 DVI units
# (this font is magnified 120%)
# 145: fntdef1 37: cmbx12
# 167: fntnum37 current font is cmbx12
# 168: setchar49 h:=4063232+530841=4594073, hh:=291Esto explica a la vez por qué un DVI es pequeño y por qué un DVI no se puede ver por sí solo. Ejecute strings sobre esos 956 bytes y lo único legible son las palabras del texto más una lista de nombres de fuentes: cmr10, cmmi7, cmsy10, cmex10 y las demás. Quien reciba un DVI no podrá reproducir la página si su máquina no encuentra fuentes con esos nombres. Esa división del trabajo era justamente el objetivo en los años ochenta: detenerse en una forma intermedia independiente del dispositivo y dejar el ajuste al papel o la pantalla reales a un controlador situado más adelante. El nombre DVI es la decisión de diseño.
| Está o no en un DVI | Qué significa |
|---|---|
setchar / put | un número de carácter; nunca la forma de la letra |
fntdef / fntnum | una fuente referida solo por nombre, tamaño de diseño y suma de control |
push / pop / down / right | la colocación de las cajas: el resultado compuesto en sí |
xxx (\special) | la vía de escape para lo que DVI no modela; lo decide el controlador |
glyph outlines | ausentes. Por eso un DVI no se muestra sin las fuentes |
color, paper size | no están en el DVI propiamente dicho; viajan como \special |
Por qué un DVI lo mide todo en 1/65536 de punto
La respuesta aparece al principio de la salida de dvitype. En numerator/denominator=25400000/473628672 el denominador 473628672 es 65536 × 7227, y 7227 puntos son exactamente 100 pulgadas. Así que una unidad DVI es 1/65536 de punto, la misma unidad entera que TeX usa internamente: el scaled point, sp. Por eso cmr10---loaded at size 655360 DVI units de más arriba no es otra cosa que 10 × 65536, es decir 10pt, y por eso cmbx12 scaled 1200 informa de 943718: 12pt × 1,2 = 14,4pt multiplicado por 65536. TeX compone la página solo con estos enteros, sin coma flotante alguna, y por eso mismo la misma fuente da el mismo resultado hasta el sp en cualquier máquina.
El formato lo diseñó en 1979 David R. Fuchs, alumno de Knuth; la especificación apareció como «The format of TeX’s DVI files» en TUGboat, volumen 3, número 2, en octubre de 1982. Más de cuarenta años después, el primer byte de doc.dvi sigue siendo 247 —el opcode pre— y el segundo sigue siendo 2, el número de identificación DVI. La compatibilidad aguantó porque el formato no suponía nada sobre el dispositivo: las máquinas de salida para las que se escribió desaparecieron hace mucho y solo queda en pie la parte que no suponía nada.
Por qué PostScript quedó en medio: mire dentro de un \special
El precio de ser independiente del dispositivo es que DVI no sabe expresar color, ni imágenes, ni rotación. Por eso Fuchs dejó exactamente una vía de escape: \special{...}, cuyo contenido nunca se interpreta y se entrega tal cual al controlador. Y lo primero que llenó esa trampilla fue PostScript. Cargue \usepackage{graphicx}, escriba \rotatebox{30}{rotated}, genere un DVI con latex y mire dentro: ahí está el PostScript en crudo. El DVI ni siquiera sabe que es PostScript. Solo transporta una cadena.
# what latex actually wrote into the DVI for \rotatebox and \textcolor
dvitype -output-level=4 -page-start='*' spec.dvi | grep xxx
# 88: xxx 'header=l3backend-dvips.pro'
# 116: xxx 'papersize=614.295pt,794.96999pt'
# 247: xxx 'color push rgb 1 0 0'
# 347: xxx 'ps: gsave currentpoint currentpoint translate
# 30 neg rotate neg exch neg exch translate'
# 449: xxx 'ps: currentpoint grestore moveto'A partir de ahí fue una calle de sentido único. Si la vía de escape de un DVI está llena de PostScript, solo una máquina que entienda PostScript puede terminar de interpretarlo. Cuando a mediados de los ochenta las impresoras láser con el PostScript de Adobe se volvieron el estándar de hecho, la ruta a través de dvips —el DVI traducido a PostScript— se asentó. Y al traducir, dvips incrusta las fuentes: el .ps generado abre con la línea %%DocumentFonts: CMBX12 CMR10 CMEX10 CMSY7 CMR7 CMMI10 CMMI7 CMR5 CMSY10, y el cuerpo lleva luego un bloque %%BeginFont: por cada una de esas nueve. Los 956 bytes y los 169.769 bytes del comienzo de esta página se diferencian exactamente en esas nueve fuentes.
PostScript ha abandonado el escenario, pero sus huellas están por todas partes. El ejecutable dvipdfmx, que va del DVI directo al PDF, lleva dentro un pequeño intérprete para ejecutar PostScript en línea, con diagnóstico incluido: Stack not empty after execution of inline PostScript code. Por eso el ps: de más arriba se sigue honrando como una rotación real en esta ruta. Su --help también lista -D template PS->PDF conversion command line template [none], el gancho para pasar a un programa externo como Ghostscript el PostScript que no puede manejar. Y el archivo .xbb que registra el tamaño de una imagen dice %%BoundingBox: 0 0 8 8: la propia convención de comentarios de PostScript, todavía en servicio.
Las tres rutas de hoy y lo que cuesta cada una
Texto occidental: directo a PDF con pdflatex y afines. Japonés: (u)platex y luego dvipdfmx. Un montón de PSTricks o de EPS heredados: latex, luego dvips, luego ps2pdf. Ahí se agota la decisión práctica. Lo que no es cierto es que el mismo documento produzca el mismo PDF. El documento del comienzo de esta página, por las tres rutas, dio direct.pdf con 85.509 bytes, viadvi.pdf con 14.693 y viaps.pdf con 17.851. Un vistazo con pdffonts lo explica al instante: pdfTeX incrusta las fuentes como Type 1, mientras que dvipdfmx y Ghostscript las convierten antes a la forma compacta Type 1C. Las páginas se ven idénticas; los archivos se diferencian seis veces.
| Ruta | Formatos por los que pasa | Dónde gana |
|---|---|---|
pdflatex / lualatex | .tex → PDF | un solo paso; el valor por defecto en texto occidental |
xelatex | .tex → XDV → PDF | fuentes del sistema; el paso XDV solo está oculto |
dvipdfmx | .tex → DVI → PDF | el estándar para japonés ((u)pLaTeX); coloca PNG y JPEG directamente |
dvips + ps2pdf | .tex → DVI → PS → PDF | PSTricks, un fondo de EPS, entregas que presuponen PostScript |
# 1. straight to PDF
pdflatex doc.tex
# 2. via DVI (the Japanese route)
uplatex doc.tex && dvipdfmx doc
# doc.dvi -> doc.pdf
# [1]
# 14692 bytes written
# 3. via PostScript
latex doc.tex && dvips doc -o doc.ps && ps2pdf doc.ps
# in practice latexmk drives all three for you¿XeLaTeX se salta de verdad el DVI?
No. xelatex -no-pdf doc.tex responde Output written on doc.xdv (1 page, 2476 bytes). y deja un doc.xdv. Su primer byte es 247, exactamente el mismo opcode pre que en doc.dvi. Solo cambia el byte siguiente: 2 para DVI, 7 para XDV. Lo que XeTeX escribe es DVI extendido, y lo que lo convierte en PDF es xdvipdfmx. El README que acompaña a TeX Live lo dice: «In the installation, dvipdfmx is a symlink to xdvipdfmx.», y en efecto dvipdfmx y extractbb apuntan al mismo ejecutable. Decir que XeLaTeX «produce PDF directamente» significa que la etapa DVI está oculta, no que haya desaparecido.
xelatex -no-pdf doc.tex
# Output written on doc.xdv (1 page, 2476 bytes).
# same container, different id byte:
# doc.dvi byte 0 = 247 (pre) byte 1 = 2
# doc.xdv byte 0 = 247 (pre) byte 1 = 7
xdvipdfmx doc.xdv # this is what xelatex runs for youCuando aparece Cannot determine size of graphic ... (no BoundingBox)
Este es el primer muro para quien coloca un PNG o un JPEG en la ruta DVI. El mensaje completo es ! LaTeX Error: Cannot determine size of graphic in sample.png (no BoundingBox)., y la causa no está ni en la imagen ni en dvipdfmx, sino en la opción de controlador de graphicx. latex no genera PDF, así que no tiene forma de leer por sí mismo las dimensiones; el controlador dvips por defecto solo sabe leer una línea PostScript %%BoundingBox, y una cabecera PNG no lo es. Hay dos remedios: nombrar el controlador, \usepackage[dvipdfmx]{graphicx}, o ejecutar antes extractbb sample.png para dejar preparado un archivo .xbb con %%BoundingBox: 0 0 8 8. Que pdflatex nunca muestre este error se debe simplemente a que pdfTeX sí sabe leer una cabecera PNG.
# ! LaTeX Error: Cannot determine size of graphic in sample.png (no BoundingBox).
# fix 1 - name the driver in the preamble:
# \usepackage[dvipdfmx]{graphicx}
# fix 2 - write the bounding box out first:
extractbb sample.png
cat sample.xbb
# %%Title: sample.png
# %%Creator: extractbb 20240305
# %%BoundingBox: 0 0 8 8
# %%HiResBoundingBox: 0.000000 0.000000 8.000000 8.000000El orden de la decisión, pues. Elija por idioma y paquetes, no por formato de salida: japonés significa (u)platex y dvipdfmx, PSTricks significa la ruta PostScript, todo lo demás significa PDF directo. Después iguale los formatos de imagen: en la ruta DVI, PDF o EPS, o bien PNG y JPEG pasados por extractbb. Y por último nombre el controlador explícitamente: escriba [dvipdfmx] tanto en graphicx como en hyperref, y quien reconstruya el documento por otra ruta más adelante no caerá en el mismo agujero. El DVI, entretanto, sigue sin saber qué color ni qué imagen transporta.