# How do I check whether the text will fit in one page?

I am trying to typeset a page that varies in length. Sometimes it's just shorter than A4, but sometimes it exceeds the length of A4.
My question is, how can I check whether the text will fit in one page and if it doesn't I want to fit as much as I can on one page, then add something like "(shortened)" and hide the rest of the text so it doesn't appear on the second page?

-
Is think this should be possible using \pagetotal and \pagegoal, see How to define a figure size so that is consume the rest of a page?. However, the trick is how to apply it to the text. – Martin Scharrer May 23 '11 at 10:44
It depends also on the nature of the material: does it contain a header such as the title or only ordinary text? – egreg May 23 '11 at 11:05
@egreg Yes, there is a title. I'm not sure why does it matter (I'm new to LaTeX) – Matej Cizik May 23 '11 at 11:28

Try putting this magic code immediately before \begin{document}

\newbox\boxA
\newtoks\loutput
\loutput=\output
\let\lenddocument\enddocument

\makeatletter
\output={\outA}
\def\outA{\global\setbox\boxA=\box255 \global\output={\outB}}
\def\outB{\setbox2=\vbox{\unvbox255\vskip 0pt plus 1filll }
\global\output=\loutput
\setbox0=\vbox to\vsize{
\unvbox\boxA
\ifdim\ht2>\topskip
\vbox to0pt{
\vskip6pt
\hbox to\hsize{\hfil\small\itshape Shortened}
\vss
}\fi
}%
\unvbox0 \aftergroup\lenddocument}


This should work in the simplest cases, but references and floats are not (completely) supported.

Some explanations. The final pages are produced when TeX calls the output routine: it gathers a page (without headers or footers and footnotes), assembles it in the box register number 255 and does what is contained in the token list \output. Here I save the usual code in \output in the token variable \loutput and change it to mean \outA. In turn \outA means: put the box containing the page into box register \boxA, then change the output routine to execute \outB. Since output routines are performed in a group, it's necessary to use \global, here.

What does \outB? It sends the content of \box255 into box register 2, but "unboxing it" and adding infinite glue, as the normal height of \box255 is the page height, so we shrink it to its natural size (unless somebody has used third order infinite glue in the document, which is unlikely). We now revert the output routine to the standard one in LaTeX and build a new box by unboxing box register \boxA (that contains the first page) and adding after it a zero height box containing the "Shortened" indication, but only if box register 2 contains something other than the \topskip, hence some text.

Now the output routine comes into action because we unbox box register 0 and execute, when the group ends, the normal \end{document}, so no more of the paper will be read.

I didn't test it very extensively, but it seems that "normal" papers should be processed correctly.

Other approaches (1) Reserve a bunch of box registers and change \shipout to mean "put the completed page in box n" and step a counter; at the end of the job look if "box 2" is empty; if not, add the "shortened" tag to it as done before; then ship out the new "box 1".

(2) Use pdfpages: compile the paper, write in an auxiliary file the number of pages and compile a new document that includes only the first page, adding the "shortened" tag if the number of pages is >1.

My original method and method (1) have a drawback: non immediate writes to auxiliary files are expanded and performed only during the output routine, so we lose all references after pages 1 and 2. This is not the case with method (2), which probably is the best.

Environment method

\documentclass[a4paper]{article}
\usepackage{lipsum}
\newsavebox{\shbox}\newlength{\shlen}
\newenvironment{shorten}[1][\textheight]
{\shlen=#1\relax\setbox\shbox=\vbox\bgroup}
{\egroup\doshorten}

\newcommand{\doshorten}{%
\ifdim\ht\shbox>\shlen
\setbox\shbox=\vsplit\shbox to\shlen
\setbox\shbox=\vbox to\shlen{
\dimen0=\dp\shbox
\unvbox\shbox
\kern-\dimen0
\vbox to0pt{
\vskip12pt
\hbox to\hsize{\hfil\small\itshape Shortened}
\vss
}
\vfill
}
\fi
\begin{figure}[p]
\centering
\kern-3.4pt\hrule\kern3pt
\box\shbox
\kern3pt\hrule\kern-3.4pt
\end{figure}
}

\begin{document}

A\lipsum

\begin{shorten}
B\lipsum
\end{shorten}

\begin{shorten}[.5\textwidth]
C\lipsum
\end{shorten}

D\lipsum

\begin{shorten}
E\lipsum[2]
\end{shorten}

\end{document}


The shorten environment will put some text into a floating environment (I've chosen figure); the text will be typeset and only what fits into one page (or in the length specified as optional argument) will be set in the page float. In order to distinguish this float from the context, rules fore and aft are appended.

The text is set into a \vbox. We examine its height and, if it's less than the desired height we do nothing; otherwise we cut off what exceeds the desired height with \vsplit, then we massage a bit the box, adding a \vfill to cure possible "underfull" situations and the "shortened" message. Finally the box is printed, preceded and followed by rules, in a figure environment.

-
@egreg Could you add a bit of explanation of the magic for the non-magicians? (Especially since this is all plain TeX.) – Alan Munn May 23 '11 at 15:01
@egreg Thanks! Over and above the call of duty is this explanation! – Alan Munn May 23 '11 at 20:57
@egreg Your answer is awesome. It does almost what I want it to do. It shortens the text but there is always one line (and "Shortened") on the second page. I can't get it all on one page. Am I doing something wrong? – Matej Cizik May 24 '11 at 7:13
@Matej: please, add an example to your question so that I can test it. – egreg May 24 '11 at 7:19
@egreg: All I have in my code is \documentclass{article} followed by your code, next is \begin{document}, bunch of text (lorem ipsum) to fill the page and \end{document}. There's always one line of text on the second page followed by line containing Shortened. – Matej Cizik May 24 '11 at 7:37