Win11; TeXLive2025; VSCode.
如下以图目录(\listoffigures)为例,表目录(\listoftables)同理。
在实际工程中需要获取图目录(listoffigures)所在的最后一页的页码值(e.g. 最后一个条目在第n页,则所获取的页码值为n),然后将其用于其他命令中。但对于图目录的最后若干项被断到下一页中的情形,基于如下语句:
\listoffigures
\thepage %获取当前页码值的位置,这里临时换成\thepage来展示获取结果会出现“最后一个条目在第n页,但所获取的页码值却为n-1”,例如文末MWE的运行结果为:
问了下AI,得到的回答大致意思是:计数器的取值命令(\the<counter>, \value{<counter>}, etc)比 \listoffigures, \listoftables 的 ship out 行为先一步展开。于是,图/表目录的盒子在计数器机制下仍属于第n-1页。
目前只想到了一种解决方案:在对计数器取值之前添加空盒子,使取值行为的时机被挪到了空盒子之后,从而被挪到了第n页当中。这也相当于:\listoffigures盒子的ship out行为被提前结束了。例如:
\listoffigures
\mbox{}
\thepage但不足在于:无论添加哪种类型的盒子,都会产生一定额外空白。例如上述修改的结果为:
这可能会导致:原本不会换页的条目因为这一空白触发了断页的罚函数机制而被断到了下一页。
因此问题为:如何在不产生额外内容的前提下让\listoffigures盒子的ship out行为被提前结束呢?
希望尽可能不用到额外宏包。当然,对于不得不用宏包的情形,也欢迎发表。
\documentclass{article}
\usepackage{graphicx}
\usepackage{lipsum}
\usepackage{showframe}
\begin{document}
% ----- 这部分是为了模拟 图目录之前还有其他内容填充 的情形 ----- %
\lipsum[1-4]
This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text.
% =================================================== %
\listoffigures
\thepage
\begin{figure}[ht]
\centering
\includegraphics[width=.48\linewidth]{example-image-a}
\caption{This is text}
\end{figure}
\begin{figure}[ht]
\centering
\includegraphics[width=.48\linewidth]{example-image-a}
\caption{This is text}
\end{figure}
\end{document}
如果要求精确获取最终排版后目录最后一个条目所在的页码,可以通过三轮编译,笨是笨了点,但是能达到目的。
lof文件,同时计算目录所有条目的数量,写入aux文件\listoffigures命令加载lof文件中的\contentsline命令,对目录的每一项进行排版,当处理最后一个条目时,向aux文件延时写入条目所在的页码,这样写入的页码会是当前条目所在页需要被shipout时的准确页码aux为此轮编译提供准确的页码如果图片数量不多,只修改\l@figure,每处理一个条目就覆盖一次页码,也是可以的。
\documentclass{article}
\usepackage{graphicx}
\usepackage{lipsum}
\usepackage{showframe}
\usepackage{pgffor}
\newcommand{\figlistlastpage}{0}
\makeatletter
\newcounter{totalfigurecount}
\setcounter{totalfigurecount}{0}
\newcounter{curfigurecount}
\setcounter{curfigurecount}{0}
%第一轮计算条目总数
\let\oldaddcontentsline\addcontentsline
\renewcommand{\addcontentsline}[3]{%
\oldaddcontentsline{#1}{#2}{#3}%
\ifnum\pdfstrcmp{#1}{lof}=0
\stepcounter{totalfigurecount}
\fi
}
%第一轮写入条目总数
\AtEndDocument{
\if@filesw
\immediate\write\@auxout{\string\gdef\string\finalfigcount{\thetotalfigurecount}}%
\fi
}
%第二轮延迟写入最后一个条目的排版页码
\let\oldcontentsline\contentsline
\renewcommand{\contentsline}[4]{%
\oldcontentsline{#1}{#2}{#3}{#4}%
\ifnum\pdfstrcmp{#1}{figure}=0
\stepcounter{curfigurecount}
\ifnum\value{curfigurecount}=\finalfigcount\relax
\if@filesw
\protected@write\@auxout{}{
\string\gdef\string\figlistlastpage{\thepage}%
}
\fi
\fi
\fi
}
%\let\old@l@figure\l@figure
%\renewcommand{\l@figure}[2]{%
% \old@l@figure{#1}{#2}%
% % 每处理一个条目就会覆盖写入一次,最后留下的就是最后一页的页码
% \protected@write\@auxout{}{%
% \string\gdef\string\figlistlastpage{\thepage}%
% }
%}
\makeatother
\begin{document}
% ----- 这部分是为了模拟 图目录之前还有其他内容填充 的情形 ----- %
\lipsum[1-4]
This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text. This is Text.
% =================================================== %
\listoffigures
\figlistlastpage
\foreach \n in {1, 2, ..., 24} {
\begin{figure}[ht]
\centering
\includegraphics[width=.48\linewidth]{example-image-a}
\caption{This is text}
\end{figure}
\begin{figure}[ht]
\centering
\includegraphics[width=.48\linewidth]{example-image-a}
\caption{This is text}
\end{figure}
\clearpage
}
%
%\begin{figure}[ht]
%\centering
%\includegraphics[width=.48\linewidth]{example-image-a}
%\caption{This is text}
%\end{figure}
\end{document}
感谢雾月老师解惑 ~ 有个疑惑:
\goodbreak展开后是带\par的,那么\par算是 typsetting material 吗(我理解的是:typsetting material 相当于能在PDF中直接生成内容的东西)?@u64726 文字、盒子、rule、glue 等这些才算是 typesetting material,
\par一般是不算的,如果不重定义\par或用段落钩子整花活的话。把
\thepage写入辅助文件的老办法总是可行的。@u10307 明白了,再次感谢~