我打算预习一下下学期的物理,物理老师扔过来一个 djvu 格式的电子书。 djvu 格式是我比较讨厌的一个格式,虽然它相比 pdf 来说,文件大小会小得多,但是毕竟阅读不方便,软件支持并不是很好。如果说,问题只是 djvu 那就算了,毕竟 iPad 上还是有应用可以打开的,最不能忍受的是,这本电子书左右合起来有 1/3 的空白,上下合起来有 1/2 的空白,在阅读器上阅读的体验极差。于是我就打算将其切边,并转换成 pdf 。

解决方法

似乎没有什么现成的工具可以切 djvu ,所以只好手动来了。首先,我们需要 djvulibre 这个工具来把 djvu 解开成单张图片,然后利用 ImageMagick 切边并转为 jpg 。转为 jpg 的原因是,因为原来的电子书质量够好,像素足够多,感觉转成 jpg 并不影响效果。

# djvulibre 可以直接从 brew 安装
brew install djvulibre

# 把第10页按照 ppm 格式导出
ddjvu --page=10 --format=ppm book.djvu 10.ppm

# 把 10.ppm 从 (335,135) 开始截截下 3410x4395 并保存为 jpg 格式
convert -crop 3410x4395+335+135 10.ppm 10.jpg

把所有的 jpg 都处理好后,就可以把所有的 jpg 合成一个 pdf 了。本来以为要先把每个 jpg 转成 pdf ,然后再合并 pdf ,绕了一大圈,后来才发现 ImageMagick 也可以做这个事情。合起来,我们就可以写一个 bash 脚本来处理这个事情。

###### make.sh:
#!/bin/bash

printf "Generating ${1} (Page ${2} ~ ${3}) ... "
for i in `seq $2 $3`
do
    ddjvu --page=$i --format=ppm book.djvu "/Volumes/Temp/${i}.ppm"
    convert -crop 3410x4395+335+135 "/Volumes/Temp/${i}.ppm" "/Volumes/Temp/${i}.jpg"
    rm "/Volumes/Temp/${i}.ppm"
    printf "%d " $i
done

convert `seq -f "/Volumes/Temp/%g.jpg" $2 $3` ${1}.pdf
rm /Volumes/Temp/*.jpg
printf "\n"

以上是生成特定一章的脚本。我们再手动把每一章的第一页页码从书的目录找出来,用 vim 稍微处理下就可以得到下面这个生成每个章节的脚本。

###### generate.sh:
#!/bin/bash
./make.sh 1 2 20
./make.sh 2 21 37
./make.sh 3 38 70
./make.sh 4 71 102
./make.sh 5 103 131
./make.sh 6 132 158
./make.sh 7 159 182
# (......)

改进

感觉似乎转换的效率并不是很给力,突然想起来有个 GNU Parallel 可以用来做并行操作,立马对程序做了些修改( OS X 下可以直接 brew install parallel 安装 GNU Parallel)

###### task.sh 用来对每页书做导出、切边、转换格式的任务:
#!/bin/bash

ddjvu --page=$1 --format=ppm book.djvu "/Volumes/Temp/${1}.ppm"
convert -crop 3410x4395+335+135 "/Volumes/Temp/${1}.ppm" "/Volumes/Temp/${1}.png"
rm "/Volumes/Temp/${1}.ppm"

###### generate.sh:
#!/bin/bash
task() {
    printf "Generating ${1} (Page ${2} ~ ${3}) ... "
    seq -f "./task.sh %g" $2 $3 | parallel -j8
    convert `seq -f "/Volumes/Temp/%g.jpg" $2 $3` ${1}.pdf
    rm /Volumes/Temp/*.jpg
    printf "Done\n"
}

task 1 2 20
task 2 21 37
task 3 38 70
task 4 71 102
task 5 103 131
task 6 132 158
# (......)

对于效率的提升还是比较明显的,我用 /usr/bin/time 做了下测试,同样是生成 2 到 20 页,原来需要用 40.17s 改用 parallel 之后只需要 25.20s ,速度提升了 37.2%

令人惊讶的是

  • 每一页 ppm 竟然需要 100MB
  • 转换后的 jpg 竟然需要 2MB
  • 每一章 pdf (大约30页左右) 竟然需要 65MB
  • 也就是说,整本书 1300 多页,大致需要 2.6GB
  • 然而原始的 djvu 只有 69.8MB

大概这就是 djvu 仍然经常被使用的原因吧。