基础知识#

打开文件#

要打开一个文件,请执行以下操作:

import pymupdf

doc = pymupdf.open("a.pdf") # open a document

注意

进一步了解

参阅支持的文件类型列表如何打开文件的操作指南以了解更多高级选项。


从 PDF 中提取文本#

要从 PDF 文件中提取所有文本,请执行以下操作:

import pymupdf

doc = pymupdf.open("a.pdf") # open a document
out = open("output.txt", "wb") # create a text output
for page in doc: # iterate the document pages
    text = page.get_text().encode("utf8") # get plain text (is in UTF-8)
    out.write(text) # write text of page
    out.write(bytes((12,))) # write page delimiter (form feed 0x0C)
out.close()

当然,可以提取文本的不仅仅是 PDF - 所有支持的文档文件格式,例如 MOBI、EPUB、TXT 等,都可以提取文本。

注意

进一步了解

如果您的文档包含基于图片的文本内容,请在该页面上使用 OCR 进行后续文本提取

tp = page.get_textpage_ocr()
text = page.get_text(textpage=tp)

还有更多示例解释如何从特定区域提取文本或如何从文档中提取表格。请参阅文本操作指南

您现在还可以以 Markdown 格式提取文本

API 参考


从 PDF 中提取图片#

要从 PDF 文件中提取所有图片,请执行以下操作:

import pymupdf

doc = pymupdf.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 = pymupdf.Pixmap(doc, xref) # create a Pixmap

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

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

注意

进一步了解

还有更多示例解释如何从特定区域提取文本或如何从文档中提取表格。请参阅文本操作指南

API 参考

提取矢量图形#

要从文档页面中提取所有矢量图形,请执行以下操作:

doc = pymupdf.open("some.file")
page = doc[0]
paths = page.get_drawings()

这将返回一个字典,其中包含页面上找到的所有矢量绘图的路径。

注意

进一步了解

请参阅:如何提取绘图

API 参考


合并 PDF 文件#

要合并 PDF 文件,请执行以下操作:

import pymupdf

doc_a = pymupdf.open("a.pdf") # open the 1st document
doc_b = pymupdf.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

合并 PDF 文件与其他类型的文件#

使用Document.insert_file(),您可以调用此方法将支持的文件与 PDF 合并。例如:

import pymupdf

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

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

注意

进一步了解

使用Document.insert_pdf()Document.insert_file() 可以轻松合并 PDF。给定已打开的 PDF 文档,您可以将页面范围从一个复制到另一个。您可以选择放置复制页面的位置,反转页面顺序,并更改页面旋转。

GUI 脚本 join.py 使用此方法合并文件列表,同时合并相应的目录段。它看起来像这样:

_images/img-pdfjoiner.jpg

API 参考


使用坐标#

在使用 PyMuPDF 时,有一个数学术语您应该感到熟悉 - “坐标”。请快速查看坐标部分,以了解坐标系,这将帮助您定位对象并理解文档空间。


向 PDF 添加水印#

要向 PDF 文件添加水印,请执行以下操作:

import pymupdf

doc = pymupdf.open("document.pdf") # open a document

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

    # insert an image watermark from a file name to fit the page bounds
    page.insert_image(page.bound(),filename="watermark.png", overlay=False)

doc.save("watermarked-document.pdf") # save the document with a new filename

注意

进一步了解

添加水印本质上就像在每个 PDF 页面底部添加图片一样简单。您应该确保图片具有所需的透明度和宽高比,以使其呈现您想要的效果。

在上面的示例中,每个文件引用都创建一个新图片,但为了获得更好的性能(节省内存和文件大小),此图片数据应仅引用一次 - 有关具体实现,请参阅Page.insert_image() 上的代码示例和解释。

API 参考


向 PDF 添加图片#

要向 PDF 文件添加图片(例如徽标),请执行以下操作:

import pymupdf

doc = pymupdf.open("document.pdf") # open a document

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

    # insert an image logo from a file name at the top left of the document
    page.insert_image(pymupdf.Rect(0,0,50,50),filename="my-logo.png")

doc.save("logo-document.pdf") # save the document with a new filename

注意

进一步了解

与水印示例一样,您应尽可能确保只引用图片一次以提高性能 - 请参阅Page.insert_image() 上的代码示例和解释。

API 参考


旋转 PDF#

要向页面添加旋转,请执行以下操作:

import pymupdf

doc = pymupdf.open("test.pdf") # open document
page = doc[0] # get the 1st page of the document
page.set_rotation(90) # rotate the page
doc.save("rotated-page-1.pdf")

注意

API 参考


裁剪 PDF#

要将页面裁剪到定义的Rect,请执行以下操作:

import pymupdf

doc = pymupdf.open("test.pdf") # open document
page = doc[0] # get the 1st page of the document
page.set_cropbox(pymupdf.Rect(100, 100, 400, 400)) # set a cropbox for the page
doc.save("cropped-page-1.pdf")

注意

API 参考


附加文件#

要向页面附加另一个文件,请执行以下操作:

import pymupdf

doc = pymupdf.open("test.pdf") # open main document
attachment = pymupdf.open("my-attachment.pdf") # open document you want to attach

page = doc[0] # get the 1st page of the document
point = pymupdf.Point(100, 100) # create the point where you want to add the attachment
attachment_data = attachment.tobytes() # get the document byte data as a buffer

# add the file annotation with the point, data and the file name
file_annotation = page.add_file_annot(point, attachment_data, "attachment.pdf")

doc.save("document-with-attachment.pdf") # save the document

注意

进一步了解

使用Page.add_file_annot() 添加文件时,请注意 filename 的第三个参数应包含实际文件扩展名。否则,附加的文件可能无法被识别为可打开的文件。例如,如果 filename 仅为“attachment”,则在查看生成的 PDF 并尝试打开附件时,您很可能会遇到错误。但是,如果使用“attachment.pdf”,PDF 阅读器可以将其识别并作为有效文件类型打开。

附件的默认图标是“图钉”,但是您可以通过设置 icon 参数来更改它。

API 参考


嵌入文件#

要向文档嵌入文件,请执行以下操作:

import pymupdf

doc = pymupdf.open("test.pdf") # open main document
embedded_doc = pymupdf.open("my-embed.pdf") # open document you want to embed

embedded_data = embedded_doc.tobytes() # get the document byte data as a buffer

# embed with the file name and the data
doc.embfile_add("my-embedded_file.pdf", embedded_data)

doc.save("document-with-embed.pdf") # save the document

注意

进一步了解

附加文件一样,使用Document.embfile_add() 添加文件时,请注意 filename 的第一个参数应包含实际文件扩展名。

API 参考


删除页面#

要从文档中删除页面,请执行以下操作:

import pymupdf

doc = pymupdf.open("test.pdf") # open a document
doc.delete_page(0) # delete the 1st page of the document
doc.save("test-deleted-page-one.pdf") # save the document

要从文档中删除多个页面,请执行以下操作:

import pymupdf

doc = pymupdf.open("test.pdf") # open a document
doc.delete_pages(from_page=9, to_page=14) # delete a page range from the document
doc.save("test-deleted-pages.pdf") # save the document

重新排列页面#

要更改页面的顺序(即重新排列页面),请执行以下操作:

import pymupdf

doc = pymupdf.open("test.pdf") # open a document
doc.move_page(1,0) # move the 2nd page of the document to the start of the document
doc.save("test-page-moved.pdf") # save the document

注意

API 参考


复制页面#

要复制页面,请执行以下操作:

import pymupdf

doc = pymupdf.open("test.pdf") # open a document
doc.copy_page(0) # copy the 1st page and puts it at the end of the document
doc.save("test-page-copied.pdf") # save the document

注意

API 参考


选择页面#

要选择页面,请执行以下操作:

import pymupdf

doc = pymupdf.open("test.pdf") # open a document
doc.select([0, 1]) # select the 1st & 2nd page of the document
doc.save("just-page-one-and-two.pdf") # save the document

注意

进一步了解

使用 PyMuPDF,您可以复制、移动、删除或重新排列 PDF 的页面。存在直观的方法,使您可以按页面级别执行此操作,例如Document.copy_page() 方法。

或者,您也可以准备一个完整的全新页面布局,形式为一个 Python 序列,其中包含您想要的页码,按您想要的顺序排列,并且每页可以出现任意多次。以下示例可能说明使用Document.select() 可以做什么:

doc.select([1, 1, 1, 5, 4, 9, 9, 9, 0, 2, 2, 2])

现在,让我们准备一个用于双面打印的 PDF(在不支持直接双面打印的打印机上):

页面数量由 len(doc) 给出(等于 doc.page_count)。以下列表分别代表偶数和奇数页码:

p_even = [p in range(doc.page_count) if p % 2 == 0]
p_odd  = [p in range(doc.page_count) if p % 2 == 1]

此代码片段创建相应的子文档,然后可以用于打印文档

doc.select(p_even) # only the even pages left over
doc.save("even.pdf") # save the "even" PDF
doc.close() # recycle the file
doc = pymupdf.open(doc.name) # re-open
doc.select(p_odd) # and do the same with the odd pages
doc.save("odd.pdf")

欲了解更多信息,请参阅此 Wiki 文章

以下示例将反转所有页面的顺序(非常快: 对于 Adobe PDF Reference 的 756 页文档,耗时不到一秒):

lastPage = doc.page_count - 1
for i in range(lastPage):
    doc.move_page(lastPage, i) # move current last page to the front

此代码片段将 PDF 与自身复制一遍,这样它将包含页面 0, 1, …, n, 0, 1, …, n (非常快,文件大小没有明显增加!)

page_count = len(doc)
for i in range(page_count):
    doc.copy_page(i) # copy this page to after last page

API 参考


添加空白页#

要添加空白页,请执行以下操作:

import pymupdf

doc = pymupdf.open(...) # some new or existing PDF document
page = doc.new_page(-1, # insertion point: end of document
                    width = 595, # page dimension: A4 portrait
                    height = 842)
doc.save("doc-with-new-blank-page.pdf") # save the document

注意

进一步了解

使用此方法创建具有其他预定义纸张格式的页面

w, h = pymupdf.paper_size("letter-l")  # 'Letter' landscape
page = doc.new_page(width = w, height = h)

便捷函数paper_size() 知道 40 多种行业标准纸张格式供您选择。要查看它们,请检查字典 paperSizes。将所需的字典键传递给paper_size() 以获取纸张尺寸。支持大小写。如果您在格式名称后附加“-L”,将返回横向版本。

这是一个 3 行代码,用于创建一个包含一个空白页面的 PDF 文件。其文件大小为 460 字节

doc = pymupdf.open()
doc.new_page()
doc.save("A4.pdf")

API 参考


插入包含文本内容的页面#

使用Document.insert_page() 方法也可以插入一个新页面,并接受相同的 widthheight 参数。但它也允许您在新页面中插入任意文本,并返回插入的行数。

import pymupdf

doc = pymupdf.open(...)  # some new or existing PDF document
n = doc.insert_page(-1, # default insertion point
                    text = "The quick brown fox jumped over the lazy dog",
                    fontsize = 11,
                    width = 595,
                    height = 842,
                    fontname = "Helvetica", # default font
                    fontfile = None, # any font file name
                    color = (0, 0, 0)) # text color (RGB)

注意

进一步了解

text 参数可以是一个(或多个)字符串(假定 UTF-8 编码)。插入将从Point (50, 72) 开始,即页面顶部下方一英寸、左侧 50 点的位置。返回插入的文本行数。

API 参考


拆分单页#

这涉及将 PDF 的页面任意拆分成多个部分。例如,您可能有一个包含 Letter 格式页面的 PDF,您想以四倍放大系数打印它:每页被拆分成 4 个部分,每个部分都将成为一个单独的 Letter 格式 PDF 页面。

import pymupdf

src = pymupdf.open("test.pdf")
doc = pymupdf.open()  # empty output PDF

for spage in src:  # for each page in input
    r = spage.rect  # input page rectangle
    d = pymupdf.Rect(spage.cropbox_position,  # CropBox displacement if not
                  spage.cropbox_position)  # starting at (0, 0)
    #--------------------------------------------------------------------------
    # example: cut input page into 2 x 2 parts
    #--------------------------------------------------------------------------
    r1 = r / 2  # top left rect
    r2 = r1 + (r1.width, 0, r1.width, 0)  # top right rect
    r3 = r1 + (0, r1.height, 0, r1.height)  # bottom left rect
    r4 = pymupdf.Rect(r1.br, r.br)  # bottom right rect
    rect_list = [r1, r2, r3, r4]  # put them in a list

    for rx in rect_list:  # run thru rect list
        rx += d  # add the CropBox displacement
        page = doc.new_page(-1,  # new output page with rx dimensions
                           width = rx.width,
                           height = rx.height)
        page.show_pdf_page(
                page.rect,  # fill all new page with the image
                src,  # input document
                spage.number,  # input page number
                clip = rx,  # which part to use of input page
            )

# that's it, save output file
doc.save("poster-" + src.name,
         garbage=3,  # eliminate duplicate objects
         deflate=True,  # compress stuff where possible
)

示例

_images/img-posterize.png

合并单页#

这涉及将 PDF 页面合并起来,形成一个新的 PDF,其中的页面各自组合了原始的两页或四页(也称为“2合1”、“4合1”等)。这可用于创建小册子或缩略图式概览。

import pymupdf

src = pymupdf.open("test.pdf")
doc = pymupdf.open()  # empty output PDF

width, height = pymupdf.paper_size("a4")  # A4 portrait output page format
r = pymupdf.Rect(0, 0, width, height)

# define the 4 rectangles per page
r1 = r / 2  # top left rect
r2 = r1 + (r1.width, 0, r1.width, 0)  # top right
r3 = r1 + (0, r1.height, 0, r1.height)  # bottom left
r4 = pymupdf.Rect(r1.br, r.br)  # bottom right

# put them in a list
r_tab = [r1, r2, r3, r4]

# now copy input pages to output
for spage in src:
    if spage.number % 4 == 0:  # create new output page
        page = doc.new_page(-1,
                      width = width,
                      height = height)
    # insert input page into the correct rectangle
    page.show_pdf_page(r_tab[spage.number % 4],  # select output rect
                     src,  # input document
                     spage.number)  # input page number

# by all means, save new file using garbage collection and compression
doc.save("4up.pdf", garbage=3, deflate=True)

示例

_images/img-4up.png

PDF 加密与解密#

从版本 1.16.0 开始,完全支持 PDF 解密和加密(使用密码)。您可以执行以下操作:

注意

PDF 文档可能有两种不同的密码

  • 所有者密码提供完全访问权限,包括更改密码、加密方法或权限详情。

  • 用户密码根据已建立的权限详情提供对文档内容的访问。如果存在,在阅读器中打开 PDF 将需要提供此密码。

Document.authenticate() 方法将根据使用的密码自动建立访问权限。

以下代码片段创建一个新的 PDF,并使用单独的用户密码和所有者密码对其进行加密。允许打印、复制和添加注释,但使用用户密码进行认证的用户不允许进行任何更改。

import pymupdf

text = "some secret information" # keep this data secret
perm = int(
    pymupdf.PDF_PERM_ACCESSIBILITY # always use this
    | pymupdf.PDF_PERM_PRINT # permit printing
    | pymupdf.PDF_PERM_COPY # permit copying
    | pymupdf.PDF_PERM_ANNOTATE # permit annotations
)
owner_pass = "owner" # owner password
user_pass = "user" # user password
encrypt_meth = pymupdf.PDF_ENCRYPT_AES_256 # strongest algorithm
doc = pymupdf.open() # empty pdf
page = doc.new_page() # empty page
page.insert_text((50, 72), text) # insert the data
doc.save(
    "secret.pdf",
    encryption=encrypt_meth, # set the encryption method
    owner_pw=owner_pass, # set the owner password
    user_pw=user_pass, # set the user password
    permissions=perm, # set permissions
)

注意

进一步了解

使用某些阅读器(例如 Nitro Reader 5)打开此文档将反映这些设置

_images/img-encrypting.jpg

如前所述,在未提供加密参数时,保存时将自动进行解密

保留 PDF 的加密方法,请使用 encryption=pymupdf.PDF_ENCRYPT_KEEP 进行保存。如果 doc.can_save_incrementally() == True,则也可以进行增量保存。

更改加密方法,请指定上述所有选项(encryption, owner_pw, user_pw, permissions)。在这种情况下,无法进行增量保存。

API 参考


从 Page 中提取表格#

可以从任何文档Page 中查找和提取表格。

import pymupdf
from pprint import pprint

doc = pymupdf.open("test.pdf") # open document
page = doc[0] # get the 1st page of the document
tabs = page.find_tables() # locate and extract any tables on page
print(f"{len(tabs.tables)} found on {page}") # display number of found tables

if tabs.tables:  # at least one table found?
   pprint(tabs[0].extract())  # print content of first table

注意

API 参考

重要

还有一个pdf2docx 提取表格方法,如果您更喜欢,也可以使用它来提取表格。


获取文档中的所有注释#

页面上的注释(Annot)可以使用 page.annots() 方法获取。

import pymupdf

for page in doc:
    for annot in page.annots():
        print(f'Annotation on page: {page.number} with type: {annot.type} and rect: {annot.rect}')

注意

API 参考


从 PDF 中涂黑(删除)内容#

密文处理是特殊类型的注释,可以标记在文档页面上,以指示页面上应安全移除的区域。使用矩形标记一个区域后,此区域将被标记为密文处理;一旦应用密文处理,内容将被安全移除。

例如,如果我们要从文档中涂黑(删除)所有出现的名字“Jane Doe”,我们可以执行以下操作:

import pymupdf

# Open the PDF document
doc = pymupdf.open('test.pdf')

# Iterate over each page of the document
for page in doc:
    # Find all instances of "Jane Doe" on the current page
    instances = page.search_for("Jane Doe")

    # Redact each instance of "Jane Doe" on the current page
    for inst in instances:
        page.add_redact_annot(inst)

    # Apply the redactions to the current page
    page.apply_redactions()

# Save the modified document
doc.save('redacted_document.pdf')

# Close the document
doc.close()

另一个示例可以是涂黑(删除)页面上的一个区域,但不对定义区域内的线条艺术(即矢量图形)进行涂黑(删除),通过按如下方式设置参数标志:

import pymupdf

# Open the PDF document
doc = pymupdf.open('test.pdf')

# Get the first page
page = doc[0]

# Add an area to redact
rect = [0,0,200,200]

# Add a redacction annotation which will have a red fill color
page.add_redact_annot(rect, fill=(1,0,0))

# Apply the redactions to the current page, but ignore vector graphics
page.apply_redactions(graphics=0)

# Save the modified document
doc.save('redactied_document.pdf')

# Close the document
doc.close()

警告

一旦保存了文档的密文处理版本,PDF 中的密文处理内容就不可恢复了。因此,文档中的密文处理区域会完全移除该区域的文本和图形。

注意

进一步了解

创建和应用密文处理到页面有几种选项,要了解控制这些选项的参数的完整 API 详情,请参阅 API 参考。

API 参考


转换 PDF 文档#

我们推荐pdf2docx 库,它使用 PyMuPDF 和 python-docx 库提供将 PDF 简单转换为 DOCX 格式的功能。


本软件按“原样”提供,不提供任何明示或默示保证。本软件根据许可协议分发,除非该许可协议条款明确授权,否则不得复制、修改或分发。有关许可信息,请参阅 artifex.com 或联系 Artifex Software Inc.,地址:39 Mesa Street, Suite 108A, San Francisco CA 94129, United States 以获取进一步信息。