2

I want a function that automatically detects if a figure and its caption will run of the page when used within the wrapfigure environment, such that it will stay with the text that I placed it with in the code. For this I have found a usefull thread here already, from where I used James Ashtons answer to come up with the following solution.

\newsavebox\curwrapfig
\makeatletter
\long\def\wrapfiguresafe#1#2#3{%
  \sbox{\curwrapfig}{ 
        \includegraphics[scale = \figureScale]{#1}
    }
  \par\penalty-100%
  \begingroup % preserve \dimen@
    \dimen@\pagegoal \advance\dimen@-\pagetotal % space left
    \advance\dimen@-\baselineskip % allow an extra line
    \ifdim \ht\curwrapfig>\dimen@ % not enough space left
      \break%
    \fi%
  \endgroup%
  \begin{wrapfigure}{O}{0.5\textwidth}
        \centering
        \includegraphics[scale = \figureScale]{#1}
        \caption{#3}
        \label{#2}
  \end{wrapfigure}
}
\makeatother

However, this solution does not include the caption height. Therefore, I have replaced the savebox in the above code with the following

\sbox{\curwrapfig}{ \parbox{0.5\textwidth}
    {
        \addtocounter{figure}{1}
        \includegraphics[scale = \figureScale]{#1}
        \vspace{0.7\abovecaptionskip}
        \newline \small
        \textbf{Figure \thefigure:} #3
        \addtocounter{figure}{-1}
    }
}

Now the problem is that this solution does not seem to work. In fact the measured height seems to be even less now, i.e. figures that first lead to a page break do not do so anymore after my attempt to include the caption height. To illustrate this I have created the following minimal working example. Here, when using the first savebox, a pagebreak is placed before image A is placed. Image B has a long caption and is moved to the next page, but not beside the intended text. When using the second savebox to resolve this issue, now also image A is moved to the next page without its text.

\documentclass{article}

\usepackage{wrapfig}
\usepackage{lipsum}
\usepackage{graphicx}

\newsavebox\curwrapfig
\makeatletter
\long\def\wrapfiguresafe#1#2#3{%
  \sbox{\curwrapfig}{ 
    \includegraphics[height=#2]{#1}
  }
  %\sbox{\curwrapfig}{ \parbox{0.5\textwidth}
    %{
      %\addtocounter{figure}{1}
      %\includegraphics[height=#2]{#1}
      %\vspace{0.7\abovecaptionskip}
      %\newline \small
      %\textbf{Figure \thefigure:} #3
      %\addtocounter{figure}{-1}
    %}
  %}
  \par\penalty-100%
  \begingroup % preserve \dimen@
    \dimen@\pagegoal \advance\dimen@-\pagetotal % space left
    \advance\dimen@-\baselineskip % allow an extra line
    \ifdim \ht\curwrapfig>\dimen@ % not enough space left
      \break%
    \fi%
  \endgroup%
  \begin{wrapfigure}{O}{0.5\textwidth}
        \centering
        \includegraphics[width = 0.45\textwidth,height=#2]{#1}
        \caption{#3}
  \end{wrapfigure}
}
\makeatother

\begin{document}

\paragraph{1} \lipsum[1]
\paragraph{2} \lipsum[2]
\paragraph{3} \lipsum[3]

\wrapfiguresafe{example-image-a}{65mm}
{This is figure A, paragraph \textbf{4} should be right beside this figure on a new page.}

\paragraph{4} \lipsum[4]
\paragraph{5} \lipsum[5]

\wrapfiguresafe{example-image-B}{40mm}
{This is figure B, paragraph \textbf{6} should be right beside this figure. Figure B has a very long caption, and therefore it will surely run off the page. Because 'O' was specified, figure B is moved to the next page, but in doing so it is separated from paragraph \textbf{6}}

\paragraph{6} \lipsum[6]
\paragraph{7} \lipsum[7]

\end{document}

Does anybody know a good way to measure the height of a figure including its caption, such that this measurement can be used to check for a page break?

2
  • You can use a savebox, at least if you use \captionof{figure}. See the \setbox code in tex.stackexchange.com/questions/415917/… Jan 19, 2020 at 17:19
  • Thanks for your comment, I have tried to use the code that you referred to but I could not get it to work. First of all '\captionof{}' seems to be part of the caption package, which I am not familiar with. Nonetheless, I included the package, but when using '\captionof{}' I got quite some errors. I also tried to use '\setbox\curwrapfigure=\sbox{\parbox{0.5\textwidth}{ ... } }'. But in doing so figure A actually disappears. Could you provide me with a bit more information regarding your solution? Or if you are able to do so, a working example will be much appreciated.
    – Sjonnie
    Jan 19, 2020 at 18:27

1 Answer 1

2

Note that wrapfig and lipsum don't play well together. I was not aware of \pagetotal but if is accurate, this should work the way you want.

\documentclass{article}

\usepackage{wrapfig}
\usepackage{lipsum}
\usepackage{graphicx}

\newsavebox\curwrapfig
\makeatletter
\long\def\wrapfiguresafe#1#2#3{%
  \setbox\curwrapfig=\vbox{\hsize=0.5\textwidth
    \def\@captype{figure}%
    \centering
    \includegraphics[width=0.45\textwidth,height=#2]{#1}
    \caption{#3}
  }%
  \par\penalty-100%
  \begingroup % preserve \dimen@
    \dimen@\pagegoal \advance\dimen@-\pagetotal % space left
    \advance\dimen@-\baselineskip % allow an extra line
    %\the\dimen@
    \ifdim \ht\curwrapfig>\dimen@ % not enough space left
      \clearpage
    \fi%
  \endgroup%
  \begin{wrapfigure}{O}{0.5\textwidth}
        \usebox\curwrapfig
  \end{wrapfigure}
}
\makeatother

\begin{document}
\sloppy
\paragraph{1} \LipsumPar{1}
\paragraph{2} \LipsumPar{2}
\paragraph{3} \LipsumPar{3}

\wrapfiguresafe{example-image-a}{65mm}
{This is figure A, paragraph \textbf{4} should be right beside this figure on a new page.}

\paragraph{4} \LipsumPar{4}
\paragraph{5} \LipsumPar{5}

\wrapfiguresafe{example-image-b}{40mm}
{This is figure B, paragraph \textbf{6} should be right beside this figure. Figure B has a very long caption, and therefore it will surely run off the page. Because 'O' was specified, figure B is moved to the next page, but in doing so it is separated from paragraph \textbf{6}}

\paragraph{6} \LipsumPar{6}
\paragraph{7} \LipsumPar{7}

\end{document}

This version uses \needspace and a regular savebox.

\documentclass{article}

\usepackage{wrapfig}
\usepackage{lipsum}
\usepackage{graphicx}
\usepackage{needspace}

\newsavebox\curwrapfig
\makeatletter
\long\def\wrapfiguresafe#1#2#3{%
  \sbox\curwrapfig{\parbox{0.5\textwidth}{%
    \def\@captype{figure}%
    \centering
    \includegraphics[width=0.45\textwidth,height=#2]{#1}
    \caption{#3}
  }}%
  \needspace{\dimexpr \ht\curwrapfig+\dp\curwrapfig+2\intextsep}%
  \begin{wrapfigure}{O}{0.5\textwidth}
    \usebox\curwrapfig
  \end{wrapfigure}
}
\makeatother

\begin{document}
\sloppy
\paragraph{1} \LipsumPar{1}
\paragraph{2} \LipsumPar{2}
\paragraph{3} \LipsumPar{3}

\wrapfiguresafe{example-image-a}{65mm}
{This is figure A, paragraph \textbf{4} should be right beside this figure on a new page.}

\paragraph{4} \LipsumPar{4}
\paragraph{5} \LipsumPar{5}

\wrapfiguresafe{example-image-b}{40mm}
{This is figure B, paragraph \textbf{6} should be right beside this figure. Figure B has a very long caption, and therefore it will surely run off the page. Because 'O' was specified, figure B is moved to the next page, but in doing so it is separated from paragraph \textbf{6}}

\paragraph{6} \LipsumPar{6}
\paragraph{7} \LipsumPar{7}

\end{document}
2
  • Both solutions work like a charm, also in the document that I needed a solution for. Thanks! Regarding \pagetotal, in the documentation of \needspace I read \pagetotal is also being used. Thanks again, you were very helpful!
    – Sjonnie
    Jan 20, 2020 at 10:02
  • One can also use a \rule, negative \vspace and a \newline. If the \rule fits, the \vspace moves it back to the starting point. If the page beaks, the \vspace is ignored. Jan 20, 2020 at 22:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .