我想可靠地检测文档最后一页还剩多少空间。最好可以在\AtEndDocument
或类似的钩子中访问它,这样我就可以将此信息写入我自己的辅助文件。另一个选择是如果它自动写入标准文件.aux
;然后我可以在下次运行中从那里恢复信息,这不是什么大问题。更重要的是,它必须考虑最后一页的浮动和脚注,包括[b]
“一”。
用例
当以“TUGboat”风格整理期刊时,文章不需要从新页开始,需要知道前一篇文章留下了多少空间,这确实应该是自动化和可靠的。这将被纳入我工作的软件包中,该软件包允许编辑期刊。
例子
在下面的例子中,它\rule
作为一种测量工具,通过反复试验来检测最终的空间。
示例 1 – 没有数字
\documentclass[a4paper]{article}
\usepackage{lipsum,showframe}
\begin{document}
\lipsum
%\rule[-1ex]{10pt}{0.75\textheight}
\end{document}
% SHOULD GIVE "0.75\textheight"
示例 2 – 上图
\documentclass[a4paper]{article}
\usepackage{lipsum,showframe}
\begin{document}
\lipsum
\begin{figure}[t] \rule{3cm}{3cm} \caption{A black square} \end{figure}
%\rule[-1ex]{10pt}{0.54\textheight}
\end{document}
% SHOULD GIVE "0.54\textheight"
示例 3 – 上图和下图
\documentclass[a4paper]{article}
\usepackage{lipsum,showframe}
\begin{document}
\lipsum
\begin{figure}[t] \rule{2cm}{2cm} \caption{A small black square} \end{figure}
\begin{figure}[b] \rule{3cm}{3cm} \caption{A black square} \end{figure}
%\rule[-1ex]{10pt}{0.37\textheight}
\end{document}
% SHOULD GIVE "flag: figure/footnote at the bottom of the last page" and "0.37\textheight" OR "0\textheight"
示例 4 – 图表在顶部,脚注在底部
\documentclass[a4paper]{article}
\usepackage{lipsum,showframe}
\begin{document}
\lipsum
Random text\footnote{A random footnote.}.
\begin{figure}[t] \rule{3cm}{3cm} \caption{A small black square} \end{figure}
%\rule[-1ex]{10pt}{0.50\textheight}
\end{document}
% SHOULD GIVE "flag: figure/footnote at the bottom of the last page" and "0.50\textheight" OR "0\textheight"
答案1
这将使用\tikzmark
和\vfill
来计算最后一页(或任何使用的页面)的剩余空间\pagespace
。需要运行两次来计算长度,再运行一次才能将值返回到\begin{document}
。
可以使用\pdflastypos
而不是 tikz 来实现这一点。您甚至可以通过\lastpagegap
在读取辅助文件时而不是在结束时进行计算将其减少到 2 次运行。
\documentclass[a4paper]{article}
\usepackage{lipsum,showframe}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\newlength{\lastpagegap}% reserve global name
\makeatletter
\newcommand{\pagespace}{%
\hrule height0pt %terminate last paragraph, it needed
\strut\tikzmark{lastpage}
\vfill
\noindent\begin{tikzpicture}[remember picture,overlay]
\coordinate (lastpage) at (pic cs:lastpage);
\pgfextracty{\lastpagegap}{\pgfpointanchor{lastpage}{center}}
\global\advance\lastpagegap by \ht\strutbox
%\node[above right]{\the\lastpagegap};
\end{tikzpicture}%
\write\@auxout{\string\global\string\lastpagegap=\the\lastpagegap}% store in aux file
}
\makeatother
\begin{document}
\the\lastpagegap
\lipsum
Random text\footnote{A random footnote.}.
\begin{figure}[t] \rule{3cm}{3cm} \caption{A small black square} \end{figure}
\pagespace\smash{\rule{10pt}{\lastpagegap}}
\end{document}
答案2
这是一个使用\pagegoal
和 的解决方案\pagetotal
。宏\getremainingheight
将命令写入辅助文件,该文件将剩余高度写入另一个辅助文件(这里\jobname.xyz
,我标记了每个以源结尾的文件,因为找到它们有点困难)。文件中的高度最终确定后,文件中的值即有效,因此在大多数情况下,在第一次运行后有效。
无需对浮点数和/或脚注做任何特殊处理,因为 TeX/LaTeX 已经做到了这一点。而且由于 的钩子\AtEndDocument
几乎在 的开头执行\end{document}
,因此可以将宏放入 中\AtEndDocument
。
如果末尾有一个浮动页面,则宏不会识别它。它将报告最后一个非浮动页面的剩余高度。
\newpage
如果由于某种原因,末尾有一个或类似的内容(可能隐藏在某些宏中),则会报告剩余高度为 0pt(您可以轻松更改此高度)。这无法避免,因为新页面已在\getremainingheight
调用时启动。但我实现了一个标志\ifendonnewpage
,其状态也写入辅助文件。
我还自由地实现了一个附加功能:您可以设置一个\minimumheight
。如果剩余高度小于该高度,则报告高度 0pt。
\documentclass[a4paper]{article}
\usepackage{showframe}
\usepackage{lipsum}
\makeatletter
% write information about free space to \jobname.xyz
\AtEndDocument{\if@filesw\newwrite\tf@xyz
% ^^^
\immediate\openout\tf@xyz\jobname.xyz\fi
% ^^^ ^^^
}
\newdimen\remainingheight
\newdimen\minimumheight
\newif\ifendonnewpage
\endonnewpagefalse
\newcommand*{\calcremaining}{%
\par
% in case a new page just started report a remaining height of 0pt
\ifdim\pagegoal=\maxdimen
\remainingheight\z@
\endonnewpagetrue
\else
\remainingheight\pagegoal
\advance\remainingheight by -\pagetotal
\advance\remainingheight by -\lineskip
\endonnewpagefalse
\fi
}
\newcommand*{\getremainingheight}{%
\calcremaining
% if not enough space, report 0pt remaining space
\ifdim\remainingheight<\minimumheight
\remainingheight\z@
\else
% important, otherwise the remaining height reported would be slightly too large
\noindent
\calcremaining
\fi
% write to own aux file via main aux
\immediate\write\@auxout{\string\@writefile{xyz}{\string\remainingheight\the\remainingheight}}%
% ^^^
\immediate\write\@auxout{\string\@writefile{xyz}{\ifendonnewpage\string\endonnewpagetrue\else\string\endonnewpagefalse\fi}}%
% ^^^
}
% just load the file to show the values in this document
% this will of course need two runs
\AtBeginDocument{\InputIfFileExists{\jobname.xyz}{}{}}
% ^^^
\AtEndDocument{\getremainingheight
% just for testing, will of course produce a third page, if the
% remaining height is less then \baselineskip
% \ifdim\remainingheight>0pt\rule{10pt}{\remainingheight}\fi
}
\makeatother
% set minimum space to be reported, less then that will be reported as 0pt
\setlength{\minimumheight}{\baselineskip}
\begin{document}
\lipsum
Remaining height: \the\remainingheight; ended on new page: \ifendonnewpage yes\else no\fi
Random text\footnote{A random footnote.}.
% see what happens if page is full
%\lipsum[4]
%\lipsum[4]
%One more line to fill the page.
\begin{figure}[t] \rule{2cm}{2cm} \caption{A small black square} \end{figure}
\begin{figure}[b] \rule{3cm}{3cm} \caption{A black square} \end{figure}
% this will produce a float page, which is not recognized at all
%\begin{figure}[p] \rule{4cm}{4cm} \caption{A big black square} \end{figure}
% see what happens, if there is a newpage at the end
%\newpage
\end{document}