Get number of pages of external PDF

pdfTeX, LuaTeX

\pdflastximageages, see the answer of Symbol 1.

Remarks:

  • \pdfximage cannot be used in DVI mode.

LuaTeX

The number of pages can also be retrieved via the epdf Lua library:

\documentclass{article}

\newcommand*{\pdfnumberofpages}[1]{%
  \directlua{%
    local doc = epdf.open("\luatexluaescapestring{#1}")
    local pages
    if (doc) then
      pages = doc:getCatalog():getNumPages()
    else
      pages = 0
    end
    tex.write(pages)
  }%
}

\begin{document}
Number of pages: \pdfnumberofpages{test.pdf}
\end{document}

Remarks:

  • If the document does not exists, the macro \pdfnumberofpages returns zero.
  • \pdfnumberofpages is full expandable. Therefore it can be used in counter assignments, it can be written to a file, ...
  • It also works in DVI mode.

XeTeX

XeTeX provides \XeTeXpdfpagecount:

\documentclass{article}

\newcommand*{\numberofpages}[1]{%
  \the\XeTeXpdfpagecount"#1" %
}

\begin{document}
Number of pages: \numberofpages{test.pdf}
\end{document}

Remarks:

  • If the file does not exists, the result is zero.
  • Also this version if full expandable.

Summary

The following example puts the different versions together:

\documentclass{article}

\usepackage{ifpdf}
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname XeTeXpdfpagecount\endcsname\relax
  \begingroup\expandafter\expandafter\expandafter\endgroup
  \expandafter\ifx\csname pdflastximagepages\endcsname\relax
    \newcommand*{\numberofpages}[1]{%
      0%
      \errmessage{\noexpand\numberofpages is unsupported for this driver}%
    }%    
  \else
    \ifpdf
      \newcommand*{\numberofpages}[1]{%
        \pdfximage{#1}%
        \the\pdflastximagepages
      }%
    \else
      \newcommand*{\numberofpages}[1]{%
        0%
        \errmessage{\noexpand\numberofpages is unsupported in DVI mode}%
      }%
    \fi
    \begingroup\expandafter\expandafter\expandafter\endgroup
    \expandafter\ifx\csname directlua\endcsname\relax
    \else
      \ifnum0\directlua{if epdf then tex.write(1)end}=1 %
        \renewcommand*{\numberofpages}[1]{%
          \directlua{%
            local doc = epdf.open("\luatexluaescapestring{#1}")
            local pages
            if doc then
              pages = doc:getCatalog():getNumPages()
            else
              pages = 0
            end
            tex.write(pages)
          }%
        }%
      \fi
    \fi 
  \fi
\else
  \newcommand*{\numberofpages}[1]{%
    \the\XeTeXpdfpagecount"#1" % space ends the file name scanning
  }%
\fi

\begin{document}
Number of pages: \numberofpages{test.pdf}
\end{document}

Remarks:

  • If the \newcommand and \renewcommand are replaced by \def constructs, then the definition also works in plain TeX. (\luatexluaescapestring might be available as \luaescapestring or has to be enabled via tex.enableprimitives.)
  • If the retrieval of the number of pages is not supported, an error message is thrown.

After \tracingmacros1 with option pages=last-1, it seems like pdfpages uses a feature of pdf(la)tex to get the number.

\documentclass{minimal}
\begin{document}
    \pdfximage{test-29.pdf}
    \the\pdflastximagepages\ pages
\end{document}