最近做调研想知道一些NZ当地的旅游信息,于是在NZ留学的友人自高奋勇地帮我去各个加油站拿了一堆旅游小册子,扫描了发给我。
但是他扫描出的高清图全在一个pdf里,顺序也不对,于是我准备把pdf文件中的图单个取出转成jpg方便查看。
使用免费的Adobe Reader X虽然可以一张一张的把图拷贝下来,转存进mspaint,但是枯燥的过程不能满足我熊熊燃烧的程序员之魂。
由于空闲时间不多,先在网上搜到一堆胡里花哨的小软件,不是看介绍就觉得文不对题就是免费版的软件内部限定只能转第一张…
于是决定用python写个脚本跑批把图取出来,先选择了PdfMiner。
PdfMiner的demo:
#!/usr/bin/env python2 #-*-encoding:utf-8-*- from pdfminer.pdfparser import PDFParser from pdfminer.pdfdocument import PDFDocument from pdfminer.pdfpage import PDFPage from pdfminer.pdfpage import PDFTextExtractionNotAllowed from pdfminer.pdfinterp import PDFResourceManager from pdfminer.pdfinterp import PDFPageInterpreter from pdfminer.pdfdevice import PDFDevice from pdfminer.layout import * from pdfminer.converter import PDFPageAggregator import urllib2 from cStringIO import StringIO def Pdf2Txt(DataIO,Save_path): #来创建一个pdf文档分析器 parser = PDFParser(DataIO) #创建一个PDF文档对象存储文档结构 document = PDFDocument(parser) if not document.is_extractable: raise PDFTextExtractionNotAllowed else: #创建一个PDF资源管理器对象来存储共赏资源 rsrcmgr=PDFResourceManager(); #设定参数进行分析 laparams=LAParams(); #创建一个PDF设备对象 #device=PDFDevice(rsrcmgr) device=PDFPageAggregator(rsrcmgr,laparams=laparams);#创建一个PDF解释器对象 interpreter=PDFPageInterpreter(rsrcmgr,device) #处理每一页 for page in PDFPage.create_pages(document): interpreter.process_page(page); #接受该页面的LTPage对象 layout=device.get_result() for x in layout: try: if(isinstance(x,LTTextBoxHorizontal)): with open('%s'%(Save_path),'a') as f: f.write(x.get_text().encode('utf-8')+' ') except: print "Failed!" #convert online pdf ''' url = "pdf url"; html = urllib2.urlopen(urllib2.Request(url)).read(); DataIO = StringIO(html.read()); Pdf2Txt(DataIO,r'C:workspacepythonconverter esource2.txt'); ''' #convert local pdf with open(r'C:workspacepythonconverter esource ext.pdf','rb') as html: DataIO = StringIO(html.read()) Pdf2Txt(DataIO,r'C:workspacepythonconverter esource3.txt')
试用后发现PdfMiner更适合配合StringIO转出pdf文件中的文字类信息。这和我的需求不符,果断更换。
接着找到了PythonMagick,通过写demo发现能够顺利转出我需要的图,但是PythonMagick并没有方法可以获取pdf文件的页数,于是又找到了PyPdf2,PyPdf2的PdfFileReader中getNumPages()方法可以读取pdf文件页数。
PythonMagick的demo:
import PythonMagick; from PyPDF2 import PdfFileReader; C_RESOURCE_FILE=r'C:workspacepythonconverter esource'; C_PDFNAME=r'6p.pdf'; C_JPGNAME=r'6p%s.jpg'; input_stream = file(C_RESOURCE_FILE+'\'+C_PDFNAME, 'rb'); pdf_input = PdfFileReader(input_stream,strict=False); #错误1 page_count = pdf_input.getNumPages(); img = PythonMagick.Image() # empty object first img.density('300'); # set the density for reading (DPI); must be as a string for i in range(page_count): try: img.read(C_RESOURCE_FILE+'\'+C_PDFNAME + ('[%s]'%i)); #分页读取 PDF imgCustRes = PythonMagick.Image(img); # make a copy imgCustRes.sample('x1600'); imgCustRes.write(C_RESOURCE_FILE+'\'+(C_JPGNAME%i)); except Exception, e: print e; pass; print 'done';
运行时,碰到错误1:
PyPDF2.utils.PdfReadError: Multiple definitions in dictionary at byte 0x4717c2 f or key /Info
通过查询,将严格模式关闭,PdfFileReader(input_stream,strict=False)可以解决。
文中所用到的包如下:
PythonMagick可以通过lfd.edu提供的镜像下载whl文件,比如我用的python2.7,64位windows,下载对应的是PythonMagick‑0.9.10‑cp27‑none‑win_amd64.whl。
安装方法,cmd进入whl文件所在目录,运行:
pip install PythonMagick‑0.9.10‑cp27‑none‑win_amd64.whl
PyPdf2可以使用pip直接安装。
pip install PyPdf2
PdfMiner可以在github里搜一下,关键字排名第一有2k star那个的就是。
在搜索过程中,还发现另外一种方法,使用ImageMagick与命令行进行转换,需要安装ImageMagick,GhostScript,参照此文。
cmd进入pdf所在目录,运行:
magick convert 6p.pdf 6p.jpg
此方法能够将pdf自动按页转为jpg。
Reference:
Python使用PDFMiner解析PDF
PdfReadError: Multiple definitions in dictionary at byte 0x30b for key /Type #244
Convert PDF to IMAGE with perl/pythjon
Unofficial Windows Binaries for Python Extension Packages - PythonMagick
PDF to JPG Conversion with Python (for Windows)