用ImageMagick处理pdf

需求和方案

最近想学习TCP/IP协议,综合考虑,阅读TCP/IP Illustrated第一版是最好的选择,而且还得读英文原版。我有个电子书阅读器DPT-RP1,找个pdf文件就可以开读了。

但网络上最流行的那个英文版pdf文件,排版质量不好,插图基本看不清,遂放弃。终于找到一个还不错的版本,制作者给实体书的每页拍照,然后将图片拼成pdf。这个pdf文件在电脑上阅读效果还不错,但图片的阴影在DPT-RP1里显示出来灰扑扑一片,阅读效果不好。

于是我考虑把pdf里的每张图片二值化,只有黑白两种颜色,放到阅读器里,效果应该会不错。我相信,Adobe Acrobat DC或者Photoshop之类的软件一定能够方便快捷地完成这个任务,但我买不起这些商业软件,安装破解版也很耗费时间和精力。于是搜寻免费的解决方案,果然,神通广大的ImageMagick就能完成这项任务,ImageMagick在Linux下的调用命令是convert

拆分pdf文件

首先将pdf文件拆成一张张图片:

1
convert -density 300 tcpip.pdf %04d.jpg

其中-density指定PPI值,该值越大,图片越清晰,得到的文件尺寸以及处理时间也会增加。%04d.jpg表示生成的图片文件名用四位数字编号,例如,第123张图片的文件名为0123.jpg

我的机器配置不高,Intel Core i5-4430四核处理器,8G内存。拆分文件相当消耗资源,拆分608页的pdf文件,用完了全部物理内存,耗时大约50分钟。

二值化图片

拆分得到的是彩色图片,要选择阈值将图片二值化,得到只有黑白两色的图片。二值化单张图片的命令如下:

1
convert 0020.jpg -threshold 55% 0020.png

经过尝试,阈值选择在140(255*55%)附近时,分割效果较好。灰度值大于该阈值的像素全部变为255(白色),灰度值低于该阈值的像素全部变为0(黑色)。

将目录下所有jpg格式的图片二值化,转换后的图片是png格式,文件名后缀由.jpg变为.png,采用下面的脚本实现:

1
2
3
4
5
6
#!/bin/bash

find ./images -name *.jpg | while read fname
do
convert $fname -threshold 55% ${fname%.jpg}.png
done

该项操作耗时不长,在我的机器上,处理608张图片仅花了几分钟。

拼接成pdf文件

最后将png格式的黑白图片拼接成pdf文件,一般的拼接命令如下:

1
convert image1.png image2.png image3.png output.pdf

但图片数量较多,为了确保按照文件名的排列顺序拼接,使用如下命令:

1
ls *.png | sort -n | tr '\n' ' ' | sed 's/$/\ TCP-IP_Illustrated.pdf/' | xargs convert

该项操作耗时约30分钟。

总结

最后得到的文件类似于高质量的扫描版pdf,阅读效果非常完美,应该是全网最佳版本了。从查找解决方案到制作完成,几乎花费了我整个下午的时间,看来还是商业软件来得方便快捷啊!