常见问题及其解决方案#
如何动态清理损坏的 PDF 文件#
这展示了 PyMuPDF 与另一个 Python PDF 库(此处以优秀的纯 Python 包 pdfrw 为例)的潜在用法。
如果需要一个干净、未损坏/解压缩的 PDF 文件,可以动态调用 PyMuPDF 来解决许多问题,如下所示
import sys
from io import BytesIO
from pdfrw import PdfReader
import pymupdf
#---------------------------------------
# 'Tolerant' PDF reader
#---------------------------------------
def reader(fname, password = None):
idata = open(fname, "rb").read() # read the PDF into memory and
ibuffer = BytesIO(idata) # convert to stream
if password is None:
try:
return PdfReader(ibuffer) # if this works: fine!
except:
pass
# either we need a password or it is a problem-PDF
# create a repaired / decompressed / decrypted version
doc = pymupdf.open("pdf", ibuffer)
if password is not None: # decrypt if password provided
rc = doc.authenticate(password)
if not rc > 0:
raise ValueError("wrong password")
c = doc.tobytes(garbage=3, deflate=True)
del doc # close & delete doc
return PdfReader(BytesIO(c)) # let pdfrw retry
#---------------------------------------
# Main program
#---------------------------------------
pdf = reader("pymupdf.pdf", password = None) # include a password if necessary
print pdf.Info
# do further processing
使用命令行工具 pdftk(仅适用于 Windows,但据报道也可在 Wine 下运行)可以实现类似的结果,参见此处。但是,您必须通过 subprocess.Popen 将其作为单独的进程调用,使用 stdin 和 stdout 作为通信媒介。
如何将任何文档转换为 PDF#
这是一个将任何 PyMuPDF 支持的文档 转换为 PDF 的脚本。这些文档包括 XPS、EPUB、FB2、CBZ 和图像格式,以及多页 TIFF 图像。
它具有保留源文档中包含的任何元数据、目录和链接的功能
"""
Demo script: Convert input file to a PDF
-----------------------------------------
Intended for multi-page input files like XPS, EPUB etc.
Features:
---------
Recovery of table of contents and links of input file.
While this works well for bookmarks (outlines, table of contents),
links will only work if they are not of type "LINK_NAMED".
This link type is skipped by the script.
For XPS and EPUB input, internal links however **are** of type "LINK_NAMED".
Base library MuPDF does not resolve them to page numbers.
So, for anyone expert enough to know the internal structure of these
document types, can further interpret and resolve these link types.
Dependencies
--------------
PyMuPDF v1.14.0+
"""
import sys
import pymupdf
if not (list(map(int, pymupdf.VersionBind.split("."))) >= [1,14,0]):
raise SystemExit("need PyMuPDF v1.14.0+")
fn = sys.argv[1]
print("Converting '%s' to '%s.pdf'" % (fn, fn))
doc = pymupdf.open(fn)
b = doc.convert_to_pdf() # convert to pdf
pdf = pymupdf.open("pdf", b) # open as pdf
toc= doc.get_toc() # table of contents of input
pdf.set_toc(toc) # simply set it for output
meta = doc.metadata # read and set metadata
if not meta["producer"]:
meta["producer"] = "PyMuPDF v" + pymupdf.VersionBind
if not meta["creator"]:
meta["creator"] = "PyMuPDF PDF converter"
meta["modDate"] = pymupdf.get_pdf_now()
meta["creationDate"] = meta["modDate"]
pdf.set_metadata(meta)
# now process the links
link_cnti = 0
link_skip = 0
for pinput in doc: # iterate through input pages
links = pinput.get_links() # get list of links
link_cnti += len(links) # count how many
pout = pdf[pinput.number] # read corresp. output page
for l in links: # iterate though the links
if l["kind"] == pymupdf.LINK_NAMED: # we do not handle named links
print("named link page", pinput.number, l)
link_skip += 1 # count them
continue
pout.insert_link(l) # simply output the others
# save the conversion result
pdf.save(fn + ".pdf", garbage=4, deflate=True)
# say how many named links we skipped
if link_cnti > 0:
print("Skipped %i named links of a total of %i in input." % (link_skip, link_cnti))
更改注释:意外行为#
问题#
有两种情况
使用 PyMuPDF 更新 由其他软件创建的注释。
使用 PyMuPDF 创建 注释,然后使用其他软件更改它。
在这两种情况下,您都可能遇到意外的更改,例如注释图标或文本字体不同、填充颜色或线条虚线消失、线条末端符号大小改变甚至消失等。
原因#
每个 PDF 维护应用程序处理注释维护的方式不同。某些注释类型可能不受支持,或者不支持完全,或者某些细节的处理方式可能与另一个应用程序不同。没有标准。
几乎所有 PDF 应用程序都带有自己的图标(文件附件、便笺和图章)以及自己支持的文本字体集。例如
(Py-) MuPDF 对“自由文本”注释只支持这 5 种基本字体:Helvetica、Times-Roman、Courier、ZapfDingbats 和 Symbol – 不支持斜体/粗体变体。当更改由其他应用程序创建的“自由文本”注释时,其字体可能不会被识别或接受,并被替换为 Helvetica。
PyMuPDF 支持所有 PDF 文本标记(高亮、下划线、删除线、波浪线),但这些类型无法通过 Adobe Acrobat Reader 进行更新。
在大多数情况下,线条虚线支持也有限,这会导致现有的虚线被直线替换。例如
PyMuPDF 完全支持所有线条虚线形式,而其他查看器只接受有限的子集。
解决方案#
不幸的是,在大多数情况下,您无能为力。
创建和更改注释时,请始终使用同一软件。
当使用 PyMuPDF 更改“外部”注释时,请尽量避免使用
Annot.update()
。以下方法无需使用它即可使用,这样可以保留原始外观
Annot.set_rect()
(位置更改)
Annot.set_flags()
(注释行为)
Annot.set_info()
(元信息,除了对 content 的更改)
Annot.set_popup()
(创建弹出窗口或更改其矩形区域)
Annot.set_oc()
(添加/移除对可选内容信息的引用)
Annot.update_file()
(文件附件更改)
丢失或不可读的提取文本#
文本提取通常不像您期望的那样工作:文本可能丢失,或可能不按屏幕上可见的阅读顺序出现,或包含乱码字符(如 ? 或“豆腐块”符号)等。这可能由许多不同的问题引起。
问题:未提取到文本#
您的 PDF 查看器显示文本,但您无法用光标选择它,并且文本提取结果为空。
原因#
您看到的可能是嵌入在 PDF 页面中的图像(例如扫描的 PDF)。
PDF 创建者没有使用字体,而是通过绘制小线条和曲线来模拟文本。例如,大写字母“D”可以通过一条线“|”和一个左开口的半圆绘制,字母“o”通过一个椭圆绘制,依此类推。
解决方案#
使用像 OCRmyPDF 这样的 OCR 软件在可见页面下方插入一个隐藏的文本层。生成的 PDF 应该会按预期工作。
问题:文本不可读#
文本提取的结果文本顺序不可读、某些文本重复或出现乱码。
原因#
单个字符本身是可读的(没有“<?>”符号),但文本在文件中编码的顺序与阅读顺序不符。这可能是出于技术原因或为了防止数据被未经授权复制。
出现许多“<?>”符号,这表明 MuPDF 无法解释这些字符。字体可能确实不受 MuPDF 支持,或者 PDF 创建者可能使用了显示可读文本的字体,但故意混淆了原始的对应 Unicode 字符。
解决方案#
使用保留布局的文本提取:
python -m fitz gettext file.pdf
。如果其他文本提取工具也不起作用,那么唯一的解决方案仍然是对页面进行 OCR 识别。