Python:利用pyMuPDF将PDF页面保存为图片

今天遇到一个小需求:一堆PDF文档,需要将首页封面保存为图片。网上搜索了一番,似乎第三方库 pyMuPDF 就能很好地解决问题。现学现卖,记录如下。

第三方库:pyMuPDF
官方文档:https://pymupdf.readthedocs.io/en/latest/index.html
安装方法:pip install pyMuPDF

最基础的用法

要将PDF的某一页保存为图片,最简单的可分为4个步骤:

  1. 打开PDF文档
  2. 获取目标页面
  3. 获取目标页面的图片
  4. 保存图片

代码如下:

import fitzpdf = fitz.open(r"D:\Docs\a001.pdf")page = pdf[0]pic = page.get_pixmap()pic.save(r"D:\Docs\a001.png")

最基础的用法

注意:

  • 第1行:这个库虽然叫 pyMuPDF,但导入的库名却是 fitz。
  • 第4行:页码从0开始,因此PDF第一页为 pdf[0]。
  • 第5行:获取图片的函数,老版本为 getPixmap(),新版本则为 get_pixmap()。
  • 第6行:保存图片的函数,老版本为 writePNG(),新版本则为 save()。

设置图片大小:笨办法

默认情况下,将以 96dpi 导出图片。可以设置缩放倍数,步骤如下:

  1. 打开PDF文档
  2. 获取目标页面
  3. 设置宽和高的缩放倍数
  4. 获取目标页面的图片
  5. 保存图片

代码如下:

import fitzpdf = fitz.open(r"D:\Docs\a001.pdf")page = pdf[0]mat = page.Matrix(2.0, 2.0) #两个浮点数分别是宽和高的缩放倍数pic = page.get_pixmap(matrix=mat) #将参数传入pic.save(r"D:\Docs\a001.png")

笨办法设置图片大小

注意:宽和高的缩放倍数不一致时,将导致图片变形。

设置图片大小:固定宽度

上面的方法虽然可以对图片进行缩放,但最终尺寸太难掌握了。而且如果PDF文档的尺寸不固定,每次缩放的倍数都得重新摸索。太费事了。

如果我们希望导出的图片有固定的宽度(比如 1280px),该咋办?答案是:先获取PDF的宽度,再来计算与目标宽度(比如 1280px)之间的倍数关系。在 pyMuPDF 中,页面宽度的属性值为 page.rect.width。

步骤如下:

  1. 打开PDF文档
  2. 获取目标页面
  3. 获取目标页面的宽度
  4. 计算宽和高的缩放倍数
  5. 设置宽和高的缩放倍数
  6. 获取目标页面的图片
  7. 保存图片

代码如下:

import fitzpdf = fitz.open(r"D:\Docs\a001.pdf")page = pdf[0]page_width = page.rect.width #获取页面宽度zoom_rate = 1280/page_width #计算缩放倍数mat = fitz.Matrix(zoom_rate, zoom_rate)pic = page.get_pixmap(matrix=mat)pic.save(r"D:\Docs\a001.png")

设置图片的固定宽度

保存图片为JPG格式

默认保存图片的格式为PNG,宽度设置得高一些,就会发现图片体积也跟着水涨船高。能不能直接保存为JPG格式呢?当然!不过需要借助第三方库 Pillow 的力量。

第三方库:Pillow
安装方法:pip install Pillow

安装之后,甚至不需要导入,用 pil_save() 函数直接调用。即:将 save() 函数替换为 pil_save() 即可。代码如下:

import fitzpdf = fitz.open(r"D:\Docs\a001.pdf")page = pdf[0]page_width = page.rect.widthzoom_rate = 1280/page_widthmat = fitz.Matrix(zoom_rate, zoom_rate)pic = page.get_pixmap(matrix=mat)pic.pil_save(r"D:\Docs\a001.jpg") #用pil_save()函数

图片保存为JPG格式

整个文件批量保存图片

最后一步,就是批处理整个文件夹内的PDF。简要步骤如下:

  1. 获取文件夹内所有PDF文档的完整路径 files。
  2. 创建用以保存图片的文件夹。
  3. 遍历所有文件并保存图片。

代码如下:

import fitz, os#获取文件夹下所有文件的完整路径folder = r"D:\Docs"files = [os.path.join(i[0], j) for i in os.walk(folder) for j in i[-1]]#创建用以保存图片的文件夹save_dir = r"%s\Covers" % folderif not os.path.exists(save_dir):os.makedirs(save_dir)#遍历并保存图片for f in files:pdf = fitz.open(f)page = pdf[0]page_width = page.rect.widthzoom_rate = 1280/page_widthmat = fitz.Matrix(zoom_rate, zoom_rate)pic = page.get_pixmap(matrix=mat)pic_name = r"%s\%s.jpg" % (save_dir, os.path.basename(f)[:-4])pic.pil_save(pic_name)

批处理整个文件夹内的所有文件

注意:

  • 第4-5行:利用 os.walk() 和列表推导式获取文件夹 folder 下所有文件的完整路径,算是一个公式吧,建议死记硬背。我是添加为输入法的字条的。
  • 第8-10行:如果图片不想保存在PDF所在路径下,就必须保证图片保存路径是已经存在的文件夹,或用 os.path.exists() 函数进行判断并创建。
  • 第21行:利用 %s 拼接图片的文件名,保持与原PDF文件名一致。用 os.path.basename(f) 获取PDF文件的末级文件名(含扩展名),类似 a001.pdf 。而后面再用切片 [:-4] 截掉扩展名(-4 表示从倒数第4个字符的左侧开始截取,至整个字符串的最左侧,截取的部分不包含倒数第4个字符)。

结语

当然,更完整的代码还应该包含异常处理,甚至目标文件夹内文件扩展名的判断等,此处不再赘述。

本篇仅涉及第三方库 pyMuPDF 比较基础的操作。查看官方文档可以发现,这个库真是个宝藏。如果对PDF文档处理有更高级的操作需求,可以仔细研读。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章