46

I was recently in charge of organizing all of the references and labels in a very large scientific proposal document. My workflow typically involved compiling the document, seeing a "There were undefined references." statement, and then searching the resultant PDF file for the usual "?" or "??."

Sometimes those missing references were in regard to labels for figures that were used throughout the text and not something in our bibliography. It got me wondering:

Is it possible to have a "dummy" or "default" figure to use in \includegraphics statements if the requested file is missing?

Perhaps a use case would be if in the LaTeX document there were a command such as \includegraphics{scaling.pdf}, but scaling.pdf doesn't exist in the current directory, so we use the existing dummy.pdf automatically. I assume this involves renewcommand'ing the includegraphics command, but how should one go about doing it for this scenario?

lockstep
  • 250,273
cm2
  • 818
  • 8
  • 13
  • Just to say that it can be useful, to avoid error due to filename with underscore, to add \detokenize in the message box for missing file : \newcommand{\includegraphicsmaybe}[1]{\IfFileExists{#1}{\includegraphics{#1}} {\makebox[0pt]{\detokenize{File #1 is missing}}}} –  May 14 '14 at 14:40

3 Answers3

56

Try the standard command \IfFileExists. It has three arguments: the file name, what to do if it exists, and what to do if it does not:

\IfFileExists{scaling.pdf}{\includegraphics{scaling.pdf}}{\includegraphics{dummy.pdf}}

Of course, you can add syntactic sugar to this:

\newcommand{\includegraphicsmaybe}[1]{\IfFileExists{#1}{\includegraphics{#1}}{\includegraphics{dummy.pdf}}}
Boris
  • 38,129
  • Great, exactly what I was looking for! – cm2 Jan 04 '12 at 01:50
  • 3
    instead of (or in addition to) using a dummy figure, it would be informative to show the name of the missing figure in the output. – barbara beeton Jan 04 '12 at 13:41
  • @barbarabeeton: Indeed! My next step was going to write a tikz code that would write the filename overtop of the image. – cm2 Jan 04 '12 at 17:08
  • 1
    You do not need tikz for this; just put in the "else" part of \IfFileExists 'File #1 is missing`. – Boris Jan 04 '12 at 17:28
  • That would replace the dummy image with text, which is an option. I think having some standard image with text overtop would probably stand out more in the document for quick finding. Perhaps just changing the text color, without an image, would be sufficient. – cm2 Jan 04 '12 at 17:44
  • 4
    You can have both text and image, for example,\newcommand{\includegraphicsmaybe}[1]{\IfFileExists{#1}{\includegraphics{#1}}{\makebox[0pt]{File #1 is missing}\includegraphics{dummy.pdf}}} – Boris Jan 04 '12 at 17:47
20

The last macro called within graphicx) before including the image is \Gin@ii. Due to the structure of \Gin@ii, it is possible to patch this command and temporarily remove LaTeX error-producing capability. Here's a minimal example:

enter image description here

\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\usepackage{graphicx}% http://ctan.org/pkg/graphicx
\newcommand{\noimage}{%
  \setlength{\fboxsep}{-\fboxrule}%
  \fbox{\phantom{\rule{150pt}{100pt}}}% Framed box
}

\makeatletter
\patchcmd{\Gin@ii}
  {\begingroup}% <search>
  {\begingroup\renewcommand{\@latex@error}[2]{\noimage}}% <replace>
  {}% <success>
  {}% <failure>
\makeatother

\begin{document}
\includegraphics[width=150pt]{tiger} \par
\includegraphics[width=150pt]{tigers}
\end{document}

In the above example, the command \noimage is used to represent the output that is generated when no image exists. You could, for example, define \noimage using

\newcommand{\noimage}{\includegraphics{dummy}}

if you wish to include dummy instead of my 150pt x 100pt empty rectangle. The redefinition of \@latex@error (which takes 2 arguments that is gobbles and replaces with \noimage) occurs inside a group, making it local and is therefore reverted back after \Gin@ii finishes.

Here is the final macro called within \Gin@ii called \Ginclude@graphics; I've highlighted the part that is indirectly affected by the redefinition of \@latex@error:

\def\Ginclude@graphics#1{%
  \begingroup
  \let\input@path\Ginput@path
  \filename@parse{#1}%
  \ifx\filename@ext\relax
    \@for\Gin@temp:=\Gin@extensions\do{%
      \ifx\Gin@ext\relax
        \Gin@getbase\Gin@temp
      \fi}%
  \else
    \Gin@getbase{\Gin@sepdefault\filename@ext}%
    \ifx\Gin@ext\relax
       \@warning{File `#1' not found}%
       \def\Gin@base{\filename@area\filename@base}%
       \edef\Gin@ext{\Gin@sepdefault\filename@ext}%
    \fi
  \fi
    \ifx\Gin@ext\relax
         \@latex@error{File `#1' not found}% <----------------------------- MODIFIED
         {I could not locate the file with any of these extensions:^^J% <-- MODIFIED
          \Gin@extensions^^J\@ehc}% <-------------------------------------- MODIFIED
    \else
       \@ifundefined{Gin@rule@\Gin@ext}%
         {\ifx\Gin@rule@*\@undefined
            \@latex@error{Unknown graphics extension: \Gin@ext}\@ehc
          \else
            \expandafter\Gin@setfile\Gin@rule@*{\Gin@base\Gin@ext}%
           \fi}%
         {\expandafter\expandafter\expandafter\Gin@setfile
             \csname Gin@rule@\Gin@ext\endcsname{\Gin@base\Gin@ext}}%
    \fi
  \endgroup}

The advantage with this approach is that you don't have to modify any of your existing macro definitions, like \includegraphics. It would be possible to extend this to indicate the offending (missing) file as well.

Werner
  • 603,163
  • Actually it is better to patch \Gin@getbase command. In one of my (yet unpublished) packages I patched it to select print version of a graphics for print version, web version of graphics for web version and the default version if the special version did not exist. – Boris Jan 04 '12 at 15:55
  • @Werner: Thanks for this alternative approach. Although it is more involved, I do like that fact that I don't have to modify the \includegraphics macro. – cm2 Jan 04 '12 at 17:10
  • 1
    @cm2: Remember, the only code required to do this is everything between \makeatletter and \makeatother. Showing \Ginclude@graphics at the end of my answer was just an illustration of what \patchcmd modifies within the command. I don't think it's that much more involved... – Werner Jan 04 '12 at 17:20
  • @Werner: Indeed, you are correct. I guess by "more involved," I simply meant that you had to modify some internal functionality. The amount of work involved is similar. – cm2 Jan 04 '12 at 17:41
  • it seems not to work with beamer. I get \end{frame} error. – luchonacho Feb 05 '18 at 14:58
  • Solution for beamer here. – luchonacho Feb 05 '18 at 15:36
3

Based on the other answers, I have come up with the following code to ignore missing image files in a latex document.

The advantage of this answer over the others is that it deals with the optional arguments of \includegraphics, it doesn't require a dummy.pdf file and it doesn't require changing any of the \includegraphics commands in the body of the document.

% deal with missing images which are not directly included in the repository
\newcommand{\noimage}{%
  \setlength{\fboxsep}{-\fboxrule}%
  \fbox{\phantom{\rule{10pt}{10pt}}File missing\phantom{\rule{10pt}{10pt}}}% Framed box
}
\let\includegraphicsoriginal\includegraphics
\renewcommand{\includegraphics}[2][width=\textwidth]{\IfFileExists{#2}{\includegraphicsoriginal[#1]{#2}}{\noimage}}
  • 2
    I think it should be \renewcommand{\includegraphics}[2][width=\textwidth]..., otherwise it'll raise an error. – Phelype Oleinik Sep 04 '18 at 11:41
  • It doesn't raise an error for me and I cannot find any source which says the (default) arguments to a (re)newcommand should be named in that way. – Tim Kuipers Sep 06 '18 at 08:26
  • 1
    It's not about how the default arguments to \renewcommand should be named (they could be named \HappyPotatoes for that matter). It's about how \includegraphicsoriginal will understand these arguments. \textwidth is not a valid option for \includegraphics. – Phelype Oleinik Sep 06 '18 at 10:33
  • What do you mean by named? \includegraphics expects a specific format for optional arguments and in the best case your pass-through will yield something unexpected. – TeXnician Sep 06 '18 at 10:34
  • I'm sorry, my head was in the wrong place. I've edited the answer and fixed the mistake you pointed out. – Tim Kuipers Sep 06 '18 at 13:28
  • This is great. I think this should be another option in the includegraphics package! – Pepe Mandioca Dec 11 '19 at 20:56