Fitting and centering text (both!) in a constrained area

Okay, TeX isn't really designed with this in mind. That said, it can be done (sort of).

\documentclass{article}
\usepackage{lmodern}
\newdimen\fontdim
\newdimen\upperfontdim
\newdimen\lowerfontdim
\newif\ifmoreiterations
\fontdim12pt
\makeatletter
\def\buildbox{%
        \setbox0\vbox{\fontsize{\fontdim}{1.2\fontdim}%
                      \selectfont
                      \centering
                      \stuff}%
        \dimen@\ht0
        \advance\dimen@\dp0
        %\message{Total height: \the\dimen@^^J}
}

\newcommand\fillthepage[1]{%
        \protected@edef\stuff{#1}%
        \buildbox
        % Compute upper and lower bounds
        \ifdim\dimen@>\textheight
                \loop
                        \fontdim.5\fontdim
                        \buildbox
                \ifdim\dimen@>\textheight
                \repeat
                \lowerfontdim\fontdim
                \upperfontdim2\fontdim
                \fontdim1.5\fontdim
        \else
                \loop
                        \fontdim2\fontdim
                        \buildbox
                \ifdim\dimen@<\textheight
                \repeat
                \upperfontdim\fontdim
                \lowerfontdim.5\fontdim
                \fontdim.75\fontdim
        \fi
        % Now try to find the optimum size
        \loop
                %\message{Bounds: \the\lowerfontdim\space
                %         \the\fontdim\space \the\upperfontdim^^J}
                \buildbox
                \ifdim\dimen@>\textheight
                        \moreiterationstrue
                        \upperfontdim\fontdim
                        \advance\fontdim\lowerfontdim
                        \fontdim.5\fontdim
                \else
                        \advance\dimen@-\textheight
                        \ifdim\dimen@<10pt
                                \lowerfontdim\fontdim
                                \advance\fontdim\upperfontdim
                                \fontdim.5\fontdim
                                \dimen@\upperfontdim
                                \advance\dimen@-\lowerfontdim
                                \ifdim\dimen@<.2pt
                                        \moreiterationsfalse
                                \else
                                        \moreiterationstrue
                                \fi
                        \else
                                \moreiterationsfalse
                        \fi
                \fi
        \ifmoreiterations
        \repeat
        % build the page
        \newpage
        \null
        \vfill
        \box0
        \vfill
}
\makeatother
\usepackage{lipsum}
\begin{document}
\fillthepage{\lipsum}
\fillthepage{\lipsum[1]}
\fillthepage{Very little}
\end{document}

You can uncomment out the \messages if you want to see how it decides on the font sizes to use. It doesn't make any effort to constrain horizontal size, so if you don't give it enough text to work with, you'll run off the right side of the page. (Try \fillthepage{X} for an example of that.)

It's pretty much essential that you use a vector font, otherwise it'll tend to go back and forth between two font sizes, spewing warnings and probably never converge. That's why I have the \usepackage{lmodern}.

I'm sure there are (many) cases where this doesn't work, but it was sort of fun to write.

Edit: Maybe that \protected@edef should just be a \def. I was originally thinking expanding it would be better, but now I'm not so sure

Tags:

Minipage