LaTeX文書内から,外部PDFファイルのページ数を取得したい状況はよくあります。例えば,「外部PDFファイルの全ページにわたって○○を繰り返す」というような状況のとき,ループ回数を決めるにはそのページ数を取得せねばなりません。
ここでは,
\newcount\PDFPageCount
と定義したカウントレジスタ \PDFPageCount
に,#1
で指定された外部ファイル のページ数を代入する動きをする,\CountPDFPages
という命令を定義してみましょう。
LuaTeX の場合
LuaTeX の場合,デフォルトで pdfe
ライブラリがグローバル変数 pdfe
にロードされていますので,pdfe.getnofpages()
でページ数がカウントできて簡単です。
\def\CountPDFPages#1{\PDFPageCount=\directlua{tex.print(pdfe.getnofpages(pdfe.open('#1')))}\relax}
なお,後ろの \relax
は \CountPDFPages{input.pdf}234
のように命令呼び出しの直後に数字が続いたときに連結されないために必要です。
pdfe
ライブラリの詳細については,次の記事が参考になります:
XeTeX の場合
XeTeX の場合,\XeTeXpdfpagecount
という,このための専用のプリミティブが用意されているので,それを呼び出すだけです。
\def\CountPDFPages#1{\PDFPageCount=\XeTeXpdfpagecount"#1"\relax}
pdfTeX の場合
pdfTeX の場合,\pdfximage{#1}
として読み込んでおけば,\pdflastximagepages
でページ数を取得できます。
\def\CountPDFPages#1{% \pdfximage{#1}% \PDFPageCount=\pdflastximagepages }
(u)pTeX の場合
この場合が最も厄介です。PDFを調べるプリミティブのようなものでページ数をカウントすることができません。この場合の実装例は,かつて次のコメントで述べたことがあります。
ここでは上記コードのアイデアを説明します。
現在の TeX Live のデフォルトでは restricted mode で特定の外部コマンド実行が許可されており,その中に extractbb
が含まれることに注目します。extractbb
は,graphicx
パッケージの \includegraphics
でPDFを貼り込む際にそのバウンディングボックスを取得するために自動起動される形で用いられています。
例えばその出力は次のようになっています。(-O
オプションで標準出力に出力します。)
$ extractbb -O sample.pdf %%Title: sample.pdf %%Creator: extractbb 20211117 %%BoundingBox: 0 0 595 842 %%HiResBoundingBox: 0.000000 0.000000 595.276000 841.890000 %%PDFVersion: 1.5 %%Pages: 3 %%CreationDate: Wed Apr 19 00:43:57 2023
この中に %%Pages: 3
という出力が含まれることに注目します。よって,この出力をTeXに読み込み,その内容をパースすることで,ページ数の取得が可能になるわけです。
ただし,この出力には %
という文字が含まれ,ページ数を表す文字列はその後に出現するため,そのパースにはTeX文書中で %
のカテゴリーコードを一時変更することが必要になります。
パッケージにまとめる
以上をまとめて,全エンジンで使える \PDFPageCount
を,LaTeXパッケージにまとめる形で定義してみましょう。iftex
パッケージを用いて現在のTeXエンジンの種類を判定し,それに応じたPDFページカウントルーチンを呼び出すようにします。
使用法
上記の countpdfpages.sty
を使えば,例えば次のようなLaTeX文書をコンパイルすることで,エンジンの種類によらず外部PDFファイルのページ数が取得できるようになります。
\documentclass{article} \usepackage{countpdfpages} \begin{document} \def\target{sample.pdf} \CountPDFPages{\target} The number of pages in \target\ is \the\PDFPageCount. \end{document}