18

Is there a possibility to get the total number of pages of an external PDF file within a LaTeX document?

Assuming that there exists a PDF file test.pdf with 8 pages in the same directory my LaTeX file is saved in. Here's my very basic approach:

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{xparse}

\DeclareDocumentCommand \pdfnumberofpages { m } {
  % Do some magic
}

\begin{document}

\texttt{test.pdf}: \pdfnumberofpages{test.pdf} pages

\end{document}

The resulting document should then contain

test.pdf: 8 pages

I know it should be possible somehow (pdfpages must do something like this), but I don't know how to implement it.

dawu
  • 1,648

4 Answers4

24

pdfTeX, LuaTeX

\pdflastximageages, see the answer of Symbol 1.

Remarks:

  • \pdfximage cannot be used in DVI mode.

LuaTeX

Unhappily, LuaTeX is constantly changing its interfaces. \luatexluaescapestring was renamed to \luaescapestring and the library epdf was replaced by the library pdfe. The following example was developed and tested with 1.15.0.

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

\documentclass{article}

\newcommand*{\pdfnumberofpages}[1]{% \directlua{% local doc = pdfe.open("\luaescapestring{#1}") local pages if (doc) then pages = pdfe.getnofpages(doc) 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.

Older 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} % XeTeX check \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname XeTeXpdfpagecount\endcsname\relax % pdfTeX check \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname pdflastximagepages\endcsname\relax \newcommand{\numberofpages}[1]{% 0% \errmessage{\noexpand\numberofpages is unsupported for this driver}% }%
\else % Definition for pdfTeX \ifpdf \newcommand
{\numberofpages}[1]{% \pdfximage{#1}% \the\pdflastximagepages }% \else \newcommand{\numberofpages}[1]{% 0% \errmessage{\noexpand\numberofpages is unsupported in DVI mode}% }% \fi \fi % LuaTeX check \typeout{LuaTeX check} \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname directlua\endcsname\relax \else \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname luaescapestring\endcsname\relax \typeout{luaescapestring is undefined}% \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname luatexluaescapestring\endcsname\relax \typeout{luatexluaescapestring is undefined}% \else \newcommand{\LuaEscapeString}{}% \let\LuaEscapeString\luatexluaescapestring \fi \else \newcommand{\LuaEscapeString}{}% \let\LuaEscapeString\luaescapestring \fi \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname LuaEscapeString\endcsname\relax \else % Definition for newer LuaTeX \ifnum0\directlua{if pdfe then tex.write(1)end}=1 % \renewcommand{\numberofpages}[1]{% \directlua{% local doc = pdfe.open("\LuaEscapeString{#1}") local pages if (doc) then pages = pdfe.getnofpages(doc) else pages = 0 end tex.write(pages) }% }% \else % Definition for older LuaTeX \ifnum0\directlua{if epdf then tex.write(1)end}=1 % \renewcommand{\numberofpages}[1]{% \directlua{% local doc = epdf.open("\LuaEscapeString{#1}") local pages if (doc) then pages = doc:getCatalog():getNumPages() else pages = 0 end tex.write(pages) }% }% \fi \fi \fi \fi \else % Definition for XeTeX \newcommand{\numberofpages}[1]{% \the\XeTeXpdfpagecount"#1" % space ends the file name scanning }% \fi

\begin{document} Number of pages: \numberofpages{test.pdf}% Should be different from \jobname.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.
Heiko Oberdiek
  • 271,626
  • 1
    Wow, that's a really detailled answer! Thank you very much! Unfortunately, I only looked for pdflatex and that's why Symbol 1's answer is the best for me. It's too bad, that I only can accept one answer. But I voted you up! – dawu Aug 27 '14 at 10:38
  • 2
    UPDATE

    With LuaTEX version 1.10 the epdf library was replaced by the pdfe library (Reference Manual April 2019 p.257)

    Now, in order to get the total number of pages of an external pdf a couple of lines must be changed. For example

    function totalnopages(filename)
     local doc = pdfe.open(filename)
     if doc then
      local pages = doc.Pages  
      local pagestotal = pdfe.getnofpages(doc)
    else
     pagestotal =0
    

    end tex.write(pagestotal) end

    – Simon Dispa Aug 28 '19 at 14:01
  • Can you update your answer for the latest versions of TeXLive (2022)? Thanks. – Paul Gaborit Apr 19 '22 at 08:24
  • @SimonDispa Thanks. The constant changing of the interfaces in LuaTeX is quite annoying. – Heiko Oberdiek Apr 20 '22 at 17:33
  • @PaulGaborit I have updated the answer for LuaTeX 1.15.0. – Heiko Oberdiek Apr 20 '22 at 17:33
  • @PaulGaborit with a current l3graphics package you can do \graphics_get_pagecount:nN {example-image-a4-numbered.pdf}\l_tmpa_tl and then \l_tmpa_tl will contain the page numbers. That works with all engines. – Ulrike Fischer Apr 20 '22 at 19:08
  • @UlrikeFischer Thanks. It deserves a new answer! :-) – Paul Gaborit Apr 20 '22 at 21:31
  • @PaulGaborit I added one. – Ulrike Fischer Apr 20 '22 at 22:27
19

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}
Symbol 1
  • 36,855
  • That's really easy! Thank you! I also looked at pdfpages, but it was too much for me and I couldn't find the relevant command. – dawu Aug 27 '14 at 10:35
  • To the reader: Contrary to what one might expect, \pdfximage does not embed the pdf as an image. The document shown compiles to an empty page with the text … pages – just as I wanted :) – Socowi Nov 09 '19 at 13:07
3

With a current l3graphics (currently in l3experimental) you can use \graphics_get_pagecount:nN to retrieve the page count and then either print it or use it as page number in a \includegraphics command. \graphics_get_pagecount:nN works with all engines and also with LaTeX in dvi mode.

\documentclass{article}
\usepackage{l3graphics}
\usepackage{graphicx}
\begin{document}

\ExplSyntaxOn \graphics_get_pagecount:nN {example-image-a4-numbered.pdf}\l_tmpa_tl \l_tmpa_tl \includegraphics[scale=0.5,page=\l_tmpa_tl]{example-image-a4-numbered.pdf} \ExplSyntaxOff

\end{document}

enter image description here

Ulrike Fischer
  • 327,261
-1

If someone is interested in a one-line command that writes the number of pages to the file test.pdf.pages (if test.pdf is the PDF file in question), the following (built upon the accepted answer) is working in command prompt under Windows 10 with MikTeX:

pdflatex "\documentclass{minimal}\nofiles\def\pdffile{test.pdf}\begin{document}\pdfximage{\pdffile}\newwrite\myfile\immediate\openout\myfile=\pdffile.pages\makeatletter\immediate\write\myfile{\the\pdflastximagepages}\makeatother\immediate\closeout\myfile\end{document}"

Together with test.pdf.pages, 2 unwanted files are generated: minimal.pdf and minimal.log, which can be deleted after compilation.

mmj
  • 1,702