基础#

打开文件#

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

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 可以提取文本 - 所有 支持的文档文件格式,如 MOBIEPUBTXT 都可以提取其文本。

注意

进一步探讨

如果您的文档包含基于图像的文本内容,请在页面上使用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文档,您可以将页面范围从一个复制到另一个。您可以选择复制的页面应该放置的位置,可以反转页面顺序,还可以改变页面旋转。这篇Wiki 文章包含了完整的描述。

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文件中,例如一个logo,执行以下操作:

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")

有关更多信息,您还可以查看这篇维基文章

以下示例将反转所有页面的顺序 (极快:Adobe PDF References 的 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”,将返回横向版本。

这里有一个创建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)

注意

进一步探讨

文本参数可以是字符串(假设为UTF-8编码)的(序列)。插入将从(50, 72)开始,该点距离页面顶部一英寸,距离左侧50个点。返回插入的文本行数。

API 参考


拆分单页#

这处理了将一个PDF页面分割成任意部分。例如,您可能有一个格式为LetterPDF文件,您想以四倍的放大倍率打印:每个页面被分成4个部分,每个部分再次转到一个单独的PDF页面,格式为Letter

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-up”、“4-up”等)。这可以用于创建小册子或缩略图式的概述。

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 参考


页面提取表格#

可以从任何文档中找到并提取表格

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 extract tables method,如果您愿意,它可以进行表格提取。


从文档中获取所有注释#

页面上的注释 (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库,该库使用PyMuPDFpython-docx库提供PDF到DOCX格式的简单文档转换。


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