41

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?

  • 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}}}} – user51717 May 14 '14 at 14:40
49

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}}}
  • Great, exactly what I was looking for! – cm2 Jan 4 '12 at 1: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 4 '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 4 '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 4 '12 at 17:28
  • 3
    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 4 '12 at 17:47
18

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.

  • 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 4 '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 4 '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 4 '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 4 '12 at 17:41
  • it seems not to work with beamer. I get \end{frame} error. – luchonacho Feb 5 '18 at 14:58
1

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 4 '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 6 '18 at 8: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 6 '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 6 '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 6 '18 at 13:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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