LaTeX+pdfpagesでPDFファイルにしおり(目次)を後付けする


PDFのしおり

PDFにはしおり(目次、ブックマーク)1という機能があります。しおりは文書の目次等をPDFのメタ情報として埋め込んだもので、大抵のPDFビューワーではしおりを使って特定のページにジャンプすることができます。

さて、PDFのしおりというのは、基本的にはPDFを作る人が埋め込んでおくものです。例えば、LaTeXであればhyperrefパッケージを使うことで目次情報を元にしたしおりを埋め込むことができます。

しかし、世の中にはしおりが設定されていないPDFが往々にして存在します。例えば、紙や書類をスキャンして作ったPDFにはしおりは設定されません。電子書籍として買ったPDFも、PDFを作った人がしおりを埋め込む設定にしていなかったらしおりは使えません。

しおりが設定されていないPDFファイルは閲覧性が悪く、価値が半減すると言っても過言ではないでしょう。どうにかして、PDFファイルにしおりを後付けできないでしょうか?

Adobe Acrobatのような有償のソフトウェアを使えば(PDFに保護がかかっていない限り)後付けでしおりを設定することができます。実際筆者もAcrobatでPDFファイルにしおりを後付けしたこともあります。しかし、これは万人に使える方法ではありません。できればフリーソフトのみでできる方法があってほしいところです。

LaTeX+pdfpagesを使う

LaTeXにはpdfpagesという、PDFファイルを文書に埋め込むことができるパッケージがあります。このパッケージを使うと、PDFファイルの加工っぽいこともできます。これを使ってPDFファイルにしおりを埋め込めないか考えてみましょう。

基本

まず、pdfpagesの基本的な使い方をみてみます。

\documentclass{book}
\usepackage{pdfpages}
\begin{document}
\includepdf[pages=-,fitpaper]{sugoi-book.pdf}
\end{document}

PDFファイルを挿入するには \includepdf コマンドを使います。

  • pages オプションで挿入する範囲を指定できます。 - を指定するとすべてのページを挿入することになります。
  • fitpaper はページのサイズを挿入するPDFに合わせるという意味です。これを省くと、デフォルトの用紙サイズ(レターサイズかA4)に挿入するPDFを貼り付けたような形になります(大抵の本はA4よりも小さいですよね)。

オプションについて細かいことはpdfpagesのドキュメントを参照してください(ターミナルや「ファイル名を指定して実行」で texdoc pdfpages を実行すれば表示されます)。

この状態でLaTeX文書を処理すると、元のPDFファイルとほぼ同じものが出来上がります。

注:この記事では特に断らない限りpdfLaTeXを前提とします。(u)pLaTeX+dvipdfmxを使う方はクラスオプションとして dvipdfmx を指定するなど、追加の設定が必要となるかもしれません。

タイトル、著者などのメタ情報を指定する(余談)

少し横道に逸れますが、PDFファイルのタイトルや著者などのメタ情報を設定してみましょう。これらの情報はhyperrefパッケージで設定できます。

\documentclass{book}
\usepackage{hyperref}
\hypersetup{
  pdftitle={Sugoi Book},
  pdfauthor={You-Know-Who}
}
\usepackage{pdfpages}
\begin{document}
\includepdf[pages=-,fitpaper]{sugoi-book.pdf}
\end{document}

他にもサブタイトルやキーワード等のメタ情報を設定できます。

(TODO: Unicode文字を含む場合は pdfencoding=autounicode オプションが必要?)

しおりの設定

いよいよ本題です。

通常のLaTeX+hyperrefでPDFを作る際は、 \chapter コマンドや \section コマンドによって目次の情報が .out ファイルに書き出され、それが2回目の実行でPDFのしおりとして反映される、という形になります。

しかし、今回のケースでは本の中身はすでに出来上がっているわけですから、 \chapter コマンドや \section コマンドを使って章や節を定義するわけにはいきません。

この場合にしおりを定義する方法は何通りか考えられます。

  • 自力で .out ファイルに書き込む
  • \includepdf コマンドの addtotoc オプションを使う
  • bookmarkパッケージの \bookmark コマンドを使う

結論だけ知りたい人は下の方の「bookmarkパッケージを使う」の部分までスクロールしてください。

.out ファイルをいじる

まず考えられるのは、hyperrefパッケージの代わりに自力で .out ファイルを作成するという方法です。hyperrefパッケージが吐いた .out ファイルには \BOOKMARK [0][-]{chapter.1}{Sugoi hon}{}% 1 というような行が並んでいるので、これを真似てやればいけそうです。各ページに対しての chapter.1 に相当する識別子は、 \includepdflink, linkname オプションを使えば用意できる気がします。

しかし、この方法はお勧めしません。理由としては、 \BOOKMARK コマンドはドキュメント化されていない内部コマンドであること、それに、しおりとして表示される文字列の部分(\BOOKMARK コマンドの最後から2番目の引数)は普通に書いたのではダメで、PDF向けの内部エンコーディング(UTF-16とかPDFDocEncoding)である必要があることが挙げられます。

addtotocオプションを使う

第二に、 \includepdf コマンドの addtotoc オプションを考えます。

\includepdf[
  pages=-,
  fitpaper,
  addtotoc={
    7,chapter,0,{Preface},preface,
    9,chapter,0,{Contents},contents,
    12,chapter,0,{Chapter I. Foo},chap1
  }
]{sugoi-book.pdf}

addtotoc オプションには、各しおりについて5つの項目をカンマ区切りで並べたものを繰り返します。最初はページ番号、2番目はLaTeXのセクション類の名前、3番目はしおりの深さ(level)、4番目はしおり用の文字列、5番目はLaTeXの \ref とかで使うラベル名です。カンマ区切りで繰り返せば複数のしおりを指定できますが、最後のしおりの後に余計なカンマがあってはいけません。(詳しくはpdfpagesのマニュアルを読んでください)

これを使えばそれっぽい感じでしおりを付加することができますが、

  • 2番目と5番目の項目が余計。特に5番目のラベル名は、今回の用途では不要な割に、省略(空文字列を設定)すると「ラベルが重複している」系の警告が出る。

という欠点があります。

bookmarkパッケージを使う

3番目の方法は、bookmarkパッケージを使うことです。使い方は、

\documentclass{book}
\usepackage{hyperref}
\hypersetup{
  % 省略
}
\usepackage{bookmark}
\usepackage{pdfpages}
\begin{document}
\includepdf[pages=-,fitpaper]{sugoi-book.pdf}
\bookmark[page=7,level=0]{Preface}
\bookmark[page=9,level=0]{Contents}
\bookmark[page=12,level=0]{Chapter I. Foo}
\end{document}

という風になります。 \bookmark コマンドによってしおりを設定できます。

ここではしおりのジャンプ先はページ番号で指定していますが、他の指定方法もあります(外部のファイルとかURIとか)。詳しくはbookmarkパッケージのマニュアルを参照してください。

ページ番号

大抵の本は最初の方(前付)のページ番号がローマ数字になっており、第1章の最初のページがアラビア数字の1ページとなっています。LaTeXだと \frontmatter, \mainmatter によってページ番号の種類が切り替割ります。ページ番号は紙面に印字されるだけではなくPDFのメタ情報としても持てるようで、LaTeX+hyperrefで \frontmatter 等を使って作ったPDFファイルの場合は、PDFビューワーで表示させた時に最初の方のページ番号がローマ数字になっています。

しかし、スキャンしてできたPDFというのは本の最初のページ(表紙)がアラビア数字の1ページとなっています。また、 \bookmark コマンドの page オプションに指定するページ番号は、本としてのページ番号(本文の1ページ目が1ページ)ではなく、PDFの最初のページが1ページとなるページ番号です。

生成されるPDFファイルのページ番号

LaTeX+pdfpages+hyperrefで生成されるPDFの最初の方のページ番号をローマ数字にするには、 \includepdf を2回に分けて、それぞれページ番号を設定すれば良いです。

% 略
\begin{document}
\pagenumbering{roman} % ページ番号がローマ数字
\includepdf[page=1-11,fitpaper]{sugoi-book.pdf}
\pagenumbering{arabic} % ページ番号がアラビア数字
\includepdf[page=12-,fitpaper]{sugoi-book.pdf}
\end{document}

\frontmatter\mainmatter コマンドを使ってしまうと空白ページが挿入されてしまう可能性があるため、 \pagenumbering コマンドを使います。

\bookmark コマンドに指定するページ番号

\bookmark コマンドに指定するページ番号は前付や本文の区別はなく、あくまでPDFファイルの先頭を1ページ目とするページ番号です。しかし、本の目次に記載されているページ番号は本文の1ページ目から始まっているので、 \bookmark コマンドを書き込む際にページ番号の換算が必要になります(例:本文が12ページから始まっていたら、本の目次に書かれているページ番号にそれぞれ11を加える)。

目次の項目が少数なら良いですが、たくさんあると換算の手間は馬鹿になりません。幸い、(La)TeXにはプログラミング機能があるので、「コマンドの引数で指定された整数に11を加える」という処理を記述できます。

例えば、

% Usage: \mainbookmark{level}{page}{title}
\newcommand\mainbookmark[3]{%
  \edef\temp{\noexpand\bookmark[page=\the\numexpr #2+11\relax,level=#1]}%
  \temp{#3}%
}

というマクロを定義しておけば、

\mainbookmark{0}{35}{Chapter II. Bar}
\mainbookmark{1}{35}{1. Hoge}
\mainbookmark{1}{41}{2. Piyo}

という記述が

\bookmark[page=46,level=0]{Chapter II. Bar}
\bookmark[page=46,level=1]{1. Hoge}
\bookmark[page=52,level=1]{2. Piyo}

に展開されます。

前付のページ数は本によって変わるので、マクロ定義中の \the\numexpr #2+11\relax11 の部分はそれに応じて書き換えてください。

(余談ですが、 \expanded プリミティブを使えば \mainbookmark の中で一旦 \edef する必要がなくなって記述が少しスッキリします。)

まとめ

11ページの前付からなる sugoi-book.pdf

  • タイトルや著者名のメタ情報の付加
  • 前付のページ番号のローマ数字化
  • しおりの付加

を行うには、以下のような .tex ファイルを書いて処理してやれば良いです:

\documentclass{book}
\usepackage{hyperref}
\hypersetup{
  pdftitle={Sugoi Book},
  pdfauthor={You-Know-Who},
  bookmarks
}
\usepackage{bookmark}
\usepackage{pdfpages}

% Usage: \mainbookmark{level}{page}{title}
\newcommand\mainbookmark[3]{%
  \edef\temp{\noexpand\bookmark[page=\the\numexpr #2+11\relax,level=#1]}%
  \temp{#3}%
}

\begin{document}
\pagenumbering{roman}
\includepdf[pages=1-11,fitpaper]{sugoi-pdf.pdf}
\pagenumbering{arabic}
\includepdf[pages=12-,fitpaper]{sugoi-book.pdf}
\bookmark[page=7,level=0]{Preface}
\bookmark[page=9,level=0]{Contents}
\mainbookmark{0}{1}{Chapter I. Foo}
\mainbookmark{1}{1}{1. Nyaa}
\mainbookmark{1}{7}{2. Meow}
\mainbookmark{1}{14}{3. Fugyaaaa}
% ...
\end{document}

ところで、電子書籍(保護のかかっていないPDFファイル)として販売されている本に対して、第三者がこういうLaTeXファイル(本文は含まないが目次の情報を含む)を配布するのって著作権的にどうなんですかね?


  1. この機能の言い方は色々あるようですが、この記事では「しおり」で通します。