2

About one and a half decades ago I tried printing a panorama with LaTeX and found a version with several calls to \afterpage, that worked for me. Meanwhile, I found a much more elegant, shorter, and better understandable algorithm by Martin Scharrer working after the same principle here: How to include a picture over two pages, left part on left side, right on right (for books)?, but I still use my own version ("never change a running system!").

A few days ago Ulrike Fischer had a look at my code and complained about my usage of \afterpage, which would destroy my footnotes: " It doesn't need to be inside the float, you can also move it behind the figure, it only matters here that it is executed while footnotes and floats are handled" and I should never use \afterpage (Footnotetext jumps to next page and back again).

So I replaced the one appearance of \afterpage Ulrike had specially hinted at and my original problem vanished. But afterward, I had a deeper look at my output, and hmm..., Ulrike is right: There are even more problems, I only got used to them over the years.

Since I wrote my algorithm, others have done so as well and I searched, whether they were able to solve the problem without \afterpage. But alas, I found \afterpage in Martin Scharrers algorithm as well as in the package hvfloat by Herbert Voß -- and both authors seem to know much more about LaTeX than me. Is it impossible to reach my aim without \afterpage?

So I tried another time, starting with Martin Scharrers code:

\documentclass[twoside]{book}

\usepackage{graphicx}
\usepackage{adjustbox}
\usepackage{placeins}
\usepackage{xcolor}

% For the `memoir` class remove the following two packages.
% This class already provide the functionality of both
\usepackage{caption}
\usepackage[strict]{changepage}
%%%

\setcounter{totalnumber}{1}
\setcounter{topnumber}{1}
\setcounter{bottomnumber}{1}
\renewcommand{\topfraction}{.99}
\renewcommand{\bottomfraction}{.99}
\renewcommand{\textfraction}{.01}

\makeatletter
\newcommand*{\twopagepicture}[4]{%
    \checkoddpage
    \ifoddpage
    \expandafter\suppressfloats% <-- replaced \afterpage by suppressfloats
    \else
    \expandafter\@firstofone% <-- and reversed order of \suppressfloats and \@firstofone
    \fi
    {{%  <-- deleted \afterpage here, replaced by reversed order two lines above
            \begin{figure}[#1]
                \if #2p%
                \if #1t%
                \thispagestyle{empty}% <-- moved here for moving with figure
                \vspace*{-\dimexpr1in+\voffset+\topmargin+\headheight+\headsep\relax}%
                \fi
                \fi
                \if #1b%
                \caption{#4}%
                \fi
                \makebox[\textwidth][l]{%
                    \if #2p\relax
                    \let\mywidth\paperwidth
                    \hskip-\dimexpr1in+\hoffset+\evensidemargin\relax
                    \else
                    \let\mywidth\linewidth
                    \fi
                    \adjustbox{trim=0 0 {.5\width} 0,clip}{\includegraphics[width=2\mywidth]{#3}}}%
                \if #1b\else
                \caption{#4}%
                \fi
                \if #2p%
                \if #1b%
                \vspace*{-\dimexpr\paperheight-\textheight-1in-\voffset-\topmargin-\headheight-\headsep\relax}%
                \fi
                \fi
            \end{figure}%
            \begin{figure}[#1]
                \if #2p%
                \if #1t%
                \thispagestyle{empty}% <-- moved here for moving with figure (replaces another \afterpage call)
                \vspace*{-\dimexpr1in+\voffset+\topmargin+\headheight+\headsep\relax}%
                \fi
                \fi
                \makebox[\textwidth][l]{%
                    \if #2p%
                    \let\mywidth\paperwidth
                    \hskip-\dimexpr1in+\hoffset+\oddsidemargin\relax
                    \else
                    \let\mywidth\linewidth
                    \fi
                    \adjustbox{trim={.5\width} 0 0 0,clip}{\includegraphics[width=2\mywidth]{#3}}}%
                \if #2p%
                \if #1b%
                \vspace*{-\dimexpr\paperheight-\textheight-1in-\voffset-\topmargin-\headheight-\headsep\relax}%
                \fi
                \fi
            \end{figure}%
    }}%
}
\makeatother

\usepackage{lipsum}
\begin{document}
    \lipsum
    \lipsum
    \twopagepicture{b}{l}{image}{Test}
    \lipsum
    \lipsum
    \twopagepicture{t}{l}{image}{Test}
    \lipsum
    \lipsum
    \twopagepicture{b}{p}{image}{Other test}
    \lipsum
    \lipsum
    \twopagepicture{t}{p}{image}{Other test with 
        very very very very very very very very very very very
        very very very very very very very very very very very
        very very very very very very very very very very very
        long caption
    }
    \lipsum
    \lipsum
    
\end{document}

The biggest problem for me was the \afterpage call, which was used if \twopagepicture was called on an odd page, as then the panorama breaks. But I had the idea, in that case to push both figures one page forward not with \afterpage, but with \suppressfloats.

Now I have two questions:

  1. The code of the MWE now works, if I replace "image" with the path to a quite wide image. Nevertheless, I am a bit anxious, about whether I have done a bad mistake again, as I do things, I have never done before. Are there any flaws visible again?

  2. One problem remaining is: My mechanism with \suppressfloats only works, if not another float of the queue gets between it and my two figures. I thought about a \FloatBarrier just above \checkoddpage, but that would only reduce the possibility, not be foolproof. Has anybody a better idea?

11
  • Why are you saying that your MWE works? figure 2 starts on an odd page with it. Beside this your code didn't break only because of afterpage, but as you also used the fewerfloatpages package which unravels pages and I have no idea if hvfloats will mess up if you load also fewerfloatpages (in general I think it would have made more sense to ask for additional float options in the latex kernel. It shouldn't be impossible to defer a float to the next odd/even page. Commented Jun 19, 2023 at 13:37
  • Ulrike -- I now took my MWE back from this Webpage, replaced "image" by a local image and all figures start at even pages, including fig. 2. I swear! ;-) I have never tested hvfloat, I only looked into the source code and found \afterpage as well -- and not only you told me, that that is dangerous, but I found the results in my text with my own code (not hvfloat!) -- so I didn't want to change everything for hvfloat, to possibly get the same problem.
    – ThorstenL
    Commented Jun 19, 2023 at 15:00
  • In in my original text it seems to make no difference, whether I use fewerfloatpages or not (I now tested it because of your comment), but I have uncommented it anyway since our last discussion.
    – ThorstenL
    Commented Jun 19, 2023 at 15:00
  • I don't quite understand your comment in brackets: Are there more options in the latex kernel to "push" a float to the next page?
    – ThorstenL
    Commented Jun 19, 2023 at 16:00
  • no they aren't. But you are not forbidden to make a feature request. Commented Jun 19, 2023 at 16:06

3 Answers 3

1

My MWE:

\documentclass[twoside]{book}%

%\usepackage[symmbound,leftcaption]{doublepagefloats}% <-- This is the package with the new command
\usepackage[symmbound]{doublepagefloats}% <-- This is the package with the new command
%\usepackage{doublepagefloats}% <-- This is the package with the new command

% For demonstration purposes
\usepackage{tikzducks}% Delivers figures for testing purposes
\usepackage{lipsum}% Delivers blind text


% Float placement:
\renewcommand{\textfraction}{0.16} % Smallest text portion on page with floats
\renewcommand{\topfraction}{0.84}  % Biggest portion for a float at page top
\renewcommand{\bottomfraction}{0.84} % Biggest portion for a float at page bottom
\renewcommand{\floatpagefraction}{0.95} %With more than this portion a float may cover a float page

\setcounter{topnumber}{2}% max. 2 floats at the top of a text page
\setcounter{bottomnumber}{2}%  max. 2 floats at the bottom of a text page
\setcounter{totalnumber}{4}% max. 2 floats in total on a text page (are 2 better?)


% For testing purposes on normal pages page numbers both in head and foot
\makeatletter
\def\ps@myheadings{%
    \def\@evenhead{\thepage\hfil\slshape  text for testing purposes}%
    \def\@oddhead{{\slshape text for testing purposes}\hfil\thepage}%
    \let\@mkboth\markboth%
    \let\@oddfoot\@oddhead\let\@evenfoot\@evenhead%
}%
\pagestyle{myheadings}
\makeatother

\begin{document}
    
% Very ugly, but double page tabular
\newcommand\mytabularhuge{%
    \Huge%
    \begin{tabular}{lllll}%
        \textbf{Entry 1} & \textbf{Entry 2} & \textbf{Entry 3} & \textbf{Entry 4} & \textbf{Entry 5} \\%
        \hline%
        Salad & House & Car & Nice garden & Never known before \\%
        hope & Fantasy & This is a very long entry & This is another very long entry & Later I will know \\%
        Don't know, how far still & Big lake & I don't believe in that & Ladies first! & I will never know \\%
    \end{tabular}}%
\newcommand\mytabularlarge{%
    \large%
    \begin{tabular}{lllll}%
        \textbf{Entry 1} & \textbf{Entry 2} & \textbf{Entry 3} & \textbf{Entry 4} & \textbf{Entry 5} \\%
        \hline%
        Salad & House & Car & Nice garden & Never known before \\%
        hope & Fantasy & This is a very long entry & This is another very long entry & Later I will know \\%
        Don't know, how far still & Big lake & I don't believe in that & Ladies first! & I will never know \\%
\end{tabular}}%

    % Wide panorama consisting of 5 ducks:
    \newcommand\panoramawide{\mbox{\includegraphics[width=.4\panowidth]{example-image-duck}\includegraphics[width=.4\panowidth]{example-image-duck}\includegraphics[width=.4\panowidth]{example-image-duck}\includegraphics[width=.4\panowidth]{example-image-duck}\includegraphics[width=.4\panowidth]{example-image-duck}}}
    \newcommand\panoramanarrow{\mbox{\includegraphics[width=.2\panowidth]{example-image-duck}\includegraphics[width=.2\panowidth]{example-image-duck}\includegraphics[width=.2\panowidth]{example-image-duck}\includegraphics[width=.2\panowidth]{example-image-duck}\includegraphics[width=.2\panowidth]{example-image-duck}}}

%-------- begin of text -----------

    \listoftables
    \vskip2\baselineskip
    \begin{figure}
        \centering
        \includegraphics[width=0.5\textwidth]{example-image-duck}
        \caption{A duck}
    \end{figure}
    \begin{figure}
        \centering
        \includegraphics[width=0.5\textwidth]{example-image-duck}
        \caption{A second duck}
    \end{figure}
    \begin{figure}
        \centering
        \includegraphics[width=0.5\textwidth]{example-image-duck}
        \caption{A duck}
    \end{figure}
    \begin{figure}
        \centering
        \includegraphics[width=0.5\textwidth]{example-image-duck}
        \caption{A second duck}
    \end{figure}
    \doublepagefloat{figure}{b}{l}{\panoramawide}{Test}% height (and keepaspectratio) may help with too high graphics
    \doublepagefloat{figure}{l}{l}{\panoramawide}{Other test}
    \doublepagefloat{figure}{h}{l}{\panoramawide}{Other test}
    \doublepagefloat{figure}{t}{l}{\panoramawide}{A figure, comparable to the table}
    \doublepagefloat{figure}{b}{p}{\includegraphics[width=\dimexpr2\textwidth+\gapwidth\relax, height=0.3\textheight]{example-image-duck}}{Still another test}
    \doublepagefloat{figure}{l}{p}{\includegraphics[width=\dimexpr2\textwidth+\gapwidth\relax, height=0.3\textheight]{example-image-duck}}{Still another test}
    \doublepagefloat{figure}{h}{p}{\includegraphics[width=\dimexpr2\textwidth+\gapwidth\relax, height=0.3\textheight]{example-image-duck}}{Still another test}
    \doublepagefloat{figure}{t}{p}{\includegraphics[width=\dimexpr2\textwidth+\gapwidth\relax, height=0.3\textheight]{example-image-duck}}{Still another test}
    \doublepagefloat{figure}{b}{p}{\panoramawide}{Other test}
    \doublepagefloat{figure}{l}{p}{\panoramawide}{Other test}
    \doublepagefloat{figure}{h}{p}{\panoramawide}{Still other test with 
        very very very very very very very very very very very
        very very very very very very very very very very very
        very very very very very very very very very very very
        long caption.
    }    
    \doublepagefloat{figure}{t}{p}{\panoramawide}{Test}% height (and keepaspectratio) may help with too high graphics    
\doublepagefloat{table}{h}{l}{\makebox[2\textwidth][c]{\mytabularlarge}}{A Table}

    % Quite some lipsums following to have enpough text for everything
    \lipsum
    \lipsum
    \lipsum
    \lipsum

    % And now we have a second table:
    \doublepagefloat[AAA]{table}{b}{p}{\makebox[2\paperwidth][c]{\mytabularhuge}}{Another Table}

    % Three small floats, but unfortunately only one per page, if you leave the command \restoreplacement commented out
    \begin{figure}
        \centering
        \includegraphics[width=0.5\textwidth]{example-image-duck}
        \caption{Never tired of ducks}
    \end{figure}
    \begin{figure}
        \centering
        \includegraphics[width=0.5\textwidth]{example-image-duck}
        \caption{Never, really~\ldots}
    \end{figure}
    \begin{figure}
        \centering
        \includegraphics[width=0.5\textwidth]{example-image-duck}
        \caption{Last duck}
    \end{figure}
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
    \lipsum
\end{document}

After quite some testing: This works for me, at least with all, I have thrown at it up to now. It works with a mixture of double-page floats and normal floats (figures and tables), it should (though not tested) work with newly defined floats as well.

It is not alone my own work, in the last two weeks I got tons of help here at StackExchange, and without I couldn't have done it.

Starting with the algorithm of Martin Scharrer (see question), I needed especially two algorithms for pushing a float to a certain page, both described at How to let a figure appear exactly on page 16? .

  1. One of them worked by pushing the float forward by emitting invisible floats of the same kind before the float to be pushed, till it was on the right page.

  2. The other one worked by Hooks before or after shipout, in which controlled by labels in the figure, the counter totalnumber was manipulated, which controls how many floats are printed on a page: After the last other float totalnumber was set to 0, at the two pages with the panorama to 1 and after the panorama back to its original state.

Both algorithms didn't work perfect in my eyes though:

  1. The invisible float algorithm was good at pushing the floats to the right place. But it might happen, that unasked-for following floats appeared already on the second page of the panorama.

  2. The totalnumber algorithm was good at avoiding the unasked-for floats on the second page of the panorama. But as totalnumber could only be manipulated from page to page, either one-half of my panorama tended to land already on the page of the last float. I could have avoided that by setting totalnumber to 1 long before -- but then only one float per page would have been possible perhaps a few pages before the float, and I didn't like that thought as well.

I ended up combining both algorithms. That was made a bit easier because I needed the hook anyway: For panoramas in the foot or head of the page I needed means to erase the normal head or foot of the page ...

How to use?
You can use it with \doublepagefloat[#1]{#2}{#3}{#4}{#5}{#6} with the parameters

  • #1: auxiliary caption, the one for the list of figures
  • #2: floattype, usually figure or table
  • #3: b: (b)ottom of page, t: (t)op of page h: (h)igh, i.e. top of text, l: (l)ow, i.e. bottom of text
  • #4: p: (p)aper, i.e. the content may be up to 2\paperwidth wide, will be centered to the gap between both pages and may stretch till the paper boundaries. It may be narrower though and then will still center. If the width of the content is exactly 2\textwidth+\gapwidth, it stretches from the left border of the left page text to the right border of the right page text. l: (l)ine, i.e. the content only uses the width of a line on both pages with a wide gap between both parts
  • #5: content, i.e. the image itself
  • #6: main caption, the text under the image

Already mentioned was a new length, \gapwidth. That is the width between the two text blocks on the left and the right page respectively. There are two options, you can call the package with, that change behavior for the complete document, both deal with the caption:

  • [symmbound], if called, leaves white space on the non-caption page just as high as the caption -- so the text starts or ends at the same height on both pages. If not called (the default), the space not needed for a caption is used for text as well.
  • [leftcaption] Per default the caption is printed on the right side. If you wish to have it on the left, call this option.

Known problems

  • This is only intended for single column use. I never intended it for multicolumn use, I never tested it with it.
  • captions may only span one paragraph. I tried to alter this, but I didn't manage.
  • it sometimes needs several compilation runs, first complaining about dead cycles.

Where do I get the package doublepagefloats?
I will post it in another answer, as it is too long for this one.

Edits
I edited this answer already twice, the first one I deleted completely, the second one I altered much -- both times, because meanwhile I had found a much better solution.

0
\documentclass[twoside]{book}
\usepackage{graphicx}
\usepackage{caption}
\usepackage{hvfloat}

\usepackage{lipsum}

\begin{document}
    \lipsum
    \lipsum
    \hvFloat[doublePage]{figure}{\includegraphics[doublefullPage]{felsen-wasser}}
        {This is the first double page image}{}

    \lipsum
    \lipsum

    \hvFloat[doublePage,sameHeight]{figure}{\includegraphics[doublefullPage]{felsen-wasser}}
    {This is the second double page image}{}

    \lipsum
    \lipsum

    \hvFloat[doublePAGE]{figure}{\includegraphics[doublefullPage]{felsen-wasser}}
    {This is the third double page image}{}

    \lipsum
    \lipsum

    \hvFloat[doublePAGE]{figure}{\includegraphics[doublefullPage]{felsen-wasser}}
    {This is the last double page image with a
        very very very very very very very very very very very
        very very very very very very very very very very very
        very very very very very very very very very very very
        long caption
    }{}

    \lipsum
    \lipsum
    
\end{document}

Page 4--5:

enter image description here

Page 8--9

enter image description here

Page 12--13

enter image description here

Page 16--17

enter image description here

12
  • Thank you, yes, that works as well. But if you look inside the sourcecode of hvfloat: It uses the package afterpage, just as I did in my old solution and Martin Scharrer in the solution, I started from. Because I had problems with afterpage in combination with floats and footnotes, I started to look for a solution without afterpage ...
    – ThorstenL
    Commented Jun 29, 2023 at 21:51
  • I know ; But the images are normal floats and footnotes can be used as usual together with floats. And, of course, \hvFloat[nonfloat,..] ... exists, but makes only sense in an appendix where nothing floats ...
    – user187802
    Commented Jun 30, 2023 at 6:21
  • In hvfloat.sty my editor finds the command \afterpage 82 times. Are you really sure, that that only regards non-floating floats? I admit, I haven't yet analyzed the code in depth really ... With my old afterpage solution I CAN use footnotes as well. Only when Ulrike Fischer told me, that afterpage is problematic in combination with floats and footnotes, I had a deeper look and understood, that some oddities in my text not just happened by accident, but because they are near to places, where I use floats, footnotes -- and \afterpage ...
    – ThorstenL
    Commented Jun 30, 2023 at 20:41
  • I wrote that you also can have a nonfloat. In general it is a float. I cannot see that \afterpage is problematic with a float, because it uses always the [t] or [b] setting.
    – user187802
    Commented Jul 1, 2023 at 5:10
  • First: I admit freely, that Herbert Voss and several others are far better at programming LaTeX than I am. Far, far better. I have made heavy use of \afterpage and I had to write my own macro for double page floats many years ago, as then there was no other solution around. And I did it with \afterpage. I had read, that David Carlisle (who else is much, much better at LaTeX than me) himself complained, that \afterpage might be a bit dangerous, but I ignored that, as I couldn't think of another solution then.
    – ThorstenL
    Commented Jul 2, 2023 at 11:16
0

The homebrew package doublepagefloats needed for my first answer -- unfortunately, it is too long to fit in my answer as well:

\NeedsTeXFormat{LaTeX2e}[1994/06/01]%
\ProvidesPackage{doublepagefloats}[%
           2023/06/22 
           v0.1
           double page floats]%
        
\extrafloats{20}% Techniques used in this package include generating quite some "invisible floats", which may prolong the queue
           
\newif\ifsymmbound\symmboundfalse% Text boundaries on left and right page of double page float different because of caption
\newif\ifleftcaption\leftcaptionfalse% Caption on right or left page?
\DeclareOption{symmbound}{\symmboundtrue}% With option [symmboundtrue] text boundaries equal on both pages
\DeclareOption{leftcaption}{\leftcaptiontrue}% With option [symmboundtrue] text boundaries equal on both pages

\DeclareOption*{\OptionNotUsed}% Warning, that option is not used
\ProcessOptions\relax%

\RequirePackage{adjustbox}% Delivers package{graphicx}
\RequirePackage{zref-abspage,zref-user, zref-pageattr}% Needed for zlabel{} and the mechanism, to erase foot or head of page
\RequirePackage[maxfloats=256]{morefloats}% For not getting the error "too many unprocessed floats"

\maxdeadcycles=200% An error "too many dead cycles" sometimes can occur because of the cycles in \pushfloattopage{}

% Exchange of \belowcaptionskip and \abovecaptionskip for caption above figure:
\newcommand\exch@ngec@ptionskip{%
    \let\dpf@templen\abovecaptionskip%
    \let\abovecaptionskip\belowcaptionskip%
    \let\belowcaptionskip\dpf@templen}%

% Width of the gap between the text on the left and the text on the right page:
\newcommand\gapwidth{\dimexpr\paperwidth-\evensidemargin+\oddsidemargin-\textwidth\relax}%

% Savebox for caption:
\newsavebox{\dpf@captionbox}%

% Left half of the image (originally overtaken from Martin Scharrer, all mistakes by me):
\newcommand\leftp@geflo@t[5][\@empty]{% #1 auxiliary caption, #2: b/t, #3: p/l, #4: content, #5: caption
    \if #2t\else%
    \if #2h\else%
        \exch@ngec@ptionskip% For bottom floats with above caption a skip below the caption is needed instead of above
    \fi%
    \fi%
    \if #2t%
        \vskip-\dimexpr1in+\voffset+\topmargin+\headheight+\headsep\relax% Move float directly to top of page
    \fi%
    \ifx\@empty#1%
        \global\savebox{\dpf@captionbox}{\parbox[b]{\textwidth}{\caption[#5]{#5}}}% This works, if #1 is empty
    \else%
        \global\savebox{\dpf@captionbox}{\parbox[b]{\textwidth}{\caption[#1]{#5}}}% This doesn't work, if #1 is empty, why?
    \fi%
    \if #2t\else%
    \if #2h\else%
        \ifleftcaption%
            \usebox{\dpf@captionbox}\\%
        \else%
            \ifsymmbound% Text on both pages symmetrical?
                \rule{0pt}{\ht\dpf@captionbox}\\% this delivers the same white space as the height of the caption
            \fi%
        \fi%
    \fi%
    \fi%
    \makebox[\textwidth][r]{%
        \if #3p\relax%
        \global\let\panowidth\paperwidth%
        \else%
        \global\let\panowidth\linewidth%
        \fi%
        \makebox[\textwidth][r]{%
            \adjustbox{trim=0 0 {.5\width} 0,clip}{#4}}% End \adjustbox
            \if #3p%
                \hskip-\dimexpr\paperwidth-\textwidth-1in-\hoffset-\evensidemargin\relax%
            \fi%
        }%
    \if #2b\else%
    \if #2l\else%
        \ifleftcaption%
            \\\usebox{\dpf@captionbox}%
        \else%
            \ifsymmbound% Text on both pages symmetrical?
                \\\rule{0pt}{\ht\dpf@captionbox}% this delivers the same white space as the height of the caption
            \fi%
        \fi%
    \fi%
    \fi%
    \if #2b%
        \vskip-\dimexpr\paperheight-\textheight-1in-\voffset-\topmargin-\headheight-\headsep\relax% Move float completely to page bottom
    \fi%
}% Ende \leftp@geflo@t

% Right half of the image  (originally overtaken from Martin Scharrer, all mistakes by me):
\newcommand*\rightp@geflo@t[5][\@empty]{% #1: auxiliary caption, #2: b/t, #3: p/l, #4: content, #5: caption
    \if #2t\else%
    \if #2h\else%
        \exch@ngec@ptionskip% For bottom floats with above caption a skip below the caption is needed instead of above
    \fi%
    \fi%
    \if #2t%
    \vskip-\dimexpr1in+\voffset+\topmargin+\headheight+\headsep\relax%
    \fi%
    \ifx\@empty#1%
        \global\savebox{\dpf@captionbox}{\parbox[b]{\textwidth}{\caption[#5]{#5}}}% This works, if #1 is empty
    \else%
        \global\savebox{\dpf@captionbox}{\parbox[b]{\textwidth}{\caption[#1]{#5}}}% This doesn't work, if #1 is empty, why?
    \fi%
    \if #2t\else%
    \if #2h\else%
        \ifleftcaption%
        \ifsymmbound% Text on both pages symmetrical?
            \rule{0pt}{\ht\dpf@captionbox}\\% this delivers the same white space as the height of the caption
        \fi%
        \else%
            \usebox{\dpf@captionbox}\\%
        \fi%
    \fi%
    \fi%
    \makebox[\textwidth][l]{%
        \if #3p%
        \global\let\panowidth\paperwidth%
        \hskip-\dimexpr1in+\hoffset+\oddsidemargin\relax%
        \else%
        \global\let\panowidth\linewidth%
        \fi%
        \adjustbox{trim={.5\width} 0 0 0,clip}{#4}% End \adjustbox
    }% end of \makebox
    \if #2b\else%
    \if #2l\else%
        \ifleftcaption%
        \ifsymmbound% Text on both pages symmetrical?
            \\\rule{0pt}{\ht\dpf@captionbox}% this delivers the same white space as the height of the caption
        \fi%
        \else%
            \\\usebox{\dpf@captionbox}%
        \fi%
    \fi%
    \fi%
    \if #2b%
    \vskip-\dimexpr\paperheight-\textheight-1in-\voffset-\topmargin-\headheight-\headsep\relax%
    \fi%
}% Ende \rightp@geflo@t



%----------------------------------------
% With this we can push a float forward to a certain page
%----------------------------------------
\newcount\invisiblefloat%
\invisiblefloat=0%
\newcount\safety%
\safety=0

\newcommand\dpf@position{}% Dummy for being able to call for \renewcommand

\def\pushfloattopage#1#2#3{% #1: page to reach, #2: float type (figure/table), #3: float placement
    \loop\ifnum\safety<20%
        \edef\pagelastinvisiblefloat{\zref@extractdefault{invisiblefloat\number\invisiblefloat}{abspage}{-1}}%
        \advance\invisiblefloat by 1\relax% increment label number for unique label
        \edef\actualpage{\zref@extractdefault{invisiblefloat\number\invisiblefloat}{abspage}{-1}}%

        % Invisible float without caption, needing no space, delivers information about actual page
        \if #3h 
            \renewcommand\dpf@position{t}
            \begin{@float}{#2}[t]% Empty float without \caption, so \counter{figure/table} is not increased
        \else%
        \if #3l 
            \renewcommand\dpf@position{b}
            \begin{@float}{#2}[b]% Empty float without \caption, so \counter{figure/table} is not increased
        \else%
            \renewcommand\dpf@position{#3}%
            \begin{@float}{#2}[#3]% Empty float without \caption, so \counter{figure/table} is not increased
        \fi%
        \fi%
            % If either following another invisible float or it is the landing page #1 (then the doublepage float follows), compensate \floatsep, either \textfloatsep
            \ifnum\actualpage = \pagelastinvisiblefloat\relax%
                \vskip-\floatsep%
            \else%
            \ifnum\actualpage=#1\relax%    
                \vskip-\floatsep%
            \else%
                \vskip-\textfloatsep%
            \fi%
            \fi%
            \zlabel{invisiblefloat\number\invisiblefloat}% test label: On which page are we?
        \end{@float}%

        % Error queries:
        \ifnum\actualpage = -1\relax% Label not found
            \PackageWarning{doublepagefloats}{Label of invisible float not found}%
            \let\iterate\relax% leave the loop
        \fi%
        \edef\lastpage{\zref@extractdefault{LastPage}{abspage}{-1}}
        \ifnum#1>\lastpage\relax% #1 > last page
            \PackageWarning{doublepagefloats}{Page number #1 behind last page \lastpage}%
            \let\iterate\relax% leave the loop
        \fi% if #1 > last page
        \ifnum#1 < 1\relax% Too small argument #1
            \PackageWarning{doublepagefloats}{Absolute page number less than 1 does not exist}%
            \let\iterate\relax% leave the loop
        \fi%
        
        % Normal end of loop after landing page is reached
        \ifnum\numexpr#1-1\relax < \actualpage%
            \let\iterate\relax% leave the loop
        \fi%
        \advance\safety by 1\relax%
    \repeat%
    \safety=0% for next call to pushfloattopage
}% End \pushfloattopage


%----------------------------------------
% Make a length non-elastic
%----------------------------------------
\newdimen\dpf@fixedlength% \newdimen delivers a non-elastic length
\newcommand\makefixedlength[1]{%
    \setlength\dpf@fixedlength{#1}% copying length to non-elastic one strips off the elastic part
    \global\setlength{#1}\dpf@fixedlength}% now copying back



%----------------------------------------
% \doublepagefloat{figure/table}{b/t/h/l}{p/l}{<content>{<caption>} is the new user command, to generate one or more double page floats
%----------------------------------------
\newcommand\dpf@pagebeforestart{-2}%

\newcounter{l@belnumber}% generates distinctive numbers for generating individual labels
\newcounter{dpf@l@belnumbershipout}% same for the shipout routine
\stepcounter{dpf@l@belnumbershipout}% start with 1

% For \label-\ref-mechanism to determine the right page number floats get an additional label dpf@float made unique by prolonging with the reading of a new counter "dpf@float"
\newcounter{dpf@float}% Counter for labeling every float (as the change of totalnumber will affect every float as well, independent of float type)
\let\end@floatold\end@float% Save original end of envíronment @float
\def\end@float{%
    \stepcounter{dpf@float}% So starting with one
    \zlabel{dpf@float\arabic{dpf@float}}%
    \end@floatold%
}%

% Save counter totalnumber
\AtBeginDocument{% Changes in the preamble will be taken into account as well, as we only save the counter at begin of document
\expandafter\edef\expandafter\totalnumber@old\expandafter{\the\value{totalnumber}}% Save state of counter totalnumber
}%

\newcommand*{\doublepagefloat}[6][\@empty]{% #1: auxiliary caption, #2: figure/table, #3: b/t/h/l, #4: p/l, #5: content, #6: caption 
%\newcommand*\doublepagefloat[5]{% #1: figure/table, #2: b/t/h/l, #3: p/l, #4: content, #5: caption, #6: auxiliary caption
    % #1: auxiliary caption, the one for the list of figures
    % #2: floattype, usually figure or table
    % #3: b: (b)ottom of page
    %     t: (t)op of page
    %     h: (h)igh, i.e. top of text
    %     l: (l)ow, i.e. bottom of text
    %
    % #4: p: (p)aper, i.e. the content may be up to 2\paperwidth wide, will be centered to the gap between both pages and may stretch till the paper boundaries.
    %        It may be narrower though and then will still center. If the width of the content is exactly \doubletextwidth, it stretches from the left border of the left page text to the right border of the right page
    %        text.
    %     l: (l)ine, i.e. the content only uses the width of a line on both pages with a wide gap between both parts
    % #5: content, i.e. the image itself
    % #6: main caption, the text under the image

    % Page number of last float before:
    \ifnum\value{dpf@float}=0\relax% This will become the first float?
        \newcommand\dpf@pagelastfloat{0}% fictitious page of last float
    \else%
        \expandafter\edef\expandafter\dpf@pagelastfloat\expandafter{\zref@extractdefault{dpf@float\arabic{dpf@float}}{abspage}{-1}}% must be expanded, before counter dpf@float is stepped again
    \fi%

    % Page, where \doublepagefloat was run (double page float is now available)
    \stepcounter{l@belnumber}% the next label should have another number (so counter starts with 1)
    \zlabel{dpf@run\arabic{l@belnumber}}% Unique label
    \expandafter\edef\expandafter\dpf@runpage\expandafter{\zref@extractdefault{dpf@run\arabic{l@belnumber}}{abspage}{-1}}% must be expanded, before counter l@belnumber is stepped again
    
    % The double page float can only appear on the first coming even page and after the last float before was printed and after \doublepagefloat was run. Calculated is the page BEFORE the first double float page
    \expandafter\edef\expandafter\dpf@pagebeforestart\expandafter{\dpf@pagelastfloat}% here the last float was printed
    \ifnum\dpf@pagebeforestart < \dpf@runpage\relax%
        \expandafter\renewcommand\expandafter\dpf@pagebeforestart\expandafter{\dpf@runpage}%
    \fi%
    \ifodd\dpf@pagebeforestart\relax% Then the double page float may already start at the next page
    \else% otherwise inkrement by 1 to reach an odd page number
        \expandafter\edef\expandafter\dpf@temp\expandafter{\dpf@pagebeforestart}%
        \expandafter\expandafter\expandafter\edef\expandafter\expandafter\expandafter\dpf@pagebeforestart\expandafter\expandafter\expandafter{\expandafter\numexpr\dpf@temp +1\relax}%
    \fi%

    % Store special pages globally with unique name for later use
    \expandafter\global\expandafter\edef\csname dpf@pagebeforestart\arabic{l@belnumber}\endcsname{\dpf@pagebeforestart}% Globally stored under unique name for comparison in next run
    \expandafter\global\expandafter\edef\csname dpf@pagelastfloat\arabic{l@belnumber}\endcsname{\dpf@pagelastfloat}% Globally stored under unique name for altering \floatsep 

    % Now push both halves of double page float to the appropriate pages and print them:
    \edef\dpf@lastpage{\zref@extractdefault{LastPage}{abspage}{-1}}%
    \expandafter\pushfloattopage\expandafter{\numexpr\dpf@pagebeforestart +1\relax}{#2}{#3}% 
    \if #3h%
        \begin{@float}{#2}[!t]% printing the left half of the image ...
    \else%
    \if #3l%
        \begin{@float}{#2}[!b]% printing the left half of the image ...
    \else%
        \begin{@float}{#2}[!#3]% printing the left half of the image ...
    \fi\fi%
        \leftp@geflo@t[#1]{#3}{#4}{#5\if#3h\else\if#3l\else\zlabel{left#3\arabic{l@belnumber}}\fi\fi}{#6}% Set label only in cases t/b, not in cases h/l
    \end{@float}%
    \expandafter\pushfloattopage\expandafter{\numexpr\dpf@pagebeforestart +2\relax}{#2}{#3}% 
    \if #3h%
        \begin{@float}{#2}[!t]%  ... and now the right half
    \else%
    \if #3l%
        \begin{@float}{#2}[!b]%  ... and now the right half
    \else%
        \begin{@float}{#2}[!#3]%  ... and now the right half
    \fi\fi%
        \rightp@geflo@t[#1]{#3}{#4}{#5\if#3h\else\if#3l\else\zlabel{right#3\arabic{l@belnumber}}\fi\fi}{#6}% Set label only in cases t/b, not in cases h/l
    \end{@float}%
}% End of \doublepagefloat

%-------------------------------
% Manipulate counters totalnumber and dpf@erase as well as lengths \floatsep and \textfloatsep via Hooks according to the calculations before 
% (after an idea of John Kormylo and with the help of Ulrike Fischer):
% totalnumber: Helps against other floats on the last double float page in a row (or of a single double page float) if set to 2 
%     -- and if the double page float is set to the top of the page, not the bottom!
% dpf@erase: controls erasing of page head or foot for placement parameters t and b
% lengths \floatsep and \textfloatsep: Are temporarily stripped off their elastic parts for better "invisibility" of "invisible floats" and 
%     better symmetric appearance of left and right page text in combination with a double page float -- are set back to their original 
%     elastic values later
%-------------------------------
\newlength\dpf@floatsepelastic%
\setlength\dpf@floatsepelastic{\floatsep}% Save floatsep
\newlength\dpf@textfloatsepelastic%
\setlength\dpf@textfloatsepelastic{\textfloatsep}% Save textfloatsep
\def\dpf@nextpage{-1}% Initializing: Next page (=0) doesn't exist

\AddToHook{shipout/after}{% With "after" we are sure to redo changes on the second page of the double page float before
    % let \textfloatsep unaltered for two pages in total, before setting back
    \ifnum\dpf@nextpage > 0% If following page shall have fixed \textfloatsep as well, \dpf@nextpage is positive 
        \xdef\dpf@nextpage{0}% Here set back to 0, because only one further page shall have fixed \textfloatsep
        \makefixedlength{\floatsep}% Strip off the elastic part of \floatsep
        \makefixedlength{\textfloatsep}% Strip off the elastic part of \textfloatsep
    \else%
        \setlength\floatsep\dpf@floatsepelastic% restore elastic length \floatsep
        \setlength\textfloatsep\dpf@textfloatsepelastic% restore elastic length \textfloatsep
    \fi%
    \ifnum\value{l@belnumber} > \numexpr\value{dpf@l@belnumbershipout} - 1\relax\relax% l@belnumber >= dpf@l@belnumbershipout ?
        \expandafter\expandafter\expandafter\ifnum\csname dpf@pagebeforestart\arabic{dpf@l@belnumbershipout}\endcsname = \value{page}% After shipout of the page before the double page float (for the first double page float page) ...
            \setcounter{totalnumber}{2}% ... set totalnumber=2 (1 invisible float, one half of the double page float, more are forbidden)
        \fi%
        % Make \textfloatsep unelastic, to make invisible floats invisible be compensating their own length (not exactly possible with elastic lengths)
        \expandafter\expandafter\expandafter\ifnum\csname dpf@pagelastfloat\arabic{dpf@l@belnumbershipout}\endcsname = \value{page}% Page of last float before double page float 
            \makefixedlength{\floatsep}% Strip off the elastic part of \floatsep
            \makefixedlength{\textfloatsep}% Strip off the elastic part of \textfloatsep
            \xdef\dpf@nextpage{1}%
        \fi%
        \ifnum\numexpr\value{page}+1\relax = \zref@extractdefault{leftt\arabic{dpf@l@belnumbershipout}}{page}{-1}% Left side with t- or h-double page float
            \makefixedlength{\floatsep}% Strip off the elastic part of \floatsep
            \makefixedlength{\textfloatsep}% textfloatsep now non-elastic, making calculations easier
            \xdef\dpf@nextpage{1}%
        \fi%
        \ifnum\numexpr\value{page}+1\relax = \zref@extractdefault{leftb\arabic{dpf@l@belnumbershipout}}{page}{-1}% Left side with l- or b-double page float
            \makefixedlength{\floatsep}% Strip off the elastic part of \floatsep
            \makefixedlength{\textfloatsep}% textfloatsep now non-elastic, making calculations easier
            \xdef\dpf@nextpage{1}%
        \fi%
    \fi%
}%
\AddToHook{shipout/before}{% With "before" we are sure that these changes on the second page of the double page float can be redone by a directly following second douböle page float
    % Set counter dpf@erase =0 on normal pages, =1 for pages with pagewide double page float in the head (leftt, rightt) and =2 for pages with pagewide double page float in the foot (leftb, rightb)
    \setcounter{dpf@erase}{0}% For normal pages
    \ifnum\value{l@belnumber} > \numexpr\value{dpf@l@belnumbershipout} - 1\relax\relax% If label exists already
        % Erase head or bottom of page in case of a double page float, that spans the complete page (\paperwidth)
        \ifnum\numexpr\value{page} + 1\relax = \zref@extractdefault{leftt\arabic{dpf@l@belnumbershipout}}{page}{-1}\setcounter{dpf@erase}{1}\fi%
        % If on left page of double page float (top): Erase head (dpf@erase=1)
        \ifnum\numexpr\value{page} + 1\relax = \zref@extractdefault{rightt\arabic{dpf@l@belnumbershipout}}{page}{-1}\setcounter{dpf@erase}{1}\fi%
        % If on right page of double page float (top): Erase head (dpf@erase=1)
        \ifnum\numexpr\value{page} + 1\relax = \zref@extractdefault{leftb\arabic{dpf@l@belnumbershipout}}{page}{-1}\setcounter{dpf@erase}{2}\fi%
        % If on left page of double page float (bottom): Erase bottom (dpf@erase=2)
        \ifnum\numexpr\value{page} + 1\relax = \zref@extractdefault{rightb\arabic{dpf@l@belnumbershipout}}{page}{-1}\setcounter{dpf@erase}{2}\fi%
        % If on right page of double page float (bottom): Erase bottom (dpf@erase=2)

        % Set totalnumber to original value
        \expandafter\expandafter\expandafter\ifnum\expandafter\numexpr\csname dpf@pagebeforestart\arabic{dpf@l@belnumbershipout}\endcsname + 2\relax = \value{page}% After shipout of the page before the double page float (for the first double page float page) ...
            \setcounter{totalnumber}{\totalnumber@old}% ... set totalnumber=2 (1 for invisible float, one half of the double page float)
        \fi%

        % Step labelcounter
        \expandafter\expandafter\expandafter\ifnum\expandafter\numexpr\csname dpf@pagebeforestart\arabic{dpf@l@belnumbershipout}\endcsname + 1\relax = \value{page}% After shipout of the page before the double page float (for the first double page float page) ...
            \stepcounter{dpf@l@belnumbershipout}% step label counter
        \fi%
    \fi% If label exists already        
}% \AddToHook{shipout/before}


%----------------------------------------
% Mechanism for erasing page head or foot based on idea by Ulrike Fischer (see https://tex.stackexchange.com/questions/689322/how-to-transport-code-not-material-with-a-float)
% The counter dpf@erase is set in \AddToHook{shipout/before} according to labels in the double page floats themselves, set in doublepagefloats
%----------------------------------------
\newcounter{dpf@erase}%

% Counter dpf@erase (controlled by shipout/before, see above) controls, whether page head (1), foot (2) or nothing (0) is erased. In the latter case the original macro is called
\AtBeginDocument{% That way one can change head and foot in the preamble
    % Save original head and foot of page
    \let\@evenheadold\@evenhead% Save even head
    \let\@oddheadold\@oddhead% Save odd head
    \let\@evenfootold\@evenfoot% Save even foot
    \let\@oddfootold\@oddfoot% Save odd foot

    % Dependand on counter dpf@erase don't show saved head or foot of page, reset dpf@erase immediately, so that the suppression lasts just for one page
    \def\@evenhead{\ifnum\value{dpf@erase} = 1\relax\else\@evenheadold\fi}% Take saved even head, if not page of labeled figure
    \def\@oddhead{\ifnum\value{dpf@erase} = 1\relax\else\@oddheadold\fi}% Take saved odd head, if not page of labeled figure
    \def\@evenfoot{\ifnum\value{dpf@erase} = 2\relax\else\@evenfootold\fi}% Take saved even foot, if not page of labeled figure
    \def\@oddfoot{\ifnum\value{dpf@erase} = 2\relax\else\@oddfootold\fi}% Take saved odd foot, if not page of labeled figure
}% AtBeginDocument



\endinput%

You must log in to answer this question.

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