我不确定这在原则上是否可行,所以让我尝试解释一下;考虑这个 MWE:
\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{tikzpagenodes} % current page text area
\usepackage{caption}
\pagecolor{yellow!15}
% convert rose: -resize 400x200! /tmp/test.png # ImageMagick
\begin{document}
\begin{center} % {figure}[h!]
\centering % %(for figure)
\includegraphics[width=1.0\textwidth]{/tmp/test.png}
\captionof{figure}[shortdesc]{ % \caption[shortdesc]{
caption lorem ipsum dolor sit amet, text line 01
caption consectetur adipisicing elit text line 02
caption text line 03
}
\label{fig:test1}
\end{center} % {figure}
% \end
% https://tex.stackexchange.com/questions/14512/how-to-define-a-figure-size-so-that-it-consumes-the-rest-of-a-page/14514#14514
% needs texing twice:
\begin{tikzpicture}[overlay,remember picture]
% Caption
\node [anchor=south west,outer sep=0pt,inner sep=0pt,text width=\textwidth] (caption) at (current page text area.south west) {%
\captionof{figure}[shortdesc]{ %
caption lorem ipsum dolor sit amet, text line 01
caption consectetur adipisicing elit text line 02
caption text line 03
}%
\label{fig:test2} % has to stand after the caption, to get its number
};
% Image
\path let \p0 = (0,0), \p1 = (caption.north) in
node [inner sep=0pt,outer sep=0pt,anchor=south] at (\x1,\y1) {%
\pgfmathsetmacro\imgheight{\y0-\y1-\abovecaptionskip}%
\includegraphics[height=\imgheight pt,width=\textwidth,keepaspectratio]{/tmp/test.png}%
};
\end{tikzpicture}%
\end{document}
第一个图像片段是我常用的模式{figure}
(或{center}
,表示非浮动)和\includegraphics
。不过,偶尔我必须让图像适合页面底部,为此我会使用模式tikz
,按照如何定义图形大小以使其占据页面的剩余部分?- 这是第二幅图像片段。
现在,当我等待文档编译一分钟,意识到图片不在我想要的位置时,我总是非常沮丧,“也许 \vspace{-1em} 会有帮助”?,编译,等待,“不...也许 \clearpage”?......等等,直到我意识到我必须使用 tikz 模式 - 这现在需要我重新排列代码片段:/
。
我喜欢我的典型模式,因为它的内容基本上只是这三个命令 - 以及它们的(唯一)参数:
\includegraphics[width=1.0\textwidth]{/tmp/test.png}
\captionof{figure}[shortdesc]{ % \caption[shortdesc]{
caption lorem ipsum dolor sit amet, text line 01
caption consectetur adipisicing elit text line 02
caption text line 03
}
\label{fig:test1}
...然后,我基本上可以只交换{figure}
({center}
和),而不用caption
对\captionof
这些内部结构进行太多改变。
因此,我最终想要做的是定义一个新的环境,比如说{tikzbottomfigure}
,这样我就可以写入相同的模式:
\begin{tikzbottomfigure}
\includegraphics[width=1.0\textwidth]{/tmp/test.png}
\captionof{figure}[shortdesc]{ % \caption[shortdesc]{
caption lorem ipsum dolor sit amet, text line 01
caption consectetur adipisicing elit text line 02
caption text line 03
}
\label{fig:test1}
\end{tikzbottomfigure}
... - 这是我不确定的部分 - 我希望新的环境代码自动将第一个命令\includegraphics...
及其参数(所有直到第二个命令)提取到#1
;将第二个命令\captionof...
及其内容提取到#2
;并将\label
及其内容提取到#3
- 以便在新的环境定义代码中,我可以简单地写道:
\begin{tikzpicture}[overlay,remember picture]
% Caption
\node [anchor=south west,outer sep=0pt,inner sep=0pt,text width=\textwidth] (caption) at (current page text area.south west) {%
#2%
#3% has to stand after the caption, to get its number
};
% Image
\path let \p0 = (0,0), \p1 = (caption.north) in
node [inner sep=0pt,outer sep=0pt,anchor=south] at (\x1,\y1) {%
\pgfmathsetmacro\imgheight{\y0-\y1-\abovecaptionskip}%
#1%
};
\end{tikzpicture}%
暂时让我们忽略\includegraphics
两种情况下没有相同参数的潜在问题;我的主要动机是避免定义具有多个参数的新环境,这将迫使我使用括号来分隔参数 - 并最终迫使我再次重写图像代码片段,而这正是我首先想要避免的。
我认为唯一可行的方法是,是否存在一种机制,可以从一段文本中解析/拆分并提取“命令及其参数”(并可能#1
稍后将它们分配给各个类型参数);值得注意的是,某些命令可能跨越多行文本,因此这不应该只是一个 (ASCII) 文本行拆分器。所以,最终,我的问题是 - Latex 中是否存在这样的解析机制,以便我可以将其应用于我所描述的预期用途?
答案1
tikzbottomfigure
好吧,我想我已经找到了一些线索,所以我将发布这个(MWE,包括一些评论和链接,如下) -按要求实现的。
问题是,由于我们要提取的命令是单独的标记——我们可以使用 a 中的参数定义在\def
标记处进行拆分;所以我们得到了我们的“解析\def
”函数(这里称为\splitfigurepattern
)。这里的一个问题是,拆分的内容可能仍包含命令,这些命令可能想要在解析中执行\def
。因此,我们在解析中使用的任何 \defs 都\def
应该是 (eTex) \protected
——但当我们想要返回我们提取的数据时,这会迫使我们做一些\expandafter
体力活。
第二个问题是,在典型的 中,我们无法真正捕获环境的和 之间\newenvironment
的内容- 因为这通常会引入不平衡的括号。因此,我们必须使用包中的,然后包会将环境中的内容提供为,我们可以将其用于解析器函数。\begin{}
\end{}
\NewEnviron
environ
\BODY
\def
买者自慎 - 请注意,如果环境中的内容最终以某种方式不是匹配解析的输入参数定义\def
,那么 Latex 将因“失控参数”而崩溃;所以 YMMV。
以下是 MWE 代码:
\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{tikzpagenodes} % current page text area
\usepackage{caption}
\usepackage{environ} % \BODY
% \usepackage{trace}
\pagecolor{yellow!15}
% convert rose: -resize 400x200! /tmp/test.png
% (c0)
% (c1)
% this one splits entire figure pattern, containing:
% \includegraphics[...]...\captionof...\label...
% (no need for external split call, as in (c1))
% still using protected, since arbitrary commands can appear wherever inside..
%\def\splitfigurepattern\includegraphics[#1]#2\captionof#3\label#4{%
% include #1 before \incl.graphics (to handle if a \centering there):
\def\splitfigurepattern#1\includegraphics[#2]#3\captionof#4\label#5{%
\protected\def\sfpA{#2} % 'width=1.0\textwidth '
\protected\def\sfpB{#3} % '{/tmp/test.png}'
\protected\def\sfpC{#4} % '{figure}[shortdesc]{ caption lorem...03 }'
\protected\def\sfpD{#5} % 'fig:test1'
\protected\def\sfpO{#1} % '' if empty before \inclgr.; else '\centering'
\typeout{sfp A: \meaning\sfpA^^J B: \meaning\sfpB^^J C: \meaning\sfpC^^J D: \meaning\sfpD^^J O: \meaning\sfpO} %
}
\def\runsplitfp#1{\splitfigurepattern#1\relax}
% (c2)
\NewEnviron{tikzbottomfigure}{%
% call parser to split the argument
% \expandafter\runsplitfp\BODY% ! Use of \splitfigurepattern doesn't match its definition.
\expandafter\expandafter\runsplitfp{\BODY}% passes!
%
% here we should have parsed elements - proceed to output tikz code:
% http://tex.stackexchange.com/questions/14512/how-to-define-/14514#14514
% needs texing twice:
\begin{tikzpicture}[overlay,remember picture]
% Caption
% unless expanded properly, \label{\tmpD} will
% fail with: "! Undefined control sequence. \sfpD"
%\edef\tmpD{\sfpD} % tmpD: \sfpD
\expandafter\edef\expandafter\tmpD\expandafter{\sfpD} % tmpD: fig:test2
\typeout{tmpD: \tmpD}
\node [anchor=south west,outer sep=0pt,inner sep=0pt,text width=\textwidth] (caption) at (current page text area.south west) {%
\expandafter\captionof\sfpC
\label{\tmpD} %
};
% Image
\expandafter\edef\expandafter\tmpB\expandafter{\sfpB} % better: File `{/tmp/test.png} ' not found.
\expandafter\edef\expandafter\tmpBB\tmpB \typeout{BB \tmpBB}% ok: BB /tmp/test.png
\path let \p0 = (0,0), \p1 = (caption.north) in
node [inner sep=0pt,outer sep=0pt,anchor=south] at (\x1,\y1) {%
\pgfmathsetmacro\imgheight{\y0-\y1-\abovecaptionskip}%
% (c3)
\expandafter\includegraphics\expandafter[\sfpA,height=\imgheight pt,
keepaspectratio,]{\tmpBB}%
};
\end{tikzpicture}%
} % \NewEnviron{tikzbottomfigure}
\begin{document}
\begin{center} % {figure}[h!]
\centering % %(for figure)
\includegraphics[width=1.0\textwidth]{/tmp/test.png}
\captionof{figure}[shortdesc]{ % \caption[shortdesc]{
caption lorem ipsum dolor sit amet, text line 01
caption consectetur adipisicing elit text line 02
caption text line 03
}
\label{fig:test1}
\end{center} % {figure}
% (c4)
text here ... \par
... to test figure scale on bottom\par
... to test figure bottom scaling\par
... to test figure scale - is ok.\par
% \runsplitfp{%
\begin{tikzbottomfigure}
\centering % algo passes with or without this (prefix before \includegraphics)
\includegraphics[width=1.0\textwidth]{/tmp/test.png}
\captionof{figure}[shortdesc]{ % \caption[shortdesc]{
caption lorem ipsum dolor sit amet, text line 01
caption consectetur adipisicing elit text line 02
caption text line 03
}
\label{fig:test2}
\end{tikzbottomfigure}
% } % \runsplitfp
% (c5)
\end{document}
% (c0)
% http://tex.stackexchange.com/questions/4736/what-is-the-difference-between-fragile-and-robust-commands
% using e-TeX's \protected system to prevent crashing at typeouts here!
% (just \string{#1} doesn't work)
% http://tex.stackexchange.com/questions/49056/optional-arguments-in-def
% http://tex.stackexchange.com/questions/57229/on-unprotecting-expanding-protected-macros-or-the-space-after-command-name
% http://tex.stackexchange.com/questions/14390/how-can-one-pass-the-contents-of-a-latex-environment-to-a-macro
\def\splitatcaptionof#1\captionof#2\relax{ %
\protected\def\splcofA{#1} %
\protected\def\splcofB{#2} %
\typeout{A: \splcofA^^JB: \splcofB} % A: \splcofA B: \splcofB
}
\def\testsplcof#1{\splitatcaptionof#1\relax}
% nope; croaks on [],{}
\def\splitfigurepatternOld\includegraphics\[#1\]\{#2\}\captionof#3\label#4{%
\protected\def\sfpA{#1} %
\protected\def\sfpB{#2} %
\protected\def\sfpC{#3} %
\protected\def\sfpD{#4} %
\typeout{A: \meaning\sfpA^^J B: \meaning\sfpB^^J C: \meaning\sfpC^^J D:
\meaning\sfpD^^J }
}
% (c1)
% if the split character doesn't occur in input - runaway argument!
% if it does, the final #3 will contain a single character,
% unless we put in a "break" token; here just chose arbitrarily
% a previously undefined token `\e` ...
% this splits: ...[width=1.0\textwidth ]{/tmp/test.png}
\def\splitoneoptstr#1[#2]#3\e{%
\def\soosA{#1} %
\def\soosB{#2} %
\def\soosC{#3} %
\typeout{srp A: \meaning\soosA^^J B: \meaning\soosB^^J C: \meaning\soosC} %
}
% ... then, the call also must have the break token `\e` before the \relax:
\def\runsplitoos#1{\splitoneoptstr#1\e\relax}
% this one splits entire figure pattern, containing:
% \includegraphics...\captionof...\label...
% and uses \runsplitoos for the includegraphics opts
\def\splitfigurepattern\includegraphics#1\captionof#2\label#3{%
\protected\def\sfpA{#1} %
\protected\def\sfpB{#2} %
\protected\def\sfpC{#3} %
\typeout{sfp A: \meaning\sfpA^^J B: \meaning\sfpB^^J C: \meaning\sfpC } %
% \expandafter\runsplitoos\sfpA % Runaway argument?
\edef\tcp{\meaning\sfpA} \typeout{tcp \tcp} %
% \expandafter\runsplitoos{\tcp} % Runaway argument?
% \expandafter\runsplitoos\tcp % passes;
\expandafter\expandafter\runsplitoos{\tcp} % passes;
}
% (c2)
\newenvironment{tikzbottomfigureNOPE}
{ % start \begin env.
% start calling \runsplitfp{%
\def\contents\begingroup % so we open a brace?
} % stop \begin env.
{ % start \end env.
\endgroup % \endgroup % close brace? cannot
} % stop end env.
% (c3)
% note, the \expandafter\edef must be outside of {node .. includegraphics},
% else spurious space is introduced!
%\traceon %
%\includegraphics[height=\imgheight pt,width=\textwidth,keepaspectratio]{/tmp/test.png}%
%\includegraphics[height=\imgheight pt,\protect\sfpA,keepaspectratio]{\sfpB}%
% sfpA needs to be expanded here first? not really, it contains
% \textwidth; it just needs to be expanded before \includegraphics;
% same for "File `\sfpB ' not found."
%\edef\tmpB{\sfpB} % \tmpB ->\sfpB: ! LaTeX Error: File `\sfpB ' not found.
\expandafter\edef\expandafter\tmpB\expandafter{\sfpB} % better: File `{/tmp/test.png} ' not found.
% now one more edef to get rid of the braces:
% \edef\tmpBB\tmpB - undef; \edef\tmpBB{\tmpB} - same as before; has braces
\expandafter\edef\expandafter\tmpBB\tmpB \typeout{BB \tmpBB}% ok: BB /tmp/test.png
% finally the includegraphics - have to expand \sfpA
% inline here (as it may contain \textwidth etc):
\expandafter\includegraphics\expandafter[\sfpA,height=\imgheight pt,
keepaspectratio,]{\tmpBB}%
% (c4)
% % http://tex.stackexchange.com/questions/14512/how-to-define-a-figure-size-so-that-it-consumes-the-rest-of-a-page/14514#14514
% % needs texing twice:
% \begin{tikzpicture}[overlay,remember picture]
% % Caption
% \node [anchor=south west,outer sep=0pt,inner sep=0pt,text width=\textwidth] (caption) at (current page text area.south west) {%
% \captionof{figure}[shortdesc]{ %
% caption lorem ipsum dolor sit amet, text line 01
% caption consectetur adipisicing elit text line 02
% caption text line 03
% }%
% \label{fig:test2} % has to stand after the caption, to get its number
% };
% % Image
% \path let \p0 = (0,0), \p1 = (caption.north) in
% node [inner sep=0pt,outer sep=0pt,anchor=south] at (\x1,\y1) {%
% \pgfmathsetmacro\imgheight{\y0-\y1-\abovecaptionskip}%
% \includegraphics[height=\imgheight pt,width=\textwidth,keepaspectratio]{/tmp/test.png}%
% };
% \end{tikzpicture}%
% (c5)
% \edef\tcp{\meaning\sfpA} \typeout{tcp \tcp}
% \typeout{A: \meaning\splcofA^^JB: \meaning\splcofB}
% A: \protected macro:->\includegraphics [width=1.0\textwidth ]{/tmp/test.png}
% B: \protected macro:->{figure}[shortdesc]{ caption lorem ipsum dolor sit amet,
% text line 01 caption consectetur adipisicing elit text line 02 caption text lin
% e 03 } \label {fig:test1}