カビパン男と私

HOME/横書き縦書き

PDFファイルをトリミング(原始人風味)

こんな PDF ファイルがあった。「なんで三段組みにするだよ」という気持ちだ。

こんな形で切り出したい。

これを A,B,C それぞれに対してやり、それぞれのページをバラバラにしてから順番を整えて拡大し、うまいサイズの PDF にするのだ。そうすれば、一段組みの見やすい PDF になる。PDF をバラバラにしたり、順番を整えたり、拡大したりするのは難しくない。すぐに方法が見当らなかったのが、最初のトリミングだ。

検索してみるといちばん引っかかってくるのが pdfcrop というコマンドである。使ってみてわかったことは、これは基本的には

こんな感じで、ページに配置されたオブジェクトを最小の長方形(点線部分)で切り出すためのツールだってことだ。

たしかにオプションで上下左右のマージンを設定できるけれども、その意味するところは、

ということである。これは、今私がやりたいことではない。

ページ中に配置されているオブジェクトと関係なしに、ページの端からの長さを指定して切り抜きたいのである。

さて、PDF の仕様は私たちがざっくりページサイズと思っているものに関連した、5 種類の「ボックス」を定義している。しかし、どんな PDF ファイルにも必ず存在し、しょぼいユーザー・エージェントも読んで使うものは \MediaBox だろう(5 種類のボックスの一番外側にあるものである)。これは、PDF ファイルの各ページに一つあり、普通の ASCII テキストで書かれている。たとえば、

/MediaBox[0 0 842 595]

は、ページ左下端x座標、左下端y座標 右上端x座標 右上端y座標を表している。単位はポイントである(少なくともデフォルトでは)。

MediaBox の値を決めると、①出力される書類の各ページの大きさがそれに決まり、②その外に配置されているオブジェクトは印刷されない。(②のほうは本来 CropBox の役目だが、CropBox のデフォルトは MediaBox だし、私の使っているユーザー・エージェントでは、CropBox と MediaBox を別々に指定しても無益である。)

つまり、マージンとして周囲に白い余白とかつけないでいいから、とにかく PDF をトリミングして印刷したいというなら、ここのところを

/MediaBox[0 0 281 595]

とすればよさそうだ。

PDF にはバイナリでデータを保持している部分があるから、エディタで開くと化け化けになるところはあるけれども、ASCII 部分だけなら普通に編集できる。値を変更するだけなら可能だ。

だが、注意しなくてはいけない。PDF のユーザー・エージェントは、PDF ファイル中でオブジェクトの記述を見つけるのに、ファイル中にある先頭からのバイト数を使うのである。少し具体的にいうと、ユーザー・エージェントは「○○番のオブジェクトは先頭から××バイト進んだところから開始する」というテーブルを参照して仕事を進めるのだ。

ということは、たとえば /MediaBox で指定されている 281 という数を 90 にしてしまうと、それ以後のオブジェクト開始位置が 1 バイトずつ前にズレてしまい、大変都合が悪いのである。

この点に気をつければ、vi エディタひとつで PDF のトリミングができるはず(たぶん)。

そして、多数の PDF ファイルを処理するなど、エディタで開くのが面倒な場合は、sed の出番となる。ただし、この場合はまた別の不安がある。PDF の PDF としての構造を無視した文字の置換をすることになるからだ。もしかすると、/MediaBox という文字列が、われわれの期待している意味以外に使われているかもしれない。

そこで、/MediaBox という文字列の登場回数を数え、ページ数を比較して同じであることを確かめることにした。PDF は総ページ数を数が書き込んである場所があり、比較的簡単にそれを見つけることができる(trailer 中の /Root が指す /Catalog からたどって /Pages を探すと、その中に /Count という項目があり、ここにページ数が保存されている)。とはいっても、そこそこ面倒くさいから、

$ pdfinfo a.pdf | grep Pages
Pages:          11

で済ませることにする。あとは、/MediaBox の登場回数を調べる。

$ grep -c /MediaBox a.pdf
11

どちらも 11 で一致するから、予想外の /MediaBox という文字列は存在しないようだ。

あとは sed を使って

sed -e "s/\/MediaBox\[0 0 842 595\]/\/MediaBox[0 0 281 595]/" in.pdf > out.pdf

みたいにやれば、めでたしである。

(PDF のことよく知らんから、いかんことしてるかもしれないけどね)

@kabipanotoko