本をスキャンした画像を djvu にする(自炊)

tiff や pdf にまとめられた本をスキャンしたファイルを少し編集して djvu ファイルにする手順をまとめておく。 モノクロか少数のカラーが対象でフルカラーの本はまだスキャンしていないのでここに変換の手順はない。 Ubuntu 12.10 の zsh で行う。

手順

  1. tiff や pdf の1ページを1つの画像にする
  2. トリミングと回転
  3. ページの境目の線を消すために画像を合成
  4. 分割して1ファイルにつき1ページにする
  5. 減色
  6. djvu に変換

ページを開いてスキャンした本を対象にしているので、裁断してスキャンした場合は3が不要になったりする。

デュアルコアのマシンを使っているので xargs コマンドには -P2 を指定しているが4コアなら -P4 とするなど 各自の環境に合わせる。

0. 準備

使うアプリケーションとスクリプトは http://transitive.info/2012/12/25/jisui-ubuntu-01-applications/ に書いてあるので用意しておく。

以下では zsh を使っている(bash にない zsh の機能を使っているので注意)。 work というディレクトリを作ってそこで作業する。 端末を起動して

mkdir work
cd work

とする。zsh でないなら

zsh

としておく。

1. tiff や pdf の1ページを1つの画像にする

ソースとなるスキャンしてできたファイルは work ディレクトリに保存しておく。 このファイルから分割したファイルは split ディレクトリに保存することにする。まず、

mkdir split

で split ディレクトリを作っておく。

pdf (001.pdf、002.pdf のようにいくつかの pdf にわかれていても問題ない) なら

for f in *.pdf; pdfimages $f split/$f:r

とする。tiff ならば

for f in *.tif; tiffsplit $f split/$f:r

のようにする。もし、うまくいかない tiff ならば irfanview で分割して split ディレクトリに保存する (Ubuntu でスキャン画像の編集(自炊) を参照)。

これ以降は split ディレクトリの中のファイルを処理するので移動する。

cd split

奇数番目と偶数番目で別々の処理をしたい場合は

ext=tif; mkdir odd even; ruby ~/scripts/pick-out-arguments.rb *.$ext | xargs mv -t odd; mv *.$ext even

などとして、odd ディレクトリと even ディレクトリに別々の処理を行う。

ソースのファイルは old に送っておく。

mkdir old
mv input.tif old

2. トリミングと回転

Gimp でファイルを開き、矩形選択を使ってトリミングする座標を調べる。 画像は tif 画像を対象にするが、異なる場合は from= のところに異なる拡張子を指定すれば良い。 トリミングの座標を convert の crop オプションで指定する。 ここでは 3000x2000+100+200 と指定しているが、これは左上の点 (100, 200) から 3000x2000 の画像を切り取ることを意味する。

from=tif; to=bmp; ls *.$from | sed -e "s/.$from$//" | xargs --replace -n1 -P2 convert -crop 3000x2000+100+200 {}.$from {}.$to

ページの上下左右が画像と合っていない場合は、ここで回転させるために rotate オプションも指定する。

from=tif; to=bmp; ls *.$from | sed -e "s/.$from$//" | xargs --replace -n1 -P2 convert -crop 3000x2000+100+200 -rotate -90 {}.$from {}.$to

トリミングした画像は bmp にした。tif ファイルはもう使わないので old ディレクトリに入れておく。

mv *.tif old

3. ページの境目の線を消すために画像を合成

見開きのときにできる中央部の線と画像の縁のノイズを除去するために、 白色の8の字を横にしたような画像を合成する。 画像は1で切り取った画像と同じサイズで背景は透明にして png 形式にする。Gimp で作成すればよい。 ここでは、作成した画像は img.png とする。

from=bmp; to=png; ls *.$from | sed -e "s/.$from$//" | xargs --replace -n1 -P2 composite img.png {}.$from {}.$to

で合成して png 画像にする。bmp ファイルも使わないので old に入れる。

mv *.bmp old

4. 分割して1ファイルにつき1ページにする

見開きのページを分割する。crop で画像の横幅の半分を指定する。crop オプションは基点を指定しないと分割になる。

from=png; to=bmp; ls *.$from | sed -e "s/.$from$//" | xargs --replace -n1 -P2 convert -crop 1500x2000 {}.$from {}.$to

bmp ファイルができる。png は old に移す。

mv *.png old

5. 減色 & DjVu に変換

モノクロ2値のときは pbm にして cjb2 で djvu にする。

from=bmp; to=pbm; ls *.$from | sed -e "s/.$from$//" | xargs --replace -n1 -P2 convert {}.$from {}.$to
from=pbm; to=djvu; ls *.$from | sed -e "s/.$from$//" | xargs --replace -n1 -P2 cjb2 {}.$from {}.$to

少数のカラーの画像なら convert_to_djvu_few_colors.rb で減色する(実際には convert で何回かにわけて減色して ppm にし、cpaldjvu で djvu に変換する)。

ls *.bmp | xargs -n1 -P2 ruby ~/scripts/convert_to_djvu_few_colors.rb

convert_to_djvu_few_colors.rb の処理やオプションについてはソースコードを参照してください。

[追記 2016-12-11] 上の方法はページ毎にカラーマップが異なる。 カラーマップを共通にするには次のような手順で変換する。

まず、カラーマップ作成のために減色する。 page1.ppm と page2.ppm の2ページで必要な色が含まれているとすると

convert -append page1.ppm page2.ppm sample.png
convert sample.png +dither -colors 8 -filter box -normalize color_quantization.png

のようにする。このときに box filter を使うときれいに減色できる。

convert color_quantization.png -format %c -colorspace RGB histogram:info:-

で色を確認する。完全な白がなければ

convert -fill "#ffffff" -opaque "#ffffff" -fuzz 5% color_quantization.png color_quantization2.png

のようにして白で塗りつぶす。

減色したファイルから

convert color_quantization.png -unique-colors -scale 100% color_map.png

でカラーマップのファイルを作る。

convert +dither -filter box -remap color_map.png other_input.ppm out.png

として他のファイルを減色することができる。場合によっては、余計なことはしないで

convert -remap color_map.png other_input.ppm out.png

とした方がよいかもしれない。

6. 1つの djvu にまとめる

最後に djvu ファイルを

djvm -c out.djvu *.djvu

でまとめる。

Tags of current page

, , ,