学习
实践
活动
工具
TVP
写文章
专栏首页萌海无涯Python将PDF转成图片—PyMuPDF和pdf2image

Python将PDF转成图片—PyMuPDF和pdf2image

前言:在最近的测试中遇到一个与PDF相关的测试需求,其中有一个过程是将PDF转换成图片,然后对图片进行测试。

粗略的试了好几种方式,其中语言尝试了Python和Java,总体而言所找到的Python方式相对比Java更快一些,更简单一些。

下面首先分享一下Python将PDF转换成图片,Java后续有时间在进行分享。

需求:我需要先将PDF转换成为PNG图片,并截取图片的一部分存储,然后作为测试目标进行测试。

操作:

1、PDF转PNG图片

2、对PNG图片进行指定区域截图,在另存到指定文件夹下

针对截图此处所找到的方法如上一篇博客: Python图片裁剪的两种方式——Pillow和OpenCV

1、PyMuPDF将PDF转换成图片

import sys, fitz
import os
import datetime
 
def pyMuPDF_fitz(pdfPath, imagePath):
    startTime_pdf2img = datetime.datetime.now()#开始时间
    
    print("imagePath="+imagePath)
    pdfDoc = fitz.open(pdfPath)
    for pg in range(pdfDoc.pageCount):
        page = pdfDoc[pg]
        rotate = int(0)
        # 每个尺寸的缩放系数为1.3,这将为我们生成分辨率提高2.6的图像。
        # 此处若是不做设置,默认图片大小为:792X612, dpi=96
        zoom_x = 1.33333333 #(1.33333333-->1056x816)   (2-->1584x1224)
        zoom_y = 1.33333333
        mat = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate)
        pix = page.getPixmap(matrix=mat, alpha=False)
        
        if not os.path.exists(imagePath):#判断存放图片的文件夹是否存在
            os.makedirs(imagePath) # 若图片文件夹不存在就创建
        
        pix.writePNG(imagePath+'/'+'images_%s.png' % pg)#将图片写入指定的文件夹内
        
    endTime_pdf2img = datetime.datetime.now()#结束时间
    print('pdf2img时间=',(endTime_pdf2img - startTime_pdf2img).seconds)
 
 
if __name__ == "__main__":
    pdfPath = '../path/demo.pdf'
    imagePath = '../path/image'
    pyMuPDF_fitz(pdfPath, imagePath)

PDF文档页数超过100页的话需要十几秒,因为先转换成一整张1056X816的图片,再对本地文件中的所有图片进行遍历截图,时间上比较慢,通过查看文档发现:

还可以在转换的同时指定图片的大小,对图片指定区域进行截取,这样快很多,一步到位,省去了二次截图的过程,前提是我们必须要知道想要截取哪一块区域并保存。

官方示例代码如下:

#下面的这段代码就是想要从一页PDF的中心点为起点截取到右下角的区域,截取整张图的1/4.
>>> mat = fitz.Matrix(2, 2)                  # 在每个方向缩放因子2
>>> rect = page.rect                         # 页面的矩形
>>> mp = rect.tl + (rect.br - rect.tl) * 0.5 # 矩形的中心
>>> clip = fitz.Rect(mp, rect.br)            # 我们想要的剪切区域
>>> pix = page.getPixmap(matrix = mat, clip = clip)

实际用到的例子是:

整张图片导出之后是1056*816,但是我想要的是这张图片最底部的部分1056*75,相当于PDF文档的页脚部分。

import sys, fitz
import os
import datetime
 
def pyMuPDF_fitz(pdfPath, imagePath):
    startTime_pdf2img = datetime.datetime.now()#开始时间
    
    pdfDoc = fitz.open(pdfPath)
    for pg in range(pdfDoc.pageCount):
        page = pdfDoc[pg]
        rotate = int(0)
        # 每个尺寸的缩放系数为1.3,这将为我们生成分辨率提高2.6的图像。
        # 此处若是不做设置,默认图片大小为:792X612, dpi=96
        zoom_x = 1.33333333 #(1.33333333-->1056x816)   (2-->1584x1224)
        zoom_y = 1.33333333
        mat = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate)
        pix = page.getPixmap(matrix=mat, alpha=False)
        
        if not os.path.exists(imagePath):#判断存放图片的文件夹是否存在
            os.makedirs(imagePath) # 若图片文件夹不存在就创建
        
        pix.writePNG(imagePath+'/'+'images_%s.png' % pg)#将图片写入指定的文件夹内
        
    endTime_pdf2img = datetime.datetime.now()#结束时间
    print('pdf2img时间=',(endTime_pdf2img - startTime_pdf2img).seconds)
 
def pyMuPDF2_fitz(pdfPath, imagePath):
    pdfDoc = fitz.open(pdfPath) # open document
    for pg in range(pdfDoc.pageCount): # iterate through the pages
        page = pdfDoc[pg]
        rotate = int(0)
        # 每个尺寸的缩放系数为1.3,这将为我们生成分辨率提高2.6的图像
        # 此处若是不做设置,默认图片大小为:792X612, dpi=96
        zoom_x = 1.33333333 #(1.33333333-->1056x816)   (2-->1584x1224)
        zoom_y = 1.33333333
        mat = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate) # 缩放系数1.3在每个维度  .preRotate(rotate)是执行一个旋转
        rect = page.rect                         # 页面大小
        mp = rect.tl + (rect.bl - (0,75/zoom_x)) # 矩形区域    56=75/1.3333
        clip = fitz.Rect(mp, rect.br)            # 想要截取的区域
        pix = page.getPixmap(matrix=mat, alpha=False, clip=clip) # 将页面转换为图像
        if not os.path.exists(imagePath):
            os.makedirs(imagePath)
        pix.writePNG(imagePath+'/'+'psReport_%s.png' % pg)# store image as a PNG
 
if __name__ == "__main__":
    pdfPath = '../path/demo.pdf'
    imagePath = '../path/image'
    #pyMuPDF_fitz(pdfPath, imagePath)#只是转换图片
    pyMuPDF2_fitz(pdfPath, imagePath)#指定想要的区域转换成图片

当然上面这种是综合下来最快的,另外PyMuPDF还可以对PDF进行追加删除之类的功能。 下面再介绍一种方法pdf2image

2、pdf2image将PDF转换成图片 pdf2image也是个包装器,真正的转换工具是poppler

GitHub地址:https://github.com/Belval/pdf2image ,上面也有相关的配置说明。

1、安装pdf2image: pip install pdf2image

2、Windows安装配置poppler(这里只介绍Windows,Mac和Linux去上面Github地址里面参考官网)

Windows用户必须为Windows安装poppler (http://blog.alivate.com.au/poppler-windows/),然后将bin/文件夹添加到PATH(开始>输入env>编辑系统环境变量>环境变量...>系统变量>Path)

注意:这里配置之后需要重启一下电脑才会生效,不然会报如下错误:

ERROE:FileNotFoundError: [WinError 2] The system cannot find the file specified

During handling of the above exception, another exception occurred:

3、pip install pillow (如果你还没有安装过的话)

from pdf2image import convert_from_path,convert_from_bytes
import tempfile
from pdf2image.exceptions import (
    PDFInfoNotInstalledError,
    PDFPageCountError,
    PDFSyntaxError
)
def pdf2image2(pdfPath, imagePath, pageNum):
    #方法一:
    #convert_from_path('a.pdf', dpi=500, "output",fmt="JPEG",output_file="ok",thread_count=4)
    #这会将a.pdf转换成在output文件夹下形如ok_线程id-页码.jpg的一些文件。
    #若不指定thread_count则默认为1,并且在文件名中显示id. 这种转换是直接写入到磁盘上的,因此不会占用太多内存。
    
    #下面的写法直接写入到内存,
    images = convert_from_path(pdfPath, dpi=96)
    for image in images:
        if not os.path.exists(imagePath):
            os.makedirs(imagePath)
        image.save(imagePath+'/'+'psReport_%s.png' % images.index(image), 'PNG')
    
    #方法二:
    images = convert_from_bytes(open('/home/belval/example.pdf', 'rb').read())
    for image in images:
        if not os.path.exists(imagePath):
            os.makedirs(imagePath)
        image.save(imagePath+'/'+'psReport_%s.png' % images.index(image), 'PNG')    
    
    #方法三,也是最推荐的方法
    with tempfile.TemporaryDirectory() as path:
        images_from_path = convert_from_path(pdfPath, output_folder=path, dpi=96)
        for image in images_from_path:
            if not os.path.exists(imagePath):
                os.makedirs(imagePath)
            image.save(imagePath+'/'+'psReport_%s.png' % images_from_path.index(image), 'PNG')
        print(images_from_path)

以下是参数定义:

pdf_path --> 要转换的PDF文档路径

dpi --> DPI中的图像质量(默认为200),Windows默认为96dpi

output_folder --> 将生成的图像写入文件夹(而不是直接写入内存)若是path不做指定的话,path的默认地址是:C:\Users\pzhang7\AppData\Local\Temp\生成的uuid4。

first_page --> 从哪一页开始转换,默认是PDF的第一页

last_page --> 转换到哪一页,默认是PDF的最后一页

fmt --> 输出图像格式默认格式是ppm,还可以设置为png和jpeg等

thread_count --> 允许生成多少个线程进行处理,一般不超过4个线程;

userpw --> PDF的密码(若有密码的话需要添加)

use_cropbox --> 使用cropbox而不是mediabox

strict --> 参数允许您使用自定义类型PDFSyntaxError捕获pdftoppm语法错误

transparent --> 参数允许生成没有背景的图像,而不是通常的白色图像(为此需要pdftocairo)

single_file --> 使用pdftoppm / pdftocairo中的-singlefile选项

output_file --> 输出文件名是什么

poppler_path --> 查找poppler二进制文件的路径,允许用户使用poppler_path指定poppler的安装路径;默认不指定的话需要将bin添加到系统PATH

pdf2image应该也可以对指定区域进行截取,暂时还没详细研究其方法,因为已经找到更快的方法解决问题了,对比如下所示:

3、比较PyMuPDF和pdf2image

以下是对一份75页的PDF,输出DPI=96的时间性能对比,pdf2image使用的是默认线程数,下面的对比并没有设置多线程,使用多线程会快一点,当线程数设为5的时候,速度是9秒。

可以看出使用pyMuPDF_Fitz明显快一倍多,最终选取了这种方式。

4、Wand将PDF转换成图片

和pdf2image一样,wand都是包装接口(bindings),而实际进行转换的工具是ImageMagick.

Wind官网: http://docs.wand-py.org/en/0.5.6/

ImageMagick官网:

https://imagemagick.org/script/download.php#windows

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)

由于问题已经解决,而且性能也还不错,就没有具体去研究Wind这种方式了,感兴趣的可以去看看。

文章分享自微信公众号:
萌海无涯

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

原始发表时间:2019-08-06
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • Python将PDF转成图片—PyMuPDF和pdf2image

    前言:在最近的测试中遇到一个与PDF相关的测试需求,其中有一个过程是将PDF转换成图片,然后对图片进行测试。

    软测小生
  • Python 将pdf转成图片

    用户1130025
  • Python将PDF转成图片PNG和JPG

    前言:在最近的测试中遇到一个与PDF相关的测试需求,其中有一个过程是将PDF转换成图片,然后对图片进行测试。

    软测小生
  • 利用python将PDF批量转成图片

    因为工作上的需求,需要将PDF转成图片,在网络上寻找了一些PDF转图片的方法,但是如若想要免费使用的话,限制太多,如:限制转换页数,像素过低等,干脆考虑...

    文科生的python自学之路
  • 用 Python 批量提取 PDF 的图片,并存储到指定文件夹

    上篇《用 Python 批量提取 PDF 的表格数据,保存为 Excel》文章中,我们利用 Python 的第三方工具库 pdfplumber 批量提取 PDF...

    杰哥的IT之旅
  • 三种方法,Python轻松提取PDF中全部图片

    今天就跟大家系统分享几种Python提取 PDF 图片的方法。其实没有非常完美的方法,每种方法提取效率都不是百分之百,因此可以考虑用多种方法进行互补,主要将涉及...

    刘早起
  • 2021-04-12 pdf转图片

    最近做anki牌组,需要把一个大的pdf每页拆成一张图片,参考下面几篇文章实现了python脚本 1、pip快速下载配置 参考:怎么解决pip下载慢,超时等...

    oracle3
  • Python脚本工具,PyMuPDF批量提取PDF文件中的图片

    如何批量快速提取出PDF中的图片文件,你是否遇到这样的一个问题,尤其是PPT文件转换为PDF文件,需要快速提取其中的图片文件,如果你恰好会那么一点py,同时复制...

    二爷
  • 批量比较两个PDF文档(PDFUtil通过文本/者图像进行比较)

    在我的项目中,我需要比较大量的PDF文档,确认两份PDF文档是否一致,如果仅仅凭借着手动去逐一比较,可能很快就阵亡了。另外也有一些软件可以辅助的去对比,但依然是...

    软测小生
  • PDF 转图片时丢字的一种可能解决方案

    Python 中 PDF 转图片一般用的是 pdf2image。有时我们会发现 PDF 转出来的图片都是空白,或者缺失了一些字,具体表现就是一些应该有字的区域是...

    Alan Lee
  • 使用Python将PDF转换成图片

        必须在Linux环境下,使用到的环境和工具:CentOS7+Python3.6+pdf2image+poppler

    py3study
  • Python调用WPS进行文档转换PDF及PDF转图片

    https://blog.alivate.com.au/poppler-windows/

    剑行者
  • 有爱的Python项目:将图片转成像素风

    各位一定见过“像素风”的图片,这种图片具体很浓的卡通风格。如果用各种色块/小图/字符拼出大的图片,构建一个像素风的世界,就像《我的世界》里一样,肯定非常有趣。

    Crossin先生
  • win7 python pdf2imag

    项目要求pdf转成图片,网上较多的方案对于windows极其不友好,wand,Pythonmagick(win下载地址:www.lfd.uci.edu/~goh...

    py3study
  • pdf2image类库实现批量pdf转图片

    通过pdf2image来实现对PDF文件的处理工作,我们本次主要做的是将PDF文件批量转成图片。之前写过批量提取封面的文章,传送:Python提取PDF第一页为...

    申霖
  • python读取pdf提取文字和图片

    如下图所示,一份pdf有几十页,每页九张图片, 提取出图片并用图片下方的文本对图片命名

    诡途
  • 利用 Python 优雅地将 PDF 转换成图片

    之前收集了很多优秀的 PDF文档,但是需要看的时候不是很方便,需要去找到这个文件,如果是在手机上的话往往还需要下载 PDF相关的插件才行,而且最大的问题是不便于...

    顶级程序员
  • Python实现PD文字识别、提取并写入CSV文件脚本分享

    扫描件一直受大众青睐,任何纸质资料在扫描之后进行存档,想使用时手机就能打开,省心省力。但是扫描件的优点也恰恰造成了它的一个缺点,因为是通过电子设备扫描,所以出来...

    老表
  • PDF 的各种操作,我用 Python 来实现(附网站和操作指导)

    PDF 处理是日常工作中的常见需求,包括 PDF 合并、删除、提取等。更复杂的任务如:将 PDF 转换成 图像。

    机器视觉CV

扫码关注腾讯云开发者

领取腾讯云代金券