大约十五年前,我尝试使用 LaTeX 打印全景图,并找到了一个对我有用的版本,其中包含多次调用 \afterpage。与此同时,我发现了 Martin Scharrer 编写的更优雅、更简短、更易于理解的算法,其工作原理与此相同:如何在两页上添加图片,左侧部分在左侧,右侧部分在右侧(用于书籍)?,但我仍然使用我自己的版本(“永远不要改变正在运行的系统!”)。
几天前,Ulrike Fischer 看了我的代码,并抱怨我对 \afterpage 的使用,这会破坏我的脚注:“它不需要在浮动内,你也可以将它移动到图形后面,这里唯一重要的是它在处理脚注和浮动时执行”,我永远不应该使用 \afterpage(脚注文本跳转到下一页并返回)。
于是我替换了 Ulrike 特别提示的 \afterpage,原来的问题就消失了。但之后,我仔细查看了我的输出,嗯……Ulrike 是对的:问题更多,这些年来我才习惯了它们。
自从我编写了自己的算法后,其他人也这样做了,我搜索了一下,看看他们是否能够在没有 \afterpage 的情况下解决问题。但遗憾的是,我在 Martin Scharrers 算法以及 Herbert Voß 的 hvfloat 包中找到了 \afterpage——而且这两位作者似乎比我更了解 LaTeX。没有 \afterpage 就不可能实现我的目标吗?
因此我又尝试了一次,从 Martin Scharrers 的代码开始:
\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}
对我来说,最大的问题是 \afterpage 调用,如果在奇数页上调用 \twopagepicture,则需要使用该调用,因为这样全景图就会中断。但我有了一个想法,在这种情况下,不用 \afterpage 将两个图向前推一页,而是用 \suppressfloats。
现在我有两个问题:
如果我将“图像”替换为相当宽的图像路径,MWE 的代码现在就可以工作了。尽管如此,我还是有点担心,我是否又犯了一个严重的错误,因为我做的事情是我以前从未做过的。是否再次出现了任何缺陷?
剩下的一个问题是:只有当队列中的另一个浮点数不位于 \suppressfloats 和我的两个数字之间时,我的 \suppressfloats 机制才有效。我考虑过在 \checkoddpage 上方放置一个 \FloatBarrier,但这只能降低可能性,而不是万无一失。有人有更好的主意吗?
答案1
我的 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}
经过相当多的测试:对我来说,这至少对我到目前为止使用过的所有方法都有效。它适用于双页浮动和普通浮动(数字和表格)的混合,它也应该(虽然没有测试)适用于新定义的浮动。
这不是我一个人的工作,在过去的两周里,我在 StackExchange 上得到了大量的帮助,没有他们的帮助我不可能做到这一点。
从 Martin Scharrer 的算法开始(见问题),我特别需要两种将浮动推到特定页面的算法,这两种算法均在如何让图形准确出现在第16页?。
其中一种方法是在要推动的浮动元素之前发射相同类型的不可见浮动元素,从而将浮动元素向前推动,直到它到达正确的页面。
另一个方法是在输出之前或之后通过 Hooks 来工作,其中通过图中的标签来控制,计数器 totalnumber 被操作,它控制在一页上打印多少个浮点数:在最后一个其他浮点数之后,totalnumber 被设置为 0,在包含全景图的两页上设置为 1,在全景图之后回到其原始状态。
但在我看来,这两种算法都不是完美的:
隐形浮动算法擅长将浮动推到正确的位置。但可能发生这样的情况:未经请求的后续浮动已经出现在全景图的第二页上。
totalnumber 算法可以很好地避免全景图第二页上出现不想要的浮动。但由于 totalnumber 只能逐页操作,因此我的全景图的一半往往会落在最后一个浮动的页面上。我本可以通过提前将 totalnumber 设置为 1 来避免这种情况——但这样一来,在浮动之前的几页中,每页可能只有一个浮动,我也不喜欢这个想法。
我最终将两种算法结合起来。这变得容易一些,因为我无论如何都需要钩子:对于页脚或页首的全景图,我需要一种方法来擦除页首或页脚的正常部分...
如何使用?
您可以将其与 \doublepagefloat[#1]{#2}{#3}{#4}{#5}{#6} 一起使用,参数如下
- #1:辅助标题,用于图片列表
- #2:float类型,通常是数字或表格
- #3:b:(b)页面底部,t:(t)页面顶部 h:(h)高,即文本顶部,l:(l)低,即文本底部
- #4:p:(p)aper,即内容可能最多为
2\paperwidth
宽,将居中到两页之间的间隙,并可能延伸到纸张边界。但它可能会更窄,然后仍然居中。如果内容的宽度正好是2\textwidth+\gapwidth
,它会从左页文本的左边框延伸到右页文本的右边框。l:(l)line,即内容仅使用两页上的线的宽度,两部分之间有较宽的间隙 - #5:内容,即图像本身
- #6:主标题,图片下方的文字
前面已经提到了新的长度 \gapwidth。这是左页和右页上两个文本块之间的宽度。有两个选项可以调用包,它们可以改变整个文档的行为,都处理标题:
- [symmbound](如果调用)会在无标题页面上留出与标题高度相同的空白 - 因此文本在两个页面上的开始或结束高度相同。如果不调用(默认),标题不需要的空间也会用于文本。
- [leftcaption] 默认情况下,标题打印在右侧。如果您希望将其打印在左侧,请调用此选项。
已知问题
- 这仅适用于单列使用。我从未打算将其用于多列,我从未对其进行过测试。
- 标题只能跨越一个段落。我尝试过修改这一点,但没有成功。
- 有时它需要多次编译运行,首先会抱怨死循环。
我在哪里可以获取 doublepagefloats 包?
我会将其发布在另一个答案中,因为它对于这个答案来说太长了。
編輯
我已经编辑过这个答案两次,第一次我完全删除了,第二次我做了很多修改——两次都是因为在此期间我找到了一个更好的解决方案。
答案2
\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}
第 4--5 页:
第 8--9 页
第 12--13 页
第 16--17 页
答案3
我的第一个答案需要自制包 doublepagefloats —— 不幸的是,它太长了,不适合我的答案:
\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%