Compilando LuaLaTeX a varios PDF
Un libro que compuse recientemente fue un volumen de actas de un congreso de crítica textual donde los capítulos
consistían en las contribuciones de cada ponente. Cuando el libro se publicase tenía que mandarles a los autores una
separata en PDF de su artículo. Había cerca de una veintena de artículos. Separar el PDF del volumen en distintos
PDFs, por rango de página, no tiene ninguna dificultad y hay muchas herramientas para ello, tanto gráficas como de línea
de comandos. De este último grupo yo suelo usar casi siempre el versátil script pdfjam
, que ejecuta pdfLATEX
en segundo plano. Incluso tengo escrita una función para Emacs que agiliza bastante el proceso. El problema es que hacer
tantos cortes en un PDF resulta un proceso pesado y repetitivo, siendo la pesadez mayor la de ir mirando cada rango de
páginas para ir creando las separatas.
Ante un paisaje así, uno puede pensar si sería posible que LuaLATEX compilara no un solo PDF, sino varios PDF por capítulo. La respuesta rápida suele ser «no». Pero si nos dejan algo más de tiempo para contestar, podemos explicar este apaño, que consiste en los siguientes dos pasos:
- Hacer que LuaLATEX genere un script en shell que contenga, de manera reiterada, las órdenes de pdfjam para separar cada capítulo del PDF final.
- Pedirle también a LuaLATEX que ejecute ese script cuando ya haya completado su trabajo de compilar el PDF «grande». Así, al final tendremos, junto a éste, todos sus PDF «vástagos».
Claro, la situación es muy idílica. Pero el problema se concreta en: ¿Cómo sabe LuaLATEX de qué página a qué
página cortar y cómo se las apañará para generar nuestro script durante la compilación. Para el primer escollo tenemos
una muy buena solución con el paquete pageslts
, que nos permite declarar diversos valores variables / contadores como
CurrentPage
1. Para lo segundo, nuestro mejor aliado son las primitivas de TEX \immediate\write\
, que se
encargan de generar un archivo de texto en la compilación, nuestro ansiado script. Quedaría ver cómo hacer que luego
lo ejecute LuaLATEX, pero eso lo dejamos para el final. De momento, comenzamos a hacer lo que más nos divierte,
que es escribir código.
Nuestro preámbulo
Partamos de un ejemplo hipotético donde tenemos tres capítulos (clase book
) y un poco de texto introductorio antes.
Comenzamos cargando lo mínimo necesario para nuestro ejemplo, que llamaremos ejemplo.tex
:
\documentclass[a4paper]{book} \usepackage{pageslts} % Nos hará falta también el paquete calc \usepackage{calc} % y lipsum, para generar texto falso \usepackage{lipsum}
A continuación, declaramos una variable / contador para la primera página y nos aseguramos de comenzar con el valor de 1
:
\newcounter{PrimPag} \setcounter{PrimPag}{1}
En este punto, declaramos el archivo de texto (ergo el script) que escribirá LuaLATEX por nosotros:
\newwrite\script \immediate\openout\script=separatas.sh %% Así se llamará nuestro script
Y, como se trata de un script de bash, la orden necesaria para que se añada al principio de todo el shebang (ojo,
no podemos escribir literalmente «#», porque nos traerá un problema de catcodes. Tenemos que anteponer antes un \string
:
\immediate\write\script{\string#!/bin/bash} % escribe el shebang
Una vez escrito todo esto, ahora es cuando viene el meollo del asunto: nuestro comando de LATEX que se encargue de
añadir las sucesivas órdenes de pdfjam
para que se corte cada capítulo. La idea es que el valor de nuestro contador
PrimPag
vaya variando tras corte. Así pues, el rango será <el valor de PrimPag +1>
(de ahí nuestra necesidad de
cargar el paquete calc
a <el valor que tenga CurrentPage en cada caso>
:
\newcommand{\separata}[1]{% %la orden de pdfjam: \immediate\write\script{pdfjam\space \jobname.pdf\space \thePrimPag -\theCurrentPage\space -o\space \jobname-#1.pdf}% % recalcula el valor de PrimPag añadiendo 1 \setcounter{PrimPag}{\theCurrentPage+1} }
Nuestro documento
Escribimos el cuerpo de nuestro documento de ejemplo, con la siguiente estructura:
\begin{document} \pagenumbering{arabic} % necesario para pageslts % Texto introductorio antes de los capítulos. Este también lo cortará, pero no nos hará % falta al final \lipsum[1-50] % Nuestro primer corte: \separata{intro} %% Ojo, por defecto en la clase book los capítulos comienzan siempre en página impar. Para %% asegurar bien la primera página del rango, debemos actualizarla antes de cada capítulo \setcounter{PrimPag}{\theCurrentPage} \chapter{Primer artículo} \lipsum[1-30] %nuestro segundo corte \separata{Primer_artículo} \setcounter{PrimPag}{\theCurrentPage} \chapter{Segundo artículo} \lipsum[1-30] %nuestro tercer corte \separata{Segundo_artículo} \setcounter{PrimPag}{\theCurrentPage} \chapter{Tercer artículo} \lipsum[1-30] %nuestro cuarto corte \separata{Tercer_artículo} % Y aquí añadimos el término "exit" al script y lo cerramos \immediate\write\script{exit}% \immediate\closeout\script% \end{document}
Si compilamos nuestro documento, obtendremos el PDF grande y, de propina, nuestro script ya listo para ejecutarlo
cuando queramos, separatas.sh
, que habrá quedado, finalmente, con este contenido:
#!/bin/bash pdfjam ejemplo.pdf 1-9 -o ejemplo-intro.pdf pdfjam ejemplo.pdf 10-16 -o ejemplo-Primer_artículo.pdf pdfjam ejemplo.pdf 17-22 -o ejemplo-Segundo_artículo.pdf pdfjam ejemplo.pdf 23-28 -o ejemplo-Tercer_artículo.pdf exit
Pero si hemos llegado hasta aquí, seguramente habremos alcanzado tal nivel de excelencia en la pereza que querremos
delegar la ejecución del script en el propio LuaLATEX. Fácil. Tendremos que cargar en nuestro documento el
paquete shellesc
, que nos permitirá ejecutar comandos de shell en la compilación. Y al final de nuestro documento,
justo antes del \end{document}
, añadimos tres órdenes: una para darle permisos de ejecución al script, otra para
correr de nuevo LuaLATEX y que pueda generarse aquél. La última, la propia ejecución del script
\ShellEscape{% chmod a+x separatas.sh && lualatex ejemplo.tex && ./separatas.sh}
Con esta macro añadida (\ShellEscape
) no podremos compilar nuestro documento de manera normal, porque no tendrían
efecto los tres anteriores comandos de shell. La razón es que LATEX no tiene permisos para ejecutar órdenes del
sistema, a fin de evitar catástrofes inesperadas. Debemos correr la compilación desde línea de comandos, con la opción
shell-escape
:
lualatex --shell-escape ejemplo.tex
∞
Publicado: 07/11/2019
Última actualización: 07/11/2019
Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.
Notas al pie de página:
Para esta ingeniosa argucia me he inspirado en una de las respuestas de este hilo de texstackexchange.