昨天有一个突发的需求,要求尽快的把一个一百多页的pdf按照页码每页转换成一个jpg文件后打包传回。正好最近一直在学习Python就打算写一个这样的脚本(结果发现踩了坑)
【pypi - Wand】【Wand官网】【Github - Wand】pip install wand
在百度上找解决方案的时候,第一条用的就是wand. 后来去stackoverflow上看也有用wand来操作的,看起来也挺简单,代码如下:
from wand.image import Image
filename="somefile.pdf"
with(Image(filename=filename, resolution=120)) as source:
images = source.sequence
pages = len(images)
for i in range(pages):
n = i + 1
newfilename = filename[:-4] + str(n) + '.jpeg'
Image(images[i]).save(filename=newfilename)
上述代码把somefile.pdf转换成一张张图片,并分为存为somefile1.jpeg这样的图片。
但问题是,我在windows下运行的时候出现了这样的错误:
Traceback (most recent call last):
File "test.py", line 1, in
from wand.image import Image
File "C:\Program Files\Python\lib\site-packages\wand\image.py", line 18, in
from . import compat
File "C:\Program Files\Python\lib\site-packages\wand\compat.py", line 25, in
abc = collections.abc if PY3 else collections
File "C:\Program Files\Python\lib\collections\__init__.py", line 55, in __getattr__
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
AttributeError: module 'collections' has no attribute 'abc'
翻看wand官网可以看到,wand和其他大部分类似库一样,都是包装接口(bindings),而实际进行转换的工具是ImageMagick. 【ImageMagick官网】【Github - ImageMagick】
在我写这篇文章的时候,我只打开过ImageMagick官网一次,剩下大部分时候都会超时。除了在ImageMagick官网上下载windows版本,Wand官网说在这里也能下载到windows版的ImageMagick。但实际上这个网站还是超时。
从ImageMagick仓库来看,官方在releases里没有提供windows版的build。但是从其CI日志看其实是在win平台上也测试并打包了。ImageMagick倒是支持在windows下编译,不过看了一下说明文档之后发现不仅不支持cmake,还需要先build一个configure程序然后再用configure生成sln编译库本体。
在Linux下,安装wand的时候会提示需要安装libmagickwand-dev。
如果脚本启动的时候报这样的错:wand.exceptions.PolicyError: not authorized somefile.pdf
,这不是wand的锅,这是ImageMagick默认配置的锅。解决方案是sudo vim /etc/ImageMagick-6/policy.xml
然后找到
这一行,将right="none"
修改为right="all"
即可。
【pypi - pdf2image 】【Github - pdf2image】pip install pdf2image
pdf2image也是个包装器,真正的转换工具是poppler。从这里下载poppler-utils的windows版. 右键另存为或者迅雷下载可能会出现一些问题,这里我只能用curl下载了(windows版本的curl去libcurl官网上就能下载到,虽然我是自己编译的)curl -O http://blog.alivate.com.au/wp-content/uploads/2018/10/poppler-0.68.0_x86.7z
解压之后把bin
目录加载到PATH
环境变量里(或者直接把bin目录下的文件都拖到当前文件夹里,用完再删了)
pdf2image用法如下:
from pdf2image import convert_from_path
convert_from_path('a.pdf', 500, "output",fmt="JPEG",output_file="ok",thread_count=4)
这会将a.pdf转换成在output文件夹下形如ok_线程id-页码.jpg
的一些文件。若不指定thread_count则默认为1,并且在文件名中显示id. 这种转换是直接写入到磁盘上的,因此不会占用太多内存。
还有一种写法是:
from pdf2image import convert_from_path
pages = convert_from_path('pdf_file', 500)
for page in pages:
page.save('out.jpg', 'JPEG')
但这种写法会占用大量内存,因为convert_from_path
的默认格式是ppm,其次若不指定输出则默认是写入到内存中的。
在Linux下使用sudo apt install poppler-utils
来安装poppler,可能还需要安装pillow,使用pip install pillow
安装即可。
除了使用现成的package,也可以通过“野路子”。比如选好一个工具,拼凑cmd命令,然后通过subprocess模块启动子进程进行转换,也是可以的。
目前除了wand和pdf2image还没发现比较好的包,以后如果发现更好的工具可能会更新。
最后推荐一个在线pdf转图片的网站:【PDF to JPG online converter - Convert PDF to JPG for FREE】如果pdf内容不要紧的话可以试试这个在线转换器,完全免费,对于多页结果还提供在线打包下载服务。