目录

  • 一. 安装fitz
  • 二. pdf文件格式问题
  • 2.1 pdf文件存在多种格式
  • 2.2 分析问题
  • 三. 代码




一. 安装fitz

安装:需要安装fitz和PyMuPDF,否则会报如下错误:ModuleNotFoundError: No module named ‘frontend’

pip install fitz PyMuPDF

二. pdf文件格式问题

2.1 pdf文件存在多种格式

pdf文件的格式有好几种,用Adobe Acroba打开比较正常的论文,如下所示:

python中fit函数 python fitz 详解_fitz

这种类型的pdf文件可以比较正常地提取里面的图片。

还有这种类型的,如下图所示:

python中fit函数 python fitz 详解_fitz_02

2.2 分析问题

这种类型pdf文件,提取图片的时候往往会将整个页面当作图片提取出来。

  • 利用fitz库读取文件
import fitz
file = 'test.pdf'
doc = fitz.open(file)
  • 获取doc的对象数
nums = doc._getXrefLength()
  • 遍历每一个对象,定义对象的字符串并打印出来看看是啥玩意儿
for i in range(1, nums):
	# 定义对象字符串
	text = doc._getXrefString(i)
	print(i, text)

部分结果如下图所示:

python中fit函数 python fitz 详解_python中fit函数_03

  • text是一个字符串,如果是图像,它会包含"/Subtype /Image"和"/Type /XObject"。所以,可以用来匹配图像。

但是,对于2.1节第二种pdf文件,text如下所示:

python中fit函数 python fitz 详解_python中fit函数_04

  • 虽然提取到图片,但是这其实是把整张页面作为图片提取出来了,我们并不需要页面图片。
  • 通过观察,可以看到,对于这种页面图片,它的宽和高分别是2550和3300,所以可以加入条件去筛选掉这种对象。
  • 同时还有可能提取到类似图标的图像,这种类型的对象text里包含"thumbnail"字符串,也可以筛选掉。
for i in range(1, nums):
    # 定义对象字符串
    text = doc._getXrefString(i)
    print(i, text)
    if ('Width 2550' in text) and ('Height 3300' in text) or ('thumbnail' in text):
        continue

接下来就是保存图像了,整体代码见第三部分。

三. 代码

import fitz
import re
import os


def pdf2pic(path, pic_path):
    '''
    # 从pdf中提取图片
    :param path: pdf的路径
    :param pic_path: 图片保存的路径
    :return:
    '''
    # 打开pdf
    doc = fitz.open(path)
    nums = doc._getXrefLength()
    imgcount = 0 # 图像计数
   
    # 遍历每一个对象
    for i in range(1, nums):
        text = doc._getXrefString(i)
        # print(i, text)
        # 过滤无用图片
        if ('Width 2550' in text) and ('Height 3300' in text) or ('thumbnail' in text):
            continue
            
	    # 使用正则表达式来查找图片
	    checkXO = r"/Type(?= */XObject)"
	    checkIM = r"/Subtype(?= */Image)"
	    
        isXObject = re.search(checkXO, text)
        isImage = re.search(checkIM, text)
        
        # 不符合条件, continue
        if not isXObject or not isImage:
            continue
		imgcount += 1

        # 生成图像
        pix = fitz.Pixmap(doc, i)
		
		# 保存图像名
        img_name = "img{}.png".format(imgcount)
        
        # 如果pix.n<5,可以直接存为PNG
        if pix.n < 5:
            try:
                pix.writePNG(os.path.join(pic_path, img_name))
                pix = None
            except:
                pix0 = fitz.Pixmap(fitz.csRGB, pix)
                pix0.writePNG(os.path.join(pic_path, img_name))
                pix0 = None

if __name__ == '__main__':
    # pdf路径
    path = r'test.pdf'
	
	# 保存的图片路径
    pic_path = 'img'
    
    pdf2pic(path, pic_path)

其他问题:可能提取到的图片尺寸非常小,也可以通过正则表达式提取图像尺寸,设置条件,筛选掉太小的图片。

结束。