いままでに自炊したPDFは、ひと通り「自炊PDFを第3世代iPadに最適化する その3」の方法で変換してiPadに入れてるんですが、こないだ、なぜか間違って右綴じになってるファイルを見つけてしまいました。オリジナルのPDFは左綴じなのに、iPad版だけ右綴じになってる。なんで!? あ、そういえば、数日前にこの本をPDF化したとき、間違ってAcrobatで右綴じ設定にしてしまい、あとで気づいてもう一回左綴じに直したのを思い出しました。なんかこのへんが関係してるのかも。

iPad版を作るとき、処理を自動化するために、オリジナルを ‘ViewerPreferences«/Direction/R2L»’ でgrepしてみて、ヒットしたら右綴じと判定するようにしています。問題の本は、もしかしてオリジナルにこの設定が残っちゃってるのかな? と思ってgrepしてみると、案の定ヒットしました。うー、Acrobatで左綴じにしたら消えると思ってたのにー。

原因調査のため、Acrobatで綴じ方向を変えて保存すると、ファイルの中身がどう変わるか見てみます。

まず、ScanSnapで作ったPDFには、’ViewerPreferences’ という文字列は含まれていません。

次に、それをAcrobatで開いて「ファイル」→「プロパティ」→「詳細設定」の「読み上げオプション」の「綴じ方」を「右」に変えて保存すると、

<</Metadata 8 0 R/Pages 2 0 R/Type/Catalog/ViewerPreferences<</Direction/R2L>>>>

という行が書き込まれていることが確認できます(ほかにもいろいろ変わってるうちの一部です)。

同じファイルをふたたびAcrobatで開いて、「綴じ方」を「左」に戻して保存するとこの行は消えるかと思いきや、

<</Metadata 8 0 R/Pages 2 0 R/Type/Catalog/ViewerPreferences<</Direction/R2L>>>>

はそのまま残っていて、その下に

<</Metadata 8 0 R/Pages 2 0 R/Type/Catalog/ViewerPreferences<<>>>>

という行が増えています。つまり、ファイルを変更すると、変更箇所がどんどん下に追加されていくみたいです。

AdobeのPDF Technology Centerで公開されているPDF 1.7の仕様書をチラ見してみたら、「3.4.5 Incremental Updates」にバッチリそのことが書かれてました。PDF仕様では、積極的に「差分追加更新方式」を取り入れてるみたいです。曰く、差分更新だと大きいファイルでも変更点だけ素早く保存できる、一旦テンポラリに書きだしてリネームみたいなことができない場合でも対応可能、内容に署名している場合はそもそも差分更新しかできない、などなど。

というわけで、この差分更新のことを考えるとgrepだけで綴じ方向を判定するのは無理っぽいので、JavaのiTextで真面目にオブジェクトのツリーをたどって処理することにしました。とり急ぎ作った判定プログラムはこんな感じ。引数で渡したファイルが右綴じだったら0、そうでなければ1のリターンコードをJavaプロセスが返すようにしています。

import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfReader;

public class DirectionChecker {
    public static void main(String[] args) throws Exception {
        PdfReader reader = new PdfReader(args[0]);
        try {
            PdfDictionary trailer = reader.getTrailer();
            PdfDictionary root = trailer.getAsDict(PdfName.ROOT);
            PdfDictionary vpref = root.getAsDict(PdfName.VIEWERPREFERENCES);
            if (vpref == null) {
                System.exit(1);
            }
            PdfName dir = vpref.getAsName(PdfName.DIRECTION);
            if (dir == null || !dir.equals(PdfName.R2L)) {
                System.exit(1);
            }
        } finally {
            reader.close();
        }
    }
}

で、シェルスクリプトでgrepしていた箇所をこのプログラムに置き換えることで、とりあえず誤判定はなくなりました。

if java -classpath .:itextpdf-5.3.0.jar DirectionChecker オリジナル.pdf; then
  java -classpath .:itextpdf-5.3.0.jar R2Ler 変換後.pdf
fi

ただし、こうなってくると、オリジナルのファイルの「開き方設定」(見開きで全体表示、とか)もついでにiPad版に踏襲させるとか、そもそもiPad最適化処理を全部Javaで処理するとか、いろいろ別のこともできるような気がしてきました。

あと、PDFの構造とか文法がよくわからんので入門書とかiTextの解説本とか買おうかなと思ってたんですが、AdobeのPDF仕様書みれば基本は全部書いてあるので、まずはこれ読めばタダだなと……。

※バージョンメモ

  • Adobe Acrobat 9 Standard 9.5.1
  • FreeBSD 9.0-RELEASE
  • iText 5.3.0