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?

  • You can use a savebox, at least if you use \captionof{figure}. See the \setbox code in tex.stackexchange.com/questions/415917/… – John Kormylo Jan 19 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 at 18:27
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}
|improve this answer|||||
  • 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 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. – John Kormylo Jan 20 at 22:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.