自炊したPDF加工についてのメモ

スキャナで書籍を自炊すると、閉じ方向やページレイアウトに不満が残ります。 それを修正する方法を備忘録として紹介します。

TL;DR

スキャナで書籍を自炊したPDFを加工するには、 今のところ以下の方法が良いとの結論に達しています。

  1. PDFtk で栞(しおり)を挿入する
  2. Perl + PDF::API2 で右綴じ&見開きを設定する

背景

少し前に入手した ScanSnap iX500 でのスキャンにも慣れてきて、 幾つか漫画もスキャンしたのですが2つほど大きな不満がありました。 1つは栞が設定できないことで、 特定のエピーソードを読むのに先頭から順にページ送りするのは、 なんともダルい作業です。

もう1つは見開きのためのページレイアウト。 一般に漫画は右綴じなのですが、 iX500 に付属のソフトは左綴じしか出力できません。 作者渾身の見開きページがまったく再現できずに残念なことになってしまいます。

以上2点の不満を解決するためにスキャン後のPDFの加工を模索していました。 その結果、現時点における私にとっての最適解を以下で解説します。

解法

栞の追加

栞を追加するには PDFtk を使います。 リンク先からダウンロードしたファイルには色々なファイルが含まれていますが、 Windows で実行する際に必要なのは pdftk.exe と libiconv2.dll だけですので、 PATH の通った場所にコピーするのも良いでしょう。 私はそうしてます。

で、栞を追加するにあたり入力データとして、 以下のような栞定義ファイルを用意します。

BookmarkBegin
BookmarkTitle: タイトル1
BookmarkLevel: 1
BookmarkPageNumber: 1

BookmarkBegin
BookmarkTitle: タイトル1-2
BookmarkLevel: 2
BookmarkPageNumber: 3

内容から想像が付くでしょうが、Title でラベルを、 Level によって木構造のネストを、 PageNumber によってリンクする先のページ番号を指定します。 日本語については必ずUTF-8で保存しましょう。

このようなファイルを bookmarks.txt と保存したら、 以下のコマンド例でPDFに栞として埋め込みます。 ココでは INPUT.pdf が入力となる栞の無い PDF で、 OUTPUT.pdf が栞が埋め込まれた出力となる PDF です。

$ pdftk INPUT.pdf update_info_utf8 bookmarks.txt output OUTPUT.pdf

右綴じ&見開き設定

右綴じ&見開きの設定はいくつか方法を試したのですが、 Perl の PDF::API2 がもっとも安定しました。 PDF::API2 は以下のように cpan を使ってインストールできます。

$ cpan
> install PDF::API2

実際に右綴じ&見開きを設定するのは以下のスクリプト (r2l.pl) を実行します。 例によって INPUT.pdf が加工前のファイル名で、 OUTPUT.pdf が加工後のファイル名です。 スクリプト中では固定値にしているので、適宜修正しましょう。

use PDF::API2;

$pdf = PDF::API2->open("INPUT.pdf");

$pdf->{'catalog'}->{'PageMode'} = PDF::API2::PDFName('UseOutlines');

$pdf->{'catalog'}->{'PageLayout'} = PDF::API2::PDFName('TwoPageRight');

$pref = $pdf->{'catalog'}->{'ViewerPreferences'} ||= PDF::API2::PDFDict();
$pref->realise();
$pref->{'Direction'} = PDF::API2::PDFName('R2L');

$pdf->{'pdf'}->out_obj($pdf->{'catalog'});
$pdf->saveas("OUTPUT.pdf");

ざっくり解説しますと、まず以下の行で栞をデフォルトで表示するようにしています。

$pdf->{'catalog'}->{'PageMode'} = PDF::API2::PDFName('UseOutlines');

次にこのブロックで、右綴じを設定してます。

$pref = $pdf->{'catalog'}->{'ViewerPreferences'} ||= PDF::API2::PDFDict();
$pref->realise();
$pref->{'Direction'} = PDF::API2::PDFName('R2L');

これは本来ならば $pdf->preferences() メソッドでやれば良いことなのですが、 これを使うと設定して欲しくないモノも設定されてしまうので、 しかたなくその実装から必要な部分だけをコピーして使っています。

ここまでで右綴じ設定はできているのですが、 表紙も含めてスキャンしていた場合には表紙が1ページになってしまい、 見開きのページがズレてしまいます。 なので表紙だけは見開きにせず、 2ページ目以降を見開きで表示するための設定が次のコードです。

$pdf->{'catalog'}->{'PageLayout'} = PDF::API2::PDFName('TwoPageRight');

ちなみにですが左綴じで同じことをしたい場合には、 コレを TwoPageLeft にすれば良いようです。

留意事項

PDF::API2 は相当に万能なので栞の埋め込みにも使えます。 しかし今回それをしていないのは、 栞の為に Perl のコードを書くのはダルいと判断したからです。 PDFtk のメタデータフォーマットは DSL の一種として成立しており、 栞のデータを入力するには適していると判断しました。 もちろん Perl で DSL を定義&解釈して、 PDF::API2 で埋め込むというのもありでしょう。 が、現時点においては DSL の実装が面倒なので PDFtk に甘えています。