TeX Alchemist Online

TeX のこと,フォントのこと,Mac のこと

LaTeX文書内から外部PDFファイルのページ数を取得する

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 ライブラリの詳細については,次の記事が参考になります:

qiita.com

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を調べるプリミティブのようなものでページ数をカウントすることができません。この場合の実装例は,かつて次のコメントで述べたことがあります。

okumuralab.org

ここでは上記コードのアイデアを説明します。

現在の 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}