views:

157

answers:

3

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

  1. How do I make this macro expand properly?; or
  2. If this is the wrong way of structuring my macros, how should I actually structure such a macro, in order to be able to insert dummy/real figures automatically?; or
  3. Is there a package that already handles this type of thing nicely that I've overlooked?

I feel like I'm missing something pretty fundamental here...

+1  A: 

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.

Alessandro C.
thanks, yeah that looks like useful package but not exactly what i'm after, i'd like it to be automatic if possible...
drfrogsplat
+3  A: 
Charles Stewart
drfrogsplat
+2  A: 

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...

drfrogsplat