[Tex/LaTex] Prevent widowing/orphaning of sections that can fit on one page

page-breakingsectioningsections-paragraphswidows-orphans

In my LaTeX document, I want to make it so that sections that can fit entirely on one page are automatically forced to start on the next page so that the section does not get widowed/orphaned. The document has images. If the section is capable of fitting on one page, then I want the equivalent effect of having "\clearpage" before that section. I need this process to be automated because, in the "real" document, the data is auto-generated. Here is a working example:

% test.tex
% For mypic.jpg I used this example image: http://media.istockphoto.com/photos/yellow-flowers-picture-id506321010

\documentclass[letterpaper,12pt,twoside,onecolumn,notitlepage]{report}
\usepackage{float}
\usepackage{lipsum}
\usepackage{graphicx}
\usepackage[margin=0.7in]{geometry}
\raggedbottom
\begin{document}
\chapter{First chapter}


% Want LaTeX to automatically put the equivalent of a \clearpage here.
\section{First section}
The image in this section is going to be widowed onto the next page.  If I hypothetically put ``{\textbackslash}clearpage" before this section, then the entire section including the image would fit on one page.  I'd like to make LaTeX detect that and automatically force this section to start on the next page so that the image doesn't get widowed.

\lipsum[1-2]
\includegraphics[height=3.4in]{mypic.jpg}


% Don't want LaTeX to automatically put the equivalent of a \clearpage here.
\section{Second section}
This section has two images and cannot fit entirely on one page (putting ``{\textbackslash}clearpage" before the section would still result in the section spanning two pages anyway), so I'm fine having this section start here and having the images flow onto the next page -- i.e., I don't want to force this section to start on the next page.

\lipsum[1]

\includegraphics[height=3.4in]{mypic.jpg}

\vspace{\baselineskip}

\includegraphics[height=3.4in]{mypic.jpg}


% Don't want LaTeX to automatically put the equivalent of a \clearpage here.
\section{Third section}
This section has no images and fits on the same page after the second section, so I'm fine having it stay here and don't want to force it to start on the next page.


% Want LaTeX to automatically put the equivalent of a \clearpage here.
\section{Fourth section}
This is also a section that could fit entirely on one page and gets orphaned or widowed, so I'd like it to be automatically forced to start on the next page.

\lipsum[1-2]

\includegraphics[height=3.4in]{mypic.jpg}


\end{document}

Can this be done in LaTeX?

Best Answer

Here is one suggestion.

  • Change the auto-generation of the code so that

    \section{<title>}
    ...
    

    is replaced by

    \begin{chunk}{<title>}
      ...
    \end{chunk}
    
  • Use environ to define the environment chunk so that you can capture its contents and test its total height.

  • Use calc so that you can easily calculate the total height (i.e. height + depth) and to make it easier to manage dimensions.
  • Use needspace to reserve sufficient vertical space for the total height of the section if, and only if, that total height is not greater than the height of the text block.

The upshot of this will be to force a page break before the section unless either the section fits on the current page or the section needs more than a single page anyway.

chunked document

Code:

\documentclass[letterpaper,12pt,twoside,onecolumn,notitlepage]{report}
\usepackage{float}
\usepackage{lipsum}
\usepackage{graphicx}
\usepackage[margin=0.7in]{geometry}
\usepackage{environ,calc,needspace}
\raggedbottom
\newlength\chunktotheight
\NewEnviron{chunk}[1]{%
  \settototalheight{\chunktotheight}{%
    \begin{minipage}{\textwidth}
      \section{#1}
      \BODY
    \end{minipage}%
  }%
  \ifdim\chunktotheight>\textheight
  \else
  \needspace{\chunktotheight}%
  \fi
  \addtocounter{section}{-1}%
  \section{#1}
  \BODY
}{}
\begin{document}
\chapter{First chapter}

% Want LaTeX to automatically put the equivalent of a \clearpage here.
\begin{chunk}{First section}
  The image in this section is going to be widowed onto the next page.  If I hypothetically put ``{\textbackslash}clearpage'' before this section, then the entire section including the image would fit on one page.  I'd like to make \LaTeX{} detect that and automatically force this section to start on the next page so that the image doesn't get widowed.

  \lipsum[1-2]
  \includegraphics[height=3.4in]{mypic}% better not to specify the extension ; may not look quite the same as the original
\end{chunk}

% Don't want LaTeX to automatically put the equivalent of a \clearpage here.
\begin{chunk}{Second section}
  This section has two images and cannot fit entirely on one page (putting ``{\textbackslash}clearpage'' before the section would still result in the section spanning two pages anyway), so I'm fine having this section start here and having the images flow onto the next page -- i.e., I don't want to force this section to start on the next page.

  \lipsum[1]

  \includegraphics[height=3.4in]{mypic}

  \vspace{\baselineskip}

  \includegraphics[height=3.4in]{mypic}
\end{chunk}

% Don't want LaTeX to automatically put the equivalent of a \clearpage here.
\begin{chunk}{Third section}
  This section has no images and fits on the same page after the second section, so I'm fine having it stay here and don't want to force it to start on the next page.
\end{chunk}

% Want LaTeX to automatically put the equivalent of a \clearpage here.
\begin{chunk}{Fourth section}
  This is also a section that could fit entirely on one page and gets orphaned or widowed, so I'd like it to be automatically forced to start on the next page.

  \lipsum[1-2]

  \includegraphics[height=3.4in]{mypic}
\end{chunk}

\end{document}

EDIT

This is a response to the comment concerning difficulties including PDFs. Without an example, it is hard to say whether I've worked on the correct issue or not. However, I did fine a problem with use of \includepdf[]{} within a chunk, but not outside them.

The following code should solve this particular problem. The idea is that, since PDF inclusion always starts a new page, any section which includes \includepdf[]{} is necessarily going to require more than one page to typeset. Hence, we check for \includepdf[]{} and do nothing in that case.

To do the check, I simply use a toggle and temporarily redefine \includepdf[]{} to set the toggle true. The original definition is replaced after the check is complete.

\documentclass[letterpaper,12pt,twoside,onecolumn,notitlepage]{report}
\usepackage{float}
\usepackage{lipsum}
\usepackage{graphicx,pdfpages}
\usepackage[margin=0.7in]{geometry}
\usepackage{environ,calc,needspace}
\raggedbottom
\newlength\chunktotheight
\NewEnviron{chunk}[1]{%
  \let\savedincludepdf\includepdf
  \let\includepdf\chunkincludepdf
  \chunkincludepdffalse
  \settototalheight{\chunktotheight}{%
    \begin{minipage}{\textwidth}
      \section{#1}
      \BODY
    \end{minipage}%
  }%
  \ifdim\chunktotheight>\textheight
  \else
    \ifchunkincludepdf
    \else
    \needspace{\chunktotheight}%
    \fi
  \fi
  \let\includepdf\savedincludepdf
  \addtocounter{section}{-1}%
  \section{#1}
  \BODY
}{}
\newcommand*\chunkincludepdf[1][]{\chunkincludepdftrue}
\newif\ifchunkincludepdf
\chunkincludepdffalse
\begin{document}
\chapter{First chapter}

\includepdf{example-image-letter}

% Want LaTeX to automatically put the equivalent of a \clearpage here.
\begin{chunk}{First section}
  The image in this section is going to be widowed onto the next page.  If I hypothetically put ``{\textbackslash}clearpage'' before this section, then the entire section including the image would fit on one page.  I'd like to make \LaTeX{} detect that and automatically force this section to start on the next page so that the image doesn't get widowed.

  \lipsum[1-2]
  \includegraphics[height=3.4in]{mypic}% better not to specify the extension ; may not look quite the same as the original
\end{chunk}

% Don't want LaTeX to automatically put the equivalent of a \clearpage here.
\begin{chunk}{Second section}
  This section has two images and cannot fit entirely on one page (putting ``{\textbackslash}clearpage'' before the section would still result in the section spanning two pages anyway), so I'm fine having this section start here and having the images flow onto the next page -- i.e., I don't want to force this section to start on the next page.

  \lipsum[1]

  \includegraphics[height=3.4in]{mypic}

  \vspace{\baselineskip}

  \includegraphics[height=3.4in]{mypic}
\end{chunk}

% Don't want LaTeX to automatically put the equivalent of a \clearpage here.
\begin{chunk}{Third section}
  This section has no images and fits on the same page after the second section, so I'm fine having it stay here and don't want to force it to start on the next page.
\end{chunk}

\includepdf{example-image-letter}

% Want LaTeX to automatically put the equivalent of a \clearpage here.
\begin{chunk}{Fourth section}
  This is also a section that could fit entirely on one page and gets orphaned or widowed, so I'd like it to be automatically forced to start on the next page.

  \lipsum[1-2]

  \includegraphics[height=3.4in]{mypic}
\end{chunk}

\begin{chunk}{Fifth section}
  This include a full-page PDF, so obviously won't fit on one page.
  Hence, we don't expect a page break prior to this section unless there would be one anyhow.

  \lipsum[1]

  \includepdf{example-image-letter}

  \lipsum[2]
\end{chunk}


\end{document}

chunked document with include PDFs

Without the fix, the final PDF inclusion does not work correctly: the PDF is included twice, with the first inclusion overlaying the previous section. This happens since this inclusion is within a chunk, whereas the first two inclusions were not.

Related Question