Python3 处理PDF之PyMuPDF 入门

news2024/9/24 11:30:22

PyMuPDF 简介

PyMuPDF是一个用于处理PDF文件的Python库,它提供了丰富的功能来操作、分析和转换PDF文档。这个库的设计目标是提供一个简单易用的API,使得开发者能够轻松地在Python程序中实现PDF文件的各种操作。

PyMuPDF的主要特点如下:

  • 跨平台兼容性:PyMuPDF支持多种操作系统,如Windows、macOS和Linux,可以在这些平台上运行Python程序。
  • 强大的PDF处理能力:PyMuPDF提供了丰富的功能来操作PDF文件,如读取、写入、分割、合并、旋转、裁剪等。此外,它还支持加密和解密PDF文档,以及提取文本、图像和元数据等信息。
  • 易于使用:PyMuPDF的API设计简洁明了,易于学习和使用。开发者可以通过简单的函数调用来实现各种PDF操作,而无需深入了解底层细节。

PyMuPDF 安装及其依赖第三方框架

pip 安装 PyMuPDF 模块

pip install pymupdf

验证pymupdf 模块是否安装成功

import fitz
import PIL

# 打印pymupdf模块:基本信息
from fitz import TextPage

print(fitz.__doc__)

PyMuPDF 1.22.5: Python bindings for the MuPDF 1.22.2 library.
Version date: 2023-06-21 00:00:01.
Built for Python 3.10 on win32 (64-bit).

PyMuPDF 依赖第三方框架 

当使用Pixmap.pil_save()Pixmap.pil_tobytes() 需要 Pillow模块

当使用Document.subset_fonts()时需要  FontTools模块

PyMuPDF 核心类

在PyMuPDF 核心类演示涉及类

 其他未使用到的其他类:Archive(档案)、Colorspace(色彩空间对象)、DisplayList(显示列表对象)、DocumentWriter(文档编辑对象)、Identity(身份对象)、 IRect(长方形对象)、linkDest(连接目的对象)、Matrix(矩阵对象)、Outline(大纲)、Quad(四边形对象)、Shape(形状对象)、 Story(章节对象)、TextPage(文本页面对象)、TextWriter(文本写入对象)、Tools(工具类)、Xml(xml 文档对象)

PyMuPDF 核心类演示

加载PDF文件

# 加载pdf 文件
doc = fitz.open("E:\doc\opencv 4.1中文官方文档v1.1版.pdf")

获取Document 属性和方法

# 获取Document 文档对象的属性和方法
# 1、获取pdf 页数
pageCount = doc.page_count
print("pdf 页数", pageCount)

# 2、获取pdf 元数据
metaData = doc.metadata
print("pdf 元数据:", metaData)

# 3、获取pdf 目录信息
toc = doc.get_toc()
print("pdf 目录:", toc)

Page 属性和方法

通过Page 对象实现以下功能:

• 您可以将页面呈现为光栅或矢量(SVG)图像,可以选择缩放、旋转、移动或剪切页面。

• 您可以提取多种格式的页面文本和图像,并搜索文本字符串。

Page 加载方法

page = doc.load_page(pno) # loads page number 'pno' of the document (0-based)
page = doc[pno] # the short form

Documnet 迭代器加载Page 方法

for page in doc:
    # do something with 'page'
    
# ... or read backwards
for page in reversed(doc):
    # do something with 'page'
    
# ... or even use 'slicing'
for page in doc.pages(start, stop, step):
    # do something with 'page'
# 获取Page 页面对象的属性和方法
page = doc.load_page(1)  # 默认加载第一页
print("page 对象:", page)

检查页面的链接、批注或表单字段

# 1、获取Page 页面的链接、批注或表单字段
links = page.get_links()
for link in links:
    # 涉及Link 对象
    print("链接:", link)

annots = page.annots()
for annot in annots:
    # 涉及Annot 对象
    print("批注:", annot)

widgets = page.widgets()
for widget in widgets:
    # 涉及表单字段
    print("表单字段:", widget)

页面展示/页面图像保存到文件中

# 2、Page 页面-光栅图像
pix = page.get_pixmap()
print("打印页面图像对象:", pix)
# 保存光栅图像图像,需要依赖第三方框架:Pillow
pix.pil_save("page-%i.png" % page.number)

Page.get_pixmap()提供了许多用于控制图像的变体:分辨率、颜色空间(例如,生成灰度图像或具有减色方案的图像)、透明度、旋转、镜像、移位、剪切等。

Pixmap包含以下引用的许多方法和属性。其中包括整数宽度高度(每个像素)和跨距(一个水平图像行的字节数)。属性示例表示表示图像数据的矩形字节区域(Python字节对象)。

温馨提示:page.get_svg_image()创建页面的矢量图像。 

提取文本和图像

# 3、Page 获取文本\图像\其他信息
# 温馨提示:涉及TextPage 常量类型定义
text = page.get_text("text")
print("指定页面文本内容:", text)

opt使用以下字符串之一以获取不同的格式:

  • "text":(默认)带换行符的纯文本。无格式、无文字位置详细信息、无图像- "blocks":生成文本块(段落)的列表- "words":生成单词列表(不包含空格的字符串)- "html":创建页面的完整视觉版本,包括任何图像。这可以通过internet浏览器显示- "dict"/"json":与HTML相同的信息级别,但作为Python字典或resp.JSON字符串。- "rawdict"/"rawjson""dict"/"json"的超级集合。它还提供诸如XML之类的字符详细信息。- "xhtml":文本信息级别与文本版本相同,但包含图像。- "xml":不包含图像,但包含每个文本字符的完整位置和字体信息。使用XML模块进行解释。

搜索文本

# 4、Page 文本检索
search = page.search_for("图像的基本操作")
print("打印检索文本的位置:", search)

提供一个矩形列表,每个矩形都包含一个字符串“mupdf”(不区分大小写)。

PDF操作 

PDF是唯一可以使用PyMuPDF修改的文档类型。其他文件类型是只读的。但是,您可以将任何文档(包括图像)转换为PDF,然后将所有PyMuPDF功能应用于转换果,Document.convert_to_pdf()

Document.save()始终将PDF以其当前(可能已修改)状态存储在磁盘上。

通常,您可以选择是保存到新文件,还是仅将修改附加到现有文件(“增量保存”),这通常要快得多。

# Document 操作PDF页面
# 1、PDF 页面删除
# doc.delete_page(1)
# 1、PDF 页面拷贝和移动
doc.copy_page(1)  # 第一页移动最后一页,温馨提示:移动的页面还在元PDF 文件中。
# 1、 PDF 插入页面,  返回插入页面对象
new_page = doc.new_page(pno=-1, width=595, height=842)
# 插入页面, 设置文本
text = "你的文本"
point = fitz.Point(50, 50)  # 这是一个下x,y 二维坐标系,在这个区域内插入你的文本
new_page.insert_text(point, text, fontsize=20)
# 2、Document 保存
doc.save("opencv pdf文件调整.pdf")
# 3、Documemt 销毁
doc.close()

PDF 删除方法

Document.delete_page()
Document.delete_pages()

PDF移动拷贝方法

Document.copy_page()
Document.fullcopy_page()
Document.move_page()

PDF插入Page 方法

Document.insert_page()
Document.new_page()

PyMuPDF 核心功能模块封装

PDF 分割

每一页单独保存为一个pdf

def split_per_page(input, output):
    if not os.path.exists(output):
        os.makedirs(output)
    
    doc = fitz.open(input)
    for page in range(doc.page_count):
        dst_doc = fitz.open()
        dst_doc.insert_pdf(doc,from_page=page,to_page=page)
        dst_doc.save(os.path.join(output,f'{page}.pdf'))
        dst_doc.close()
    doc.close()

# 把每一个页面保存为一个pdf,并保存在test文件夹中
split_per_page("test.pdf","test")

范围内的页面保存为pdf 

def split_range_page(input, output, range):
    if not os.path.exists(output):
        os.makedirs(output)
    doc = fitz.open(input)
    start = range[0] - 1
    end = range[1] - 1
    dst_doc = fitz.open()
    dst_doc.insert_pdf(doc, from_page=start, to_page=end)
    dst_doc.save(os.path.join(output,'range_page.pdf'))
    dst_doc.close()
    doc.close()

# 把1-10也保存为pdf,保存在test文件夹中
split_range_page('test.pdf','test', [1,10])

 任意的页面保存为pdf

def split_selected_page(input, output, pages):
    if not os.path.exists(output):
        os.makedirs(output)
    
    doc = fitz.open(input)
    result = map(lambda x: x - 1, pages)
    doc.select(list(result))
    doc.save(os.path.join(output,'selected_pages.pdf'))
    doc.close()
    
# 把第一、三、八页面保存为pdf,并保存在test文件夹中
split_selected_page('test.pdf','test',[1,3, 8])

PDF 合并

import fitz

doc_a = fitz.open("a.pdf") # open the 1st document
doc_b = fitz.open("b.pdf") # open the 2nd document

doc_a.insert_pdf(doc_b) # merge the docs
doc_a.save("a+b.pdf") # save the merged document with a new filename

# 把b.pdf合并到a.pdf,保存为a+b.pdf

PDF 中的图片提取

import fitz

doc = fitz.open("test.pdf") # open a document

for page_index in range(len(doc)): # iterate over pdf pages
	page = doc[page_index] # get the page
	image_list = page.get_images()

	# print the number of images found on the page
	if image_list:
		print(f"Found {len(image_list)} images on page {page_index}")
	else:
		print("No images found on page", page_index)

	for image_index, img in enumerate(image_list, start=1): # enumerate the image list
		xref = img[0] # get the XREF of the image
		pix = fitz.Pixmap(doc, xref) # create a Pixmap

		if pix.n - pix.alpha > 3: # CMYK: convert to RGB first
			pix = fitz.Pixmap(fitz.csRGB, pix)

		pix.save("page_%s-image_%s.png" % (page_index, image_index)) # save the image as png
		pix = None

PDF 保存为图片

def covert2pic(zoom):
    doc = fitz.open("test.pdf")
    total = doc.page_count
    for pg in range(total):
        page = doc[pg]
        zoom = int(zoom)            #值越大,分辨率越高,文件越清晰
        rotate = int(0)
        
        trans = fitz.Matrix(zoom / 100.0, zoom / 100.0).prerotate(rotate)
        pm = page.get_pixmap(matrix=trans, alpha=False)
      
        lurl='.pdf/%s.jpg' % str(pg+1)
        pm.save(lurl)
    doc.close()

covert2pic(200)

PDF 添加水印

def add_watermark(input, watermark):
    doc = fitz.open(input)
    for page in doc:
        page.insert_image(page.bound(),filename=watermark, overlay=False)
    doc.save(os.path.join("test","watermark.pdf"))
    doc.close()
    
add_watermark("test.pdf","watermark.png")

PDF 加密

PDF加密有两种形式

  • 用户加密,需要输入密码才能打开pdf
  • 拥有者加密,可以防止打印、复制、添加注释、添加删除页面等功能
def encrypt_pdf():
    perm = int(
        fitz.PDF_PERM_ACCESSIBILITY # always use this
                | fitz.PDF_PERM_PRINT # permit printing
                | fitz.PDF_PERM_COPY # permit copying
                | fitz.PDF_PERM_ANNOTATE # permit annotations
    ) # 可以打印,复制,添加注释
    owner_pass = "owner" # owner password
    user_pass = "user" # user password
    encrypt_meth = fitz.PDF_ENCRYPT_AES_256 # strongest algorithm
    doc = fitz.open("test.pdf") # empty pdf
    doc.save("encrypt.pdf",encryption=encrypt_meth,owner_pw=owner_pass,permissions=perm,user_pw=user_pass) # 同时使用
    
# 这两个加密方式可以,单独使用,也可以同时使用

# 单独使用用户加密
doc.save("encrypt.pdf",encryption=encrypt_meth,owner_pw=owner_pass)

PyMuPDF 在PyQT5 运用

功能要求:在PyQT-5 展示pdf 文件.

效果展示:

PyQT-5 UI效果展示和源文件

 

 pdfshow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <widget class="QLabel" name="label">
   <property name="geometry">
    <rect>
     <x>130</x>
     <y>70</y>
     <width>54</width>
     <height>12</height>
    </rect>
   </property>
   <property name="text">
    <string>PDF展示</string>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

pdfshow.py 源码

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'pdfshow.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.
import sys

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtGui import QImage, QPixmap, QTransform
from PyQt5.QtWidgets import QWidget, QApplication
# 添加PDF 文件操作依赖
import fitz


class Ui_Form(QWidget):
    def __init__(self):
        super().__init__()
        self.label = None
        self.setupUi()
        self.image()

    def setupUi(self):
        self.setObjectName("Form")
        self.resize(400, 300)
        self.label = QtWidgets.QLabel(self)
        self.label.setGeometry(QtCore.QRect(130, 70, 54, 12))
        self.label.setObjectName("label")

        self.retranslateUi()
        QtCore.QMetaObject.connectSlotsByName(self)

    def retranslateUi(self):
        _translate = QtCore.QCoreApplication.translate
        self.setWindowTitle(_translate("Form", "Form"))
        self.label.setText(_translate("Form", "PDF展示"))

    def image(self):
        file = "E:\doc\opencv 4.1中文官方文档v1.1版.pdf"
        # 打开文件
        doc = fitz.open(file)
        # 读取一页 0代表第1页
        page_one = doc.load_page(1)
        # 将第一页转换为Pixmap
        page_pixmap = page_one.get_pixmap()
        # 将Pixmap转换为QImage
        image_format = QImage.Format_RGBA8888 if page_pixmap.alpha else QImage.Format_RGB888
        page_image = QImage(page_pixmap.samples, page_pixmap.width,
                            page_pixmap.height, page_pixmap.stride, image_format)
        width = page_image.width()
        height = page_image.height()
        # QImage 转为QPixmap
        pix = QPixmap.fromImage(page_image)
        trans = QTransform()
        trans.rotate(90)  # 这里设置旋转角度
        new = pix.transformed(trans)
        # 设置标签宽和高
        self.label.setFixedSize(400, 350)
        # 设置图片大小自适应标签
        self.label.setScaledContents(True)
        # 给标签设置图像
        self.label.setPixmap(new)


if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = Ui_Form()
    w.show()
    sys.exit(app.exec_())

解决思路

  1. 使用PyMuPDF模块打开文件。
  2. 读取第一页pdf文件第一页。
  3. 从第一页获取图像,是Pixmap类。
  4. 使用PyQt5的QImage将上面的Pixmap转换为QImage。
  5. 将QImage转换为QPixmap。
  6. 将QPixmap设置给Label。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/839251.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【分布式系统】聊聊服务调度

什么是服务治理 对于程序员来说的话&#xff0c;把功能按照一定的设计进行开发上线之后&#xff0c;其实并不够&#xff0c;在未来的时间内&#xff0c;其实还需要做好功能的维护工作&#xff0c;而维护项目的成本远远高于开发出一个软件的成本。 对于功能开发起来期来说&am…

ensp-GVRP服务

ensp-GVRP服务 日期&#xff1a;6-26 &#x1f4ce;GVRP实验.zip&#x1f4ce;GVRP服务.docx

无涯教程-Perl - 环境配置

在开始编写Perl程序之前&#xff0c;让我们了解如何设置我们的Perl环境。 您的系统更有可能安装了perl。只需尝试在$提示符下给出以下命令- $perl -v 如果您的计算机上安装了perl&#xff0c;那么您将收到以下消息: This is perl 5, version 16, subversion 2 (v5.16.2) b…

谁更适合搭配甜点显卡?i7-13700KF、锐龙7 7800X3D对比:游戏相当 生产力Intel强了50%...

一、前言&#xff1a;如果搭配2000元甜点显卡 i7-13700KF和锐龙7 7800X3D谁更有性价比&#xff1f; 现在AMD最受欢迎的处理器无疑是拥有96MB三级缓存的锐龙7 7800X3D&#xff0c;这是一颗专为游戏而生的处理器。 Intel这边&#xff0c;i7-13700KF以略高于i5-13600K的售价&#…

python:卡尔曼和贝叶斯滤波器

本文分享一个Filerpy的说明文档和代码示例文档&#xff0c;有关于 Python 中的卡尔曼和贝叶斯滤波器。该方法可以应用于气象遥感等领域。 说明文档&#xff1a;https://filterpy.readthedocs.io/en/latest/kalman/KalmanFilter.html 参考代码链接&#xff1a;https://nbviewer.…

conda install 和pip install有什么区别?

本篇为分享贴&#xff0c;截图部分选自知乎&#xff0c;部分选自csdn&#xff0c;文字内容是结合自己实践进行总结。 环境引用的包在哪&#xff1f; 首先&#xff0c;一条命令&#xff1a; python -m site 这条命令可以定位引用的包在哪里 &#xff0c;当然也可以自己设置默认…

K8s中的Secret

Secret作用&#xff1a;加密数据存在etcd里面&#xff0c;让pod容器以挂载Volume方式进行访问。场景&#xff1a;凭据

基于Open3D的点云处理14-法向量

法向量 计算法向量的接口函数&#xff1a; Open3d使用estimate_normals函数来计算法向量。其参数设置Open3d提供了3中参数搜索的方法&#xff08;所有计算的法向量模长为1&#xff09;&#xff1a; open3d.geometry.KDTreeSearchParamKNN(knn20) # 计…

win11设置管理员权限

【win11家庭版怎么找管理员权限&#xff0c;怎么找gpedit】 win11家庭版怎么找管理员权限&#xff0c;怎么找gpedit_哔哩哔哩_bilibili echo offpushd "%~dp0"dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum …

【雕爷学编程】Arduino动手做(185)---WK104 亚克力机械爪

收了一套 亚克力机械爪的散件&#xff0c;准备尝试组装一下。 All parts 2 left claw 2 right claw 4 half claw 2 plate fixer 双通铜柱 Double copper column 铜柱 copper pillar 螺母 Nut 螺丝 Screw Prepare several parts of the picture and start assembling the l…

小蜗语音1.2 文本生成字幕 文本生成语音配音

1、文本转字幕&#xff0c;可以把一部小说直接生成字幕 2、文本转语音&#xff0c;可以直接把一部小说或者字幕文件生成语音&#xff0c;并且新生成的语音和字幕一一对应 链接&#xff1a;https://pan.baidu.com/s/1X_rY4Wjkk2cWqsFcu4JSHA?pwdvtpm 提取码&#xff1a;vtpm

S7-200SMART与ET200SP远程IO模块进行PROFINET通信的具体方法

S7-200SMART与ET200SP远程IO模块进行PROFINET通信的具体方法 使用前提: 只有标准型且固件版本为V2.4及以上的S7-200 SMART CPU才支持 PROFINET 控制器功能。 S7-200 SMART 作 PROFINET 控制器最多可带8个 IO 设备(例如:远程 IO、阀岛、变频器、伺服和机器人等)。 本例中以 …

剑指offer15.二进制中1的个数

第一种方法是将n不断与2的i次方相与&#xff0c;如果n的2的i次方的位置上是1&#xff0c;相与的结果就是1&#xff0c;res&#xff0c;最后返回res即可。 public class Solution {// you need to treat n as an unsigned valuepublic int hammingWeight(int n) {int res 0;fo…

Jmeter录制HTTPS脚本

Jmeter录制HTTPS脚本 文章目录 添加“HTTP代理服务器”设置浏览器代理证书导入存在问题 添加“HTTP代理服务器” 设置浏览器代理 保持端口一致 证书导入 点击一下启动让jmeter自动生成证书&#xff0c;放在bin目录下&#xff1a; 打开jmeter的SSL管理器选择刚刚生成的证书&…

Rabbitmq的消息确认

配置文件 spring:rabbitmq:publisher-confirm-type: correlated #开启确认回调publisher-returns: true #开启返回回调listener:simple:acknowledge-mode: manual #设置手动接受消息消息从生产者到交换机 无论消息是否到交换机ConfirmCallback都会触发。 Resourceprivate Rabb…

LeetCode--剑指Offer75(3)

目录 题目描述&#xff1a;剑指 Offer 20. 表示数值的字符串&#xff08;中等&#xff09;题目接口解题思路什么是有限状态自动机&#xff1f;如何使用&#xff1f; 代码 PS: 题目描述&#xff1a;剑指 Offer 20. 表示数值的字符串&#xff08;中等&#xff09; 请实现一个函数…

支付宝蜻蜓设备abs调试

蜻蜓设备系统日志调试 1、蜻蜓设备进入开发者模式 长按关键键直到屏幕上出现设置按钮&#xff0c;点击设置按钮&#xff0c;选择关于本机&#xff0c;找到系统版本&#xff0c;连续点击8次&#xff0c;选择进入调试模式 2、找到小程序容器&#xff0c;连续点击8次&#xff0…

自己实现Linux 的 cp指令

cp指令 Linux的cp指令就是复制文件&#xff1a; cp: 拷贝(cp 拷贝的文件 要拷贝到的地址或文件)&#xff0c;cp b.c test.c 将b.c拷成test.c的一个新文件 Linux 系统初识_mjmmm的博客-CSDN博客 实现思路 打开源文件读文件内容到缓冲区创建新文件将读到的文件内容全部写入新文…

Java-对对象的拷贝、抽象类和接口的区别、Object类、对象的比较方法和内部类

目录 1.Clonable接口和深拷贝 2.抽象类和接口的区别 3.Object类 4.获取对象的信息 5.对象比较方法equals 6.内部类 1.Clonable接口和深拷贝 Java 中内置了一些很有用的接口, Clonable 就是其中之一&#xff0c;Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对…

人工智能学习07--pytorch23--目标检测:Deformable-DETR训练自己的数据集

参考 https://blog.csdn.net/qq_44808827/article/details/125326909https://blog.csdn.net/dystsp/article/details/125949720?utm_mediumdistribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-125949720-blog-125326909.235^v38^pc_releva…