Quiero llenar una página con una sola palabra o frase repetida una y otra vez. Luego imprimiré esta página. Por ejemplo,
\documentclass[12pt]{article}
\usepackage[margin=0.5in]{geometry}
\usepackage{pgffor}
\begin{document}
\thispagestyle{empty}
\pagestyle{empty}
\setlength{\parindent}{0cm}
\def\Phrase{Phrase to repeat }
\def\repititions{400}%The issue is with the number 400.
\foreach \n in {0,...,\repititions}{\Phrase}
\end{document}
Sin embargo, llegué a la cifra 400
mediante prueba y error. Esto no es realmente un problema, ya que imprimiré la página para poder configurar el número \repetition
para que sea arbitrariamente grande. Más bien es una molestia.
Entonces, mi pregunta es:
¿Hay alguna manera de detener el bucle al final de una página, en lugar de obtener el valor
400
mediante prueba y error?
Respuesta1
El creador de páginas es asincrónico y TeX no tiene idea de dónde termina una página al escribir un párrafo. Sólo cuando un párrafo ha finalizado se toman decisiones de salto de página.
Mi estrategia es construir el párrafo gigantesco en un cuadro que luego se compara con la altura del texto deseado. Si todavía está debajo, se prepara un nuevo cuadro con más repeticiones. Cuando tenemos suficiente material (la altura de la página más tres líneas para estar seguros), el cuadro se divide a la altura deseada y se coloca en la página actual.
\documentclass[12pt]{article}
\usepackage[
margin=0.5in,
heightrounded, % whole number of lines on the page
showframe, % just for the example
]{geometry}
\usepackage{expl3}
\ExplSyntaxOn
% faster than \pgffor
\cs_set_eq:NN \repeatphrase \prg_replicate:nn
\ExplSyntaxOff
\pagestyle{empty}
\setlength{\parindent}{0cm}
\begin{document}
\def\Phrase{Phrase to repeat }
\count255=200 % or anything that seems fit
\loop
\typeout{Trying \the\count255\space\space repetitions}
\setbox0=\vbox{\repeatphrase{\count255}{\Phrase}}
\ifdim\ht0<\dimexpr\textheight+3\baselineskip\relax
\advance\count255 by 20
\repeat
\setbox0=\vbox to \textheight{
\vbadness=10000 % remove a spurious message
\vsplit0 to \textheight
}
\unvbox0
\end{document}
Los mensajes en el terminal y el archivo de registro son
Trying 200 repetitions
Trying 220 repetitions
Trying 240 repetitions
Trying 260 repetitions
Trying 280 repetitions
Trying 300 repetitions
Trying 320 repetitions
El punto de partida es 200, una estimación aproximada de lo que se necesita (se podría empezar desde 1, pero no parece significativo).
Tenga en cuenta que LaTeX no tiene una interfaz pública \vsplit
, por lo que tenemos que recurrir a programación de nivel inferior.
Aquí hay una versión completa expl3
que es esencialmente la misma. Acabo de agregar una pequeña flexibilidad al salto entre líneas para llenar mejor la página.
\documentclass[12pt]{article}
\usepackage[
margin=0.5in,
heightrounded, % whole number of lines on the page
showframe, % just for the example
]{geometry}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\fillpage}{O{200}m}
{
\clearpage
\egreg_fillpage:nn { #1 } { #2 }
\clearpage
}
\int_new:N \l__egreg_fillpage_copies_int
\box_new:N \l__egreg_fillpage_box
\cs_new_protected:Npn \egreg_fillpage:nn #1 #2
{
\int_set:Nn \l__egreg_fillpage_copies_int { #1 }
\bool_do_until:nn
{
\dim_compare_p:nNn { \box_ht:N \l__egreg_fillpage_box } > { \textheight + 3\baselineskip }
}
{
\typeout{Trying~\int_eval:n { \l__egreg_fillpage_copies_int }~repetitions}
\vbox_set:Nn \l__egreg_fillpage_box
{
\skip_set:Nn \baselineskip { 1\baselineskip plus 0.1pt }
\prg_replicate:nn { \l__egreg_fillpage_copies_int } { #2 }
}
\int_add:Nn \l__egreg_fillpage_copies_int { 20 }
}
\vbox_set_split_to_ht:NNn \l__egreg_fillpage_box \l__egreg_fillpage_box { \textheight }
\box_use_drop:N \l__egreg_fillpage_box
}
\ExplSyntaxOff
\pagestyle{empty}
\setlength{\parindent}{0cm}
\begin{document}
\fillpage{Phrase to repeat }
\end{document}
El comando \fillpage
tiene un argumento opcional para establecer el número inicial de repeticiones (200 por defecto), por lo que
\fillpage[300]{Phrase to repeat }
Empezaría desde 300.
Respuesta2
Mi solución solo imprime una vez el texto repetido en el cuadro temporal0. Entonces este box0 está \vsplit
en la página actual.
Se proporciona la macro \toendpage{repeated text}
. Esta macro llena la página actual desde el punto actual (es irrelevante si está al principio de la página o en el medio de la página) hasta el final de la página.
La macro \toendpage
necesita hacer un cálculo de cuántas repeticiones del texto necesitamos. Este número debe ser suficientemente grande, por lo que se calcula como
(1.3 * \hsize
/ ancho_del_texto + 1) * líneas_en_el_\pagegoal
La macro sigue:
\newcount\tmpnum
\def\toendpage#1{\par \bgroup
\setbox0=\hbox{#1}
\null \nobreak \vskip-\baselineskip % we need to set \pagegoal and set zero \prevdepth
\dimen0=\pagegoal
\divide\dimen0 by\baselineskip
\tmpnum=\dimen0 % \tmpnum= number of lines in \pagegoal
\dimen0=1.3\hsize
\divide\dimen0 by\wd0 % \dimen0= number of text in 1.3\hsize
\advance\dimen0 by1sp % increased by one
\multiply\dimen0 by\tmpnum % \dimen0= number of repeats of the text
\tmpnum=0
\setbox0=\vbox{\null \loop #1\advance\tmpnum by1 \ifnum\tmpnum<\dimen0 \repeat}
\vbadness=10000
\dimen0=\pagegoal \advance\dimen0 by-\pagetotal
\setbox0=\vsplit0 to\dimen0 % \vsplit to the end of the current page
\unvbox0
\vfil\break \egroup
}
Usage:
\toendpage{This is repeated text. }