# After a series of nested \includegraphics, some PDF viewers fail to display the image

I'll admit this is a convoluted example, but I like drawing with TikZ and LaTeX and this particular issue has come up for me more than once.

The minimal working example takes a few files, but in a nutshell - a PDF is produced at each compile with the current filesize in it. After a set number of includes some viewers (evince,okular,acroread*) fail to display the deeply nested images, while others segfault (xpdf) and only one (gs) shows the full image correctly.

*Note that acroread won't fail on the example below, but will if you keep cranking up the iterations.

# first.tex

\documentclass{standalone}\begin{document}start\end{document}


# next.tex

\documentclass{standalone}
\usepackage{graphicx}
\IfFileExists{\jobname.pdf}
{\edef\Size{\pdffilesize{\jobname.pdf}}}
{\def\Size{0}}

\renewcommand{\arraystretch}{0}
\setlength\fboxsep{1pt}
\newcommand{\X}{\includegraphics{first.pdf}}
\begin{document}%
\begin{tabular}{@{}l@{}}%
\framebox{\Size} \\ \X
\end{tabular}
\end{document}


# Makefile

all:
make first
make block
make block
make block

evince next.pdf
gs next.pdf

first:
pdflatex first.tex

next:
pdflatex next.tex
cp next.pdf first.pdf

block:
make next
make next
make next
make next
make next
make next
make next
make next
make next
make next


# Examples (gs vs evince)

Questions:

1. Why can't the viewers display the deeply nested images?

2. By running pdf2ps -> ps2pdf the problem is fixed, but is there any risk for more complicated images being mangled (i.e. using TikZ or fonts with ConTeX)?

-
Can you try also with \documentclass[preview]{standalone} in first.tex? –  percusse Oct 8 '12 at 22:28
What is make first supposed to do? How do you run that Makefile? With make all I get missing separator. –  egreg Oct 8 '12 at 22:47
I still get Missing separator. –  egreg Oct 8 '12 at 23:14
@egreg You have to replace the spaces at the begin of the indented lines by a tabulator. –  Heiko Oberdiek Oct 8 '12 at 23:24
@HeikoOberdiek Thanks, I didn't realize that the markup ate the tab characters and replaced them with spaces. Is there any way to stop that? –  Hooked Oct 8 '12 at 23:40

evince, okular and xpdf share a common heritage for their pdf parsing facilities (evince is based on poppler which is based on xpdf; okular is based on kpdf is based on xpdf) and they all explicitly limit the form recursion depth precisely to avoid infinite recursion on damaged pdfs that have forms who include themselves (possibly via a convoluted route). This could also be a DoS attack from maliciously-constructed pdfs. Here is a very recent patch to poppler to increase the recursion depth from 20 to 100, but presumably your installation of evince uses the older limit of 20.

The PDF specification PDF 32000-1:2008 doesn't seem to explicitly limit the allowed recursion level for form XObjects but it does say in section 8.10.1 that

When the Do operator is applied to a form XObject, a conforming reader shall perform the following tasks:
a) Saves the current graphics state, as if by invoking the q operator (see 8.4.4, "Graphics State Operators")
[....]
e) Restores the saved graphics state, as if by invoking the Q operator (see 8.4.4, "Graphics State Operators")

and in Appendix C.2, table C.1 it gives a limit on q/Q nesting as 28 levels deep, based on the fact that these operators map to PostScript gsave and grestore operators when converting PDF to PostScript (table B.1 of the PostScript spec, 3rd edition gives a maximum gsave level of 31, and presumably a couple of these are needed for other purposes, leaving 28 for PDF q/Q and form XObjects).

-
Any idea on why runnning pdf2ps -> ps2pdf fixes the problem? Do the images get somehow "mapped down"? –  Hooked Oct 9 '12 at 4:20
Yes, it seems ghostscript flattens the forms. Actually ps2pdf next.pdf next-refried.pdf is enough, despite the name of the command it can take pdf as input. –  Lev Bishop Oct 9 '12 at 5:03