I'm writing my thesis/dissertation and since its an on-going work I don't always have the actual images ready for the figures I put into my document, but for various reasons want to automatically have it substitute a dummy figure in place when the included graphics file doesn't exist. E.g. I can do something like \includegraphics[width=8cm]{\chapdir/figures/fluxcapacitor}
(where \chapdir
is a macro for my 'current' chapter directory, e.g. \def\chapdir{./ch_timetravel}
and if there's no ./ch_timetravel/figures/fluxcapacitor.jpg
it'll insert ./commands/dummy.jpg
instead.
I've structured my macros (perhaps naïvely?) so that I have a macro (\figFileOrDummy
) that determines the appropriate file to include by checking if the argument provided to it exists, so that I can call \includegraphics[properties]{\figFileOrDummy{\chapdir/figures/fluxcapacitor}}
. Except I'm getting various errors depending on how I try to call this, which seem to suggest that I'm approaching the problem in a fundamentally flawed way as far as 'good LaTeX programming' goes.
Here's the macro to check if the file exists (and 'return' either filename or the dummy filename):
\newcommand{\figFileOrDummy}[1]{%
% Figure base name (no extension) to be used if the file exists
\def\fodname{#1}%
\def\dummyfig{commands/dummy}%
% Check if output is PS (.EPS) or PDF (.JPG/.PDF/.PNG/...) figures
\ifx\pdfoutput\undefined%
% EPS figures only
\IfFileExists{\fodname.eps}{}{\def\fodname{\dummyfig}}%
\else%
% Check existence of various extensions: PDF, TIF, TIFF, JPG, JPEG, PNG, MPS
\def\figtest{0}% flag below compared to this value
\IfFileExists{\fodname.pdf}{\def\figfilenamefound{1}}{\def\figfilenamefound{0}}%
\IfFileExists{\fodname.jpg}{\def\figfilenamefound{1}}{}%
\IfFileExists{\fodname.png}{\def\figfilenamefound{1}}{}%
% and so on...
% If no files found matching the filename (flag is 0) then use the dummy figure
\ifx\figfilenamefound\figtest%
\def\fodname{\dummyfig}%
\fi%
\fi%
% 'return' the filename
\fodname%
}%
Alternatively, here's a much simpler version which seems to have similar problems:
\newcommand{\figFileOrDummy}[1]{%
\def\dummyfig{commands/dummy}%
\dummyfig%
}
The \def
commands seems to be processed after the expansion of the macro they're trying to define, so it ends up being \def {commands/dummy}...
(note the space after \def
) and obviously complains.
Also it seems to treat the literal contents of the macro as the filename for \includegraphics
, rather than resolving/expanding it first, so complains that the file '\def {commands/dummy}... .png'
doesn't exist..
I've tried also doing something like
\edef\figfilename{\figFileOrDummy{\chapdir/figures/fluxcapacitor}}
to try to force it to make \figfilename
hold just the value rather than the full macro, but I get an Undefined control sequence
error complaining the variables I'm trying to \def
in the \figFileOrDummy
macro are undefined.
So my question is either
I feel like I'm missing something pretty fundamental here...
I think the point is that \expandafter is only interested in its arguments as a string representing a filename, so doesn't evaluate it — macro languages are lazy! Try \expandafter {\includegraphics[width=8cm]}{\chapdir/figures/fluxcapacitor}
.
\def\newcs{abc}
and \def \newcs {abc}
are identical: they are exactly the same sequence of tokens.I first thought the problem lay elsewhere, so wrote something prettier:
\def\dummypath{commands/dummy}% \ifx\pdfoutput\undefined \def\figFileOrDummy#1{\IfFileExists {#1.eps}{#1}\dummypath} \else \def\figFileOrDummy#1{\IfFileExists {#1.pdf}{#1}{\IfFileExists {#1.jpg}{#1}{\IfFileExists {#1.png}{#1}\dummypath}}} %or have more graphics types, if you like. \fi
Alright, so I've found a possible answer to #2, by restructuring the way the macros work (and sort of using some suggestions from Charles Stewart's answer — I'll admit I don't like the 'look' of what seems to be widely considered good LaTeX code, I'm perhaps too ingrained in my C/C++ ways to be a real LaTeX programmer).
Anyway, my answer...
Instead of trying to produce the file name in a macro to pass to the \includegraphics
macro, make a macro that wraps \includegraphics
and passes it the real or dummy file name. This seems to avoid passing (as an argument) a long script/macro, though I don't see any good reason why it should have to be written this way. But it does work...
% Dummy figure file
\def\dummyfigure{commands/dummy}%
% Includegraphics wrapper macro to include either dummy or real figure
\ifx\pdfoutput\undefined
\newcommand{\incgfx}[2]{%
\def\testfile{\chapdir/fig/#2}%
\IfFileExists{\testfile.eps}%
{\includegraphics[#1]{\testfile}}% test file found
{\includegraphics[#1]{\dummyfigure}}% test file not found
}
\else
\newcommand{\incgfx}[2]{%
\def\figfilename{\dummyfigure}
\def\testfile{\chapdir/fig/#2}
\IfFileExists{\testfile.jpg}{\def\figfilename{\testfile}}{}
\IfFileExists{\testfile.png}{\def\figfilename{\testfile}}{}
\IfFileExists{\testfile.pdf}{\def\figfilename{\testfile}}{}
\IfFileExists{\testfile.jpeg}{\def\figfilename{\testfile}}{}
\IfFileExists{\testfile.tif}{\def\figfilename{\testfile}}{}
\IfFileExists{\testfile.tiff}{\def\figfilename{\testfile}}{}
\includegraphics[#1]{\figfilename}
}
\fi
This allows one to use it as intended:
\begin{figure}
\begin{center}
\incgfx{height=3cm}{\chapdir/fig/fluxcapacitor}
\caption{...}\label{fig:...}
\end{center}
\end{figure}
Again, I'd like to think there's a way to make the original idea work rather than having to make a wrapper for existing functions, but this will do for now...
Answer to #3: For this purpose, I find very useful the todonotes
package. It does not provide the level of automation that your code is aiming to offer, but it has a very nice \missingfigure
command that lets you put a dummy box for, you guess it, a missing figure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With