PyMuPDF 1.24.4 中文文档(五)(4)https://developer.aliyun.com/article/1559439
更改注释:意外行为
问题
存在两种情况:
- 使用 PyMuPDF 更新 由其他软件创建的注释。
- 使用 PyMuPDF 创建 注释,稍后用其他软件更改它。
在这两种情况下,可能会发生意外更改,如不同的注释图标或文本字体,填充颜色或线型消失,线段末端符号大小变化甚至消失等等。
原因
每个 PDF 维护应用程序处理注释维护的方式不同。某些注释类型可能不受支持,或者不完全支持,或者某些细节可能以与另一个应用程序不同的方式处理。没有标准。
几乎每个 PDF 应用程序都配有自己的图标(文件附件、便笺和印章)以及自己支持的文本字体集。例如:
- (Py-)MuPDF 仅支持这 5 种基本字体的‘FreeText’注释:Helvetica、Times-Roman、Courier、ZapfDingbats 和 Symbol - 没有斜体/粗体变体。当更改由其他应用程序创建的‘FreeText’注释时,其字体可能不会被识别或接受,会被替换为 Helvetica。
- PyMuPDF 支持所有 PDF 文本标记(高亮、下划线、删除线、波浪线),但这些类型无法在 Adobe Acrobat Reader 中更新。
大多数情况下,对线段破折号的支持也有限,这会导致现有的虚线被直线替换。例如:
- PyMuPDF 完全支持所有线段破折号形式,而其他查看器仅接受有限的子集。
解决方案
不幸的是,在大多数情况下,你无能为力。
- 使用相同软件来创建和更改注释。
- 当使用 PyMuPDF 更改“外部”注释时,尽量避免使用
Annot.update()
。以下方法无需此操作,可以保持原始外观:
Annot.set_rect()
(位置变更)Annot.set_flags()
(注释行为)Annot.set_info()
(元信息,除内容之外的更改)Annot.set_popup()
(创建弹出窗口或更改其矩形)Annot.set_optional_content()
(添加/移除可选内容信息的引用)Annot.set_open()
Annot.update_file()
(文件附件更改)
丢失或无法读取的提取文本
文本提取经常不按预期工作:文本可能丢失,或者不会出现在屏幕上可见的阅读顺序中,或者包含乱码字符(如问号或“TOFU”符号)等。这可能由多种不同问题引起。
问题:未提取到任何文本
你的 PDF 查看器显示文本,但无法用光标选择它,文本提取结果为空。
原因
- 你可能在 PDF 页面中看到嵌入的图像(例如扫描的 PDF)。
- PDF 创建者未使用字体,而是通过绘制使用小线条和曲线来模拟文本。例如,一个大写的“D”可能是通过一条“|”和一个左开放的半圆绘制,一个“o”可能是通过一个椭圆绘制,依此类推。
解决方案
使用 OCR 软件如 OCRmyPDF 在可见页面下方插入隐藏文本层。生成的 PDF 应如预期般运行。
问题:无法阅读的文本
文本提取未按可读顺序交付文本,重复某些文本或以其他方式混乱。
原因
- 单个字符可读取(无“<?>”符号),但文件中的文本编码顺序与阅读顺序不符合。背后的动机可能是技术性的或用于保护数据免受未经授权的复制。
- 许多“<?>”符号出现,表明 MuPDF 无法解释这些字符。字体可能确实不受 MuPDF 支持,或者 PDF 创建者可能使用了一种显示可读文本但有意混淆对应 Unicode 字符的字体。
解决方案
- 使用保留布局的文本提取:
python -m fitz gettext file.pdf
。 - 如果其他文本提取工具也不起作用,那么唯一的解决方案还是对页面进行 OCR 处理。
您对本页面有什么反馈吗?
本软件按原样提供,不附带任何明示或暗示的担保。本软件根据许可证分发,未经许可不得复制、修改或分发。请参阅许可信息,详情请访问 artifex.com 或联系美国加利福尼亚州旧金山 Mesa 街 39 号 108A 套房的 Artifex Software Inc. 以获取更多信息。
此文档涵盖所有版本,直至 1.24.4。
如何动态清理损坏的 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))
如何处理 MuPDF 发出的消息
自 PyMuPDF v1.16.0 以来,由底层 MuPDF 库发出的 错误消息 已重定向到 Python 标准设备 sys.stderr。因此,您可以像处理此设备上的任何其他输出一样处理它们。
此外,这些消息与 MuPDF 警告一起发送到内部缓冲区 – 请参阅下文。
我们始终用标识字符串 “mupdf:” 前缀这些消息。如果您希望根本不看到可恢复的 MuPDF 错误,请发出命令 pymupdf.TOOLS.mupdf_display_errors(False)
。
MuPDF 警告继续存储在内部缓冲区中,并且可以使用Tools.mupdf_warnings()
查看。
请注意,MuPDF 的错误可能会导致 Python 异常,也可能不会。换句话说,您可能会看到 MuPDF 可以恢复并继续处理的错误消息。
可恢复错误的示例输出。我们正在打开一个受损的 PDF,但 MuPDF 能够修复它,并且为我们提供了一些关于发生了什么的信息。然后,我们说明如何查明文档是否可以随后以增量方式保存。在此时检查Document.is_dirty
属性还表明,pymupdf.open
期间必须对文档进行修复:
>>> import pymupdf >>> doc = pymupdf.open("damaged-file.pdf") # leads to a sys.stderr message: mupdf: cannot find startxref >>> print(pymupdf.TOOLS.mupdf_warnings()) # check if there is more info: cannot find startxref trying to repair broken xref repairing PDF document object missing 'endobj' token >>> doc.can_save_incrementally() # this is to be expected: False >>> # the following indicates whether there are updates so far >>> # this is the case because of the repair actions: >>> doc.is_dirty True >>> # the document has nevertheless been created: >>> doc pymupdf.Document('damaged-file.pdf') >>> # we now know that any save must occur to a new file
不可恢复错误的示例输出:
>>> import pymupdf >>> doc = pymupdf.open("does-not-exist.pdf") mupdf: cannot open does-not-exist.pdf: No such file or directory Traceback (most recent call last): File "<pyshell#1>", line 1, in <module> doc = pymupdf.open("does-not-exist.pdf") File "C:\Users\Jorj\AppData\Local\Programs\Python\Python37\lib\site-packages\fitz\pymupdf.py", line 2200, in __init__ _pymupdf.Document_swiginit(self, _pymupdf.new_Document(filename, stream, filetype, rect, width, height, fontsize)) RuntimeError: cannot open does-not-exist.pdf: No such file or directory >>>
更改注释:意外行为
问题
存在两种场景:
- 使用 PyMuPDF 更新由其他软件创建的注释。
- 使用 PyMuPDF 创建 注释,然后使用其他软件更改它。
在这两种情况下,您可能会遇到意外的变化,比如不同的注释图标或文本字体,填充颜色或线条虚线消失,线条末尾符号的大小已更改或甚至也已消失等。
原因
每个 PDF 维护应用程序对注释维护的处理方式各不相同。某些注释类型可能不受支持,或者支持不完全,或者某些细节可能与其他应用程序处理方式不同。没有标准。
几乎每个 PDF 应用程序还配有自己的图标(文件附件、便笺和图章)和一组支持的文本字体。例如:
- (Py-)MuPDF 仅支持‘FreeText’注释的这 5 种基本字体:Helvetica,Times-Roman,Courier,ZapfDingbats 和 Symbol – 没有斜体/加粗变体。当更改由其他应用程序创建的‘FreeText’注释时,其字体可能不会被识别或接受,并被 Helvetica 替换。
- PyMuPDF 支持所有 PDF 文本标记(高亮、下划线、删除线、波浪线),但这些类型无法与 Adobe Acrobat Reader 一起更新。
在大多数情况下,线条虚线的支持也是有限的,这导致现有虚线被直线替换。例如:
- PyMuPDF 完全支持所有线条虚线形式,而其他查看器只接受有限的子集。
解决方案
不幸的是,在大多数情况下,您无法做太多事情。
- 建议您使用相同的软件创建和更改注释。
- 当使用 PyMuPDF 更改一个“外来”注释时,请尽量避免使用
Annot.update()
。以下方法可以在没有它的情况下使用,以保持原始外观:
Annot.set_rect()
(位置更改)Annot.set_flags()
(注释行为)Annot.set_info()
(元信息,除了内容更改)Annot.set_popup()
(创建弹出窗口或更改其矩形)Annot.set_optional_content()
(添加/删除可选内容信息的引用)Annot.set_open()
Annot.update_file()
(文件附件更改)
问题
有两种情况:
- 使用 PyMuPDF 更新由其他软件创建的注释。
- 使用 PyMuPDF 创建注释,然后使用其他软件更改它。
在这两种情况下,您可能会遇到意外的更改,比如不同的注释图标或文本字体,填充颜色或线条虚线已经消失,线段终止符号改变了大小甚至也消失了,等等。
原因
每个 PDF 维护应用程序都以不同的方式处理注释维护。某些注释类型可能不受支持,或者支持不完全,或者某些细节可能以与另一个应用程序不同的方式处理。没有标准。
几乎每个 PDF 应用程序都配备了自己的图标(文件附件、便笺和印章)和自己支持的文本字体。例如:
- (Py-)MuPDF 仅支持这 5 种基本字体用于“FreeText”注释:Helvetica、Times-Roman、Courier、ZapfDingbats 和 Symbol – 没有斜体/粗体变体。当更改其他应用程序创建的“FreeText”注释时,其字体可能无法识别或接受,并被替换为 Helvetica。
- PyMuPDF 支持所有 PDF 文本标记(高亮、下划线、删除线、波浪线),但这些类型无法使用 Adobe Acrobat Reader 更新。
大多数情况下,线条虚线也存在有限的支持,这会导致现有的虚线被直线替换。例如:
- PyMuPDF 完全支持所有线条虚线形式,而其他查看器只接受有限的子集。
解决方案
不幸的是,在大多数情况下,您无法做太多事情。
- 建议您使用相同的软件创建和更改注释。
- 当使用 PyMuPDF 更改一个“外来”的注释时,请尽量避免使用
Annot.update()
。以下方法可以在没有它的情况下使用,以便保持原始外观:
Annot.set_rect()
(位置更改)Annot.set_flags()
(注释行为)Annot.set_info()
(元信息,不包括内容的更改)Annot.set_popup()
(创建弹出窗口或更改其位置)Annot.set_optional_content()
(添加/删除可选内容信息)Annot.set_open()
Annot.update_file()
(文件附件更改)
未提取到或无法读取的文本
文本提取经常不按您期望的方式工作:可能缺少文本,或者在屏幕上可见的阅读顺序中没有出现,或者包含乱码字符(如?或“TOFU”符号)等。这可能由多种不同的问题引起。
问题:未提取到文本
您的 PDF 查看器显示文本,但无法用鼠标选择它,文本提取结果为空。
原因
- 可能您正在查看嵌入在 PDF 页面中的图像(例如扫描的 PDF)。
- PDF 创建者未使用字体,而是通过绘制使用小线条和曲线来模拟文本。例如,一个大写的“D”可以通过一条竖线“|”和一个左开的半圆来绘制,“o”可以通过一个椭圆来绘制,等等。
解决方案
使用像OCRmyPDF这样的 OCR 软件,在可见页面下方插入一个隐藏文本层。生成的 PDF 应该按预期方式工作。
问题:不可读文本
文本提取未按可读顺序提供文本,重复了一些文本,或者其他情况下乱码。
原因
- 单个字符可直接阅读(没有“<?>”符号),但文件中编码的顺序与阅读顺序不同。这背后的动机可能是技术性的或为了保护数据免受未经授权的复制。
- 许多“<?>”符号出现,表明 MuPDF 无法解释这些字符。字体可能确实不受 MuPDF 支持,或者 PDF 创建者可能使用了一种显示可读文本但故意混淆原始对应 Unicode 字符的字体。
解决方案
- 使用保留布局的文本提取:
python -m fitz gettext file.pdf
。 - 如果其他文本提取工具也不起作用,那么唯一的解决方案再次是对页面进行 OCR。
对本页面有任何反馈吗?
本软件按原样提供,不提供任何明示或暗示的担保。本软件根据许可证分发,并且未经明确授权不得复制、修改或分发。有关详细信息,请参阅许可信息,网址为artifex.com,或联系美国旧金山 94129 号,Mesa 街 39 号 108A 套房的 Artifex Software Inc.。
本文档覆盖所有版本,直至 1.24.4。
问题:未提取任何文本
您的 PDF 查看器显示文本,但您不能用光标选择它,且文本提取无效。
原因
- 您可能在 PDF 页面中嵌入了图像(例如扫描过的 PDF)。
- PDF 创建者未使用任何字体,而是通过绘制使用小线条和曲线来模拟文本。例如,大写字母“D”可以由一条竖线“|”和一个左开弧组成,“o”可以由一个椭圆组成,依此类推。
解决方案
使用 OCR 软件像OCRmyPDF在可见页面下插入一个隐藏的文本层。生成的 PDF 应按预期工作。
问题:无法阅读的文本
文本提取未按可读顺序提供文本,复制了部分文本,或者内容混乱。
原因
- 这些单个字符可读性良好(无“<?>”符号),但文件中编码的文本顺序与阅读顺序不同。其动机可能是技术性的或为了保护数据免受未经授权的复制。
- 出现许多“<?>”符号,表明 MuPDF 无法解释这些字符。该字体可能确实不受 MuPDF 支持,或者 PDF 创建者可能使用了一种显示可读文本但故意混淆原始对应 Unicode 字符的字体。
解决方案
- 使用保留布局的文本提取:
python -m fitz gettext file.pdf
。 - 如果其他文本提取工具也无法正常工作,则唯一的解决方案是再次对页面进行 OCR 处理。
对本页有任何反馈意见吗?
本软件按原样提供,不提供任何明示或暗示的担保。本软件根据许可证分发,并且未经明确授权不得复制、修改或分发。有关详细信息,请参阅许可信息,网址为artifex.com,或联系美国旧金山 94129 号,Mesa 街 39 号 108A 套房的 Artifex Software Inc.。
本文档覆盖所有版本,直至 1.24.4。