Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm not sure whether this is in principle possible, so let me try to explain; consider this 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

  % 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}%

\end{document}

The first image snippet is my regular pattern of use of {figure} (or {center}, for non-floating) and \includegraphics. Occasionally though, I have to make images fit on bottom of page, for which I use the tikz pattern, as per How to define a figure size so that it consumes the rest of a page? - and that is the second image snippet.

Now, I always get mega frustrated when I wait for a minute for a doc to comile, realize the pic is not where I want, "maybe \vspace{-1em} will help"?, compile, wait, "Nope... maybe \clearpage"? ... etc until I realize I have to use the tikz pattern - which now requires me to rearrange the code snippet :/.

What I like about my typical pattern, is that its contents are basically just these three commands - and their (only) arguments:

\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}

... and then, I can basically just exchange {figure} for {center} (and caption for \captionof) without changing these innards much.

So, what I'd ultimately want to do, is define a new environment, say {tikzbottomfigure}, so I can write the same pattern inside:

\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}

... - and this is the part I'm unsure of - I'd want the new environment code to automatically extract the first command \includegraphics... and its arguments (all up to second command) into #1; the second command \captionof... and its contents into #2; and the \label and its contents into #3 -- so that in the new environment definition code, I could simply write:

\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}%

Let's for the moment ignore the potential problems of \includegraphics not having the same arguments in both cases; my primary motive is to avoid defining a new environment with multiple arguments, which would force me to use braces to delimit arguments - and thus ultimately force me to rewrite image code snippets again, which is what I want to avoid in the first place.

The only way I can see this working, is if there is a mechanism that can parse/split and extract "commands and their arguments" from a chunk of text (and possibly assign them to individual #1 type arguments later); notably, some commands may span several lines of text, so this shouldn't be just an (ASCII) text line splitter. So, ultimately, my question is - does such a parsing mechanism exist in Latex, so that I could apply it to my intended usage as described?

share|improve this question
    
1  
My impression is that you want to define a command with a key-value argument: \mycomm{caption=<text>,shortcaption=<short>,label=<label>,image=<file>,imageopt‌​s=<options>} –  egreg Jun 19 at 19:56
    
Thanks for the comment, @egreg - actually, I want to avoid it; basically, I want to keep my usual ({figure}, {center}) usage pattern; and that kind of a \mycomm would require me to rewrite all images code to conform to that pattern. Basically, I'd keep my usual ({figure}, {center}) usage pattern as is during work; and if the time comes where bottom alignment is needed, I just change the environment name - instead of re-writing the entire snippet. My answer below shows a way, but probably not too robust. Cheers! –  sdaau Jun 19 at 20:01
1  
You can even have a key such as format=figure or format=filltobottom and others, which wouldn't require changing the environment's name, but just the value. Instead of an inflexible format like the one you want, a much more flexible approach. –  egreg Jun 19 at 20:04

1 Answer 1

Well, I think I got somewhere, so I'll post this (the MWE, including some comments and links, is below) - an implementation of a tikzbottomfigure as required.

The thing is, since the commands we want to extract are individual tokens -- we can use definition of arguments in a \def to split at tokens; so we get our "parsing \def" function (here called \splitfigurepattern). One problem here is that the split contents may still contain commands, which may want to execute within the parsing \def. So, any \defs we use inside the parsing \def should be (eTex) \protected -- but this then forces a bit of \expandafter gymnastics when we want to get back at the data we extracted.

A second problem in that in a typical \newenvironment, we cannot really capture the contents between the \begin{} and the \end{} of the environment - because that would typically introduce unbalanced braces. So we must use \NewEnviron from the environ package, which then provides the contents within an environment as \BODY, which we can use for the parser \def function.

Caveat emptor - note that if the contents within the environment, end up somehow not matching the input argument definition of the parsing \def, then Latex will crash with "Runaway argument"; so YMMV.

Here is the MWE code:

\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}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.