Using execute at begin node with \phantom and \pgfuseimage in TikZ?

(Just too long for a comment)

\phantom expects an argument, that must be given in explicit braces or as a single token: so

\phantom{A}

and

\def\x{A} \phantom\x

are equivalent, because the argument will be used to typeset a box where macro expansion is performed. And TeX is happy to do \hbox{A} and \hbox{\x}, with the same output if \x is defined as above.

The fact that \textit\bgroup word\egroup works can be explained with a (very) simplified version of \textit:

\def\textit#1{{\itshape #1}}

What happens with \textit\bgroup word\egroup? Here it is.

  1. The argument to \textit is \bgroup so the token list becomes

  2. {\itshape\bgroup} word\egroup and

  3. \bgroup and } cancel each other, while \egroup matches the first open brace.

(Note: the actual definition of \textit is much more complicated than this, but the description above is really what essentially happens.)

In some cases \bgroup and \egroup are equivalent to{and}`, but not in general and definitely not when grabbing of macro arguments is involved. With TeX primitives the question is quite more intricated: see this answer by Taco Hoekwater

For example \hbox\bgroup word\egroup is just the same as \hbox{word}. Instead, \lowercase\bgroup WORD\egroup is not equivalent to \lowercase{WORD}, while \lowercase\bgroup WORD} is. :-)


There's a lot of information buried in the comments so I'm going to try to extract my contributions into some form of answer. My recommended solution is to use pgfkeys. The key lengths can be short - single letter if really wanted - so the number of key strokes needed to use them is not really that much more than putting the picture name in the node text. Indeed, if you are going to use names that match some pattern (as in the example), there's no need to specify the picture name at all whereupon it isn't necessary to use any key in the actual node commands. Or you could patch into the unknown key handler so that an unknown key is taken to the the name of a picture. The pgfkeys method is the most robust, I think, and the most flexible. For example, it will work with matrix of nodes.

Second in my list of solutions would be Jake's solution of defining an entirely new macro. The only downside to this is that it doesn't work transparently with matrix of nodes (that is, you can always put the new macro into the cells but you can't take advantage of the automatically inserted nodes).

Way, way down at the bottom of my list is a hack that allows you to actually do what you originally asked: use the node text as the argument to a macro. This is a Very Bad Idea for lots of reasons. Firstly, it involves modifying the TikZ node processing commands directly rather than via hooks. Secondly, the opening bracket of the node text is actually removed before TikZ starts its node machinery (this is what TikZ looks for to know to start processing the text and the test is destructive) so we have to put it back again and this means More Hackery. It is not possible to insert stuff in the begin node/end node hooks for two reasons: Firstly, what appears between those two hooks is not just the node text. It is:

\bgroup%
  \aftergroup\unskip%
  \ifx\tikz@textcolor\pgfutil@empty%
  \else%
   \pgfutil@colorlet{.}{\tikz@textcolor}%
  \fi%
  \pgfsetcolor{.}%
  \setbox\tikz@figbox=\box\pgfutil@voidb@x%
  \tikz@uninstallcommands%
  \aftergroup\tikz@fig@collectresetcolor%
  \tikz@halign@check%
  \ignorespaces%

followed by the node text. There's even more junk after the node text and before the end hook is called. So if we want to get at the actual node text we need to add something after that \ignorespaces and it has to have a genuine opening brace.

Here's code illustrating all the above-mentioned solutions.

\documentclass{article}

\usepackage{tikz}

\pgfdeclareimage{firstpicture}{vignettes.pdf}
\pgfdeclareimage{secondpicture}{vignettes.pdf}
\pgfdeclareimage{thirdpicture}{vignettes.pdf}
\pgfdeclareimage{fourthpicture}{vignettes.pdf}

\makeatletter
\newif\if@pgfimagefound
\tikzset{
  dummy image with key/.style={
    every node/.append style={%
      execute at end
node=\phantom{\pgfuseimage{\pgfkeysvalueof{/tikz/pname}}}
    },
  },
  pname/.initial={},
  dummy image/.style={
    every node/.append style={%
      execute at end
node=\phantom{\pgfuseimage{\pgfkeysvalueof{/tikz/pname}}},
    /tikz/.unknown/.add code=%
    {%
      \@ifundefined{pgf@image@\pgfkeyscurrentname!}{\@pgfimagefoundfalse}{%
        \let\tikz@key=\pgfkeyscurrentname
        \tikzset{pname/.expand once=\tikz@key}%
        \@pgfimagefoundtrue
      }%
      \if@pgfimagefound
      \else
    }%
    {
      \fi
    }
    }
  }
}

\let\orig@tikz@do@fig=\tikz@do@fig
\tikzset{
  slurp node text/.code={
    \def\tikz@do@fig{\orig@tikz@do@fig\expandafter\slurp@node\expandafter{\iffalse}\fi}
  },
  slurp node/.style={
    every node/.append style={
      slurp node text
    },
    slurp node command/.code={#1}
  },
}
\def\slurp@node#1{%
\pgfkeys{/tikz/slurp node command={#1}}%
\egroup}

\newcommand\imgnode[2][]{%
  \node[#1] {\phantom{\pgfuseimage{#2}}};}

\makeatletter
\begin{document}
\tikzset{every node/.append style={draw}}
\begin{tikzpicture}
\matrix [dummy image with key]
{
  \node[pname=firstpicture] {}; & \node[pname=secondpicture] {}; \\
  \node[pname=thirdpicture] {}; & \node[pname=fourthpicture] {}; \\
};
\end{tikzpicture}

\begin{tikzpicture}
\matrix [dummy image]
{
  \node[firstpicture] {}; & \node[secondpicture] {}; \\
  \node[thirdpicture] {}; & \node[fourthpicture] {}; \\
};
\end{tikzpicture}

\begin{tikzpicture}
\matrix
{
  \imgnode{firstpicture} & \imgnode{secondpicture} \\
  \imgnode{thirdpicture} & \imgnode{fourthpicture} \\
};
\end{tikzpicture}

\begin{tikzpicture}
\matrix [slurp node={\phantom{\pgfuseimage{#1}}}] {
  \node {firstpicture}; & \node {secondpicture}; \\
  \node {thirdpicture}; & \node {fourthpicture}; \\
};
\end{tikzpicture}
\end{document}

Maybe you will like this possibity:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning,chains}
\begin{document}

\pgfdeclareimage{firstpicture}{pic1.pdf}
\pgfdeclareimage{secondpicture}{pic2.pdf}

\tikzset{
  phantom-content/.style={execute at begin node=\phantom{#1}},
  visible-content/.style={execute at begin node=#1},
  phantom-pgfimage/.style={phantom-content={\pgfuseimage{#1}}},
  visible-pgfimage/.style={visible-content={\pgfuseimage{#1}}},
  every node/.style={draw=red},
}

\begin{tikzpicture}
  \begin{scope}[start chain=going below]
    \node[phantom-content={\pgfuseimage{firstpicture}},on chain]{};
    \node[visible-content={\pgfuseimage{secondpicture}},on chain]{};
    \node[phantom-pgfimage={firstpicture},on chain]{};
    \node[visible-pgfimage={secondpicture},on chain]{};
  \end{scope}
\end{tikzpicture}

\foreach \vis in {phantom,visible}{
  \begin{tikzpicture}
    \tikzset{content/.style={\vis-content=##1}}
    \node[content={\pgfuseimage{firstpicture}}]{};
  \end{tikzpicture}
}

\foreach \vis in {phantom,visible}{
  \begin{tikzpicture}
    \tikzset{content/.style={\vis-pgfimage=##1}}
    \node[content={secondpicture}]{};
  \end{tikzpicture}
}
\end{document}