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?

ThorstenL
  • 161
  • 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. – Ulrike Fischer Jun 19 '23 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 Jun 19 '23 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 Jun 19 '23 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 Jun 19 '23 at 16:00
  • no they aren't. But you are not forbidden to make a feature request. – Ulrike Fischer Jun 19 '23 at 16:06
  • You said Fig. 2 didn't work for you. I just tested to out comment the very first \lipsum. I was quite disappointed, wenn in the PDF EVERY panorama was broken. But when I compiled it for the second time, everything was ok again.

    How often did you compile?

    – ThorstenL Jun 19 '23 at 17:51
  • replace all image by example-image-duck and try yourself. – Ulrike Fischer Jun 19 '23 at 17:59
  • That correlates with warnings like "LaTeX Warning: Float too large for page by 111.89592pt on input line 92.", I get with your image. I don't get that with mine.

    If the image is too big, the simple mechanism with two {figure}[t] following each other may break?

    – ThorstenL Jun 19 '23 at 18:42
  • The problem is NOT the algorithm, the problem is, that the 4 pictures are following too quickly. With your image, the \suppressfloats of the following panorama is disturbing the one before.

    I have altered that in my MWE, now it should work with your image as well ...

    – ThorstenL Jun 19 '23 at 19:54
  • use only the first two, and add \lipsum\lipsum\lipsum\lipsum\lipsum\lipsum\lipsum\lipsum\lipsum\lipsum\lipsum\lipsum\lipsum\lipsum*[1-10] between them. There will be more then 12 pages between both and the second will still be wrong. – Ulrike Fischer Jun 19 '23 at 20:02
  • I understand the problem now, and I have no solution: If the code of the figure appears, but there is not left enough space on the page, the figure goes to the next page. If the next page is odd, I am lost.

    Is it possible to use \suppressfloats inside a float?

    – ThorstenL Jun 19 '23 at 21:08

3 Answers3

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.

ThorstenL
  • 161
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

user187802
  • 16,850
  • 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 Jun 29 '23 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 Jun 30 '23 at 06: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 Jun 30 '23 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 Jul 01 '23 at 05: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 Jul 02 '23 at 11:16
  • Placing (non-floating) double page floats with my \afterpage solution in combination with other floats worked and works quite well. Only recently I noticed, that footnotes in that area (and others where I used \afterpage and real floats) ceased to work properly. One footnote was extreme: It started at the bottom of a page, went on at the page before (!) and then ended above its own beginning. On Ulrike Fischers (as well much better than me) advice I removed the single \afterpage -- and the problem is gone. Only then I noticed problems with my homebrew double page float algorithm and footnotes. – ThorstenL Jul 02 '23 at 11:22
  • So my problem is NOT the placement of floats not working with the help of \afterpage. My problem is, that footnotes in the same area begin to behave unpredictably. That is, why I started to look for an algorithm without \afterpage ... – ThorstenL Jul 02 '23 at 11:26
  • Do you have the footnote defined inside the float or in the text? – user187802 Jul 02 '23 at 15:58
  • The footnotes that broke were defined in the text but near the \afterpage-command. Ulrike Fischer advised me, that the combination of floats, \afterpage, packet fewerfloatpages and footnotes was dangerous. I first dropped fewerfloatpages, as that was easy. Nothing altered. Then I replaced \afterpage. Mysteriously the footnote suddenly was ok again. Only then I became suspicious. And found not quite that obvious, but many problems. So I decided to try to get rid of \afterpage as far as possible. Perhaps an individual problem -- but at least Ulrike knew it ... – ThorstenL Jul 02 '23 at 23:14
  • can you show an example where it doesn't work? If possible with \hvFloat? – user187802 Jul 03 '23 at 06:00
  • The first problem I found, I tried to describe here: https://tex.stackexchange.com/questions/688815/footnotetext-jumps-to-next-page-and-back-again. That one was very bad -- the others, not quite as bad, I found only later.

    They happened with a homebrew algorithm with \afterpage and I have not yet come far enough, to include my new algorithm there, as I am still working on it. So I can not yet DEFINITELY say, that without \afterpage problems will be gone.

    After a short look into the source of hvfloat, finding \afterpage 82 times, I didn't bother to use it, so sorry, no example.

    – ThorstenL Jul 03 '23 at 16:23
  • By the way: I have meanwhile edited my answer a bit as well, now one has some more options than before and I managed to get rid of some "minor bugs". – ThorstenL Jul 03 '23 at 20:39
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&gt;\lastpage\relax% #1 &gt; last page
        \PackageWarning{doublepagefloats}{Page number #1 behind last page \lastpage}%
        \let\iterate\relax% leave the loop
    \fi% if #1 &gt; last page
    \ifnum#1 &lt; 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 &lt; \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 &lt; \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%

ThorstenL
  • 161