使用mupdf处理PDF中的图片
将获取文档文件名并从其每个页面生成一个 PNG 文件。
文档可以是任何受支持的类型,如 PDF、XPS 等。
该脚本用作命令行工具,需要将文件名作为参数提供。生成的图像文件(每页 1 个)存储在脚本的目录中:
脚本目录现在将包含名为page-0.png、page-1.png等的 PNG 图像文件。图片具有页面尺寸,宽度和高度四舍五入为整数,例如,A4 纵向尺寸页面为 595 x 842 像素. 它们在 x 和 y 维度上的分辨率为 96 dpi,并且没有透明度。你可以改变这一切——关于如何做到这一点,请阅读下一节。
如何增加图像分辨率
文档页面的图像由 Pixmap 表示,创建像素图的最简单方法是通过方法 Page.get_pixmap()
。
此方法有许多选项会影响结果。其中最重要的是矩阵,它可以让你缩放、旋转、扭曲或镜像结果。
Page.get_pixmap()
默认情况下将使用单位矩阵,它什么也不做。
下面,我们应用一个每个维度的缩放因子为 2,这将为我们生成分辨率提高四倍的图像(大小也是大约 4 倍):
从版本 1.19.2 开始,有一种更直接的方法来设置分辨率:"dpi"
可以使用参数(每英寸点数)代替"matrix"
. 要创建页面的 300 dpi 图像,请指定. 除了符号简洁之外,这种方法还有一个额外的优点,即dpi 值与图像文件一起保存——这在使用矩阵符号时不会自动发生。pix = page.get_pixmap(dpi=300)
如何创建部分像素图(剪辑)
并不总是需要或想要页面的完整图像。例如,当您在 GUI 中显示图像并希望用页面的缩放部分填充相应窗口时就是这种情况。
假设您的 GUI 窗口有足够的空间来显示完整的文档页面,但您现在想用页面的右下四分之一填充这个空间,从而使用四倍更好的分辨率。
为此,定义一个等于您希望在 GUI 中显示的区域的矩形,并将其称为“剪辑”。在 PyMuPDF 中构造矩形的一种方法是提供两个对角相对的角,这就是我们在这里所做的。

在上面我们通过指定两个对角线相对的点来构造剪辑:页面矩形的中点mp和它的右下角rect.br。
如何将剪辑缩放到 GUI 窗口
这次我们要计算剪辑的缩放系数,使其图像最适合给定的 GUI 窗口。这意味着图像的宽度或高度(或两者)将等于窗口尺寸。对于以下代码片段,您需要提供应该接收页面剪辑矩形的 GUI 窗口的宽度和高度。
在这种情况下,我们有zoom = HEIGHT/clip.height = WIDTH/clip.width,所以我们必须设置clip.height = HEIGHT/zoom和,clip.width = WIDTH/zoom。
选择页面上剪辑的左上角点tl来计算右侧像素图:
如何创建或删除注释图像
通常情况下,一个页面的像素图也会显示该页面的注释。偶尔,这可能是不可取的。
要抑制渲染页面上的注释图像,只需在Page.get_pixmap()中指定annots=False。
你也可以单独渲染注释:它们有自己的Annot.get_pixmap()方法。得到的像素图与注释矩形的尺寸相同。
如何提取图像:非 PDF 文档
与前面的部分不同,本部分涉及提取文档中包含的图像,因此它们可以显示为一页或多页的一部分。
如果你想以文件形式或作为内存区域重新创建原始图像,你基本上有两个选择:
将文档转换为 PDF,然后使用其中一种仅限 PDF 的提取方法。此代码段会将文档转换为 PDF:
Page.get_text()
与“dict”参数一起使用。这适用于所有文档类型。它将提取页面上显示的所有文本和图像,格式化为 Python 字典。每个图像都将出现在一个图像块中,包含元信息和二进制图像数据。有关字典结构的详细信息,请参阅TextPage。该方法同样适用于 PDF 文件。这将创建页面上显示的所有图像的列表:
如何提取图像:PDF 文档
xref
与 PDF 中的任何其他“对象”一样,图像由交叉引用编号(整数)标识。如果你知道这个数字,你有两种方法来访问图像的数据:
使用指令pix = fitz.Pixmap(doc, xref)创建图像的像素图。这种方法非常快(单位数微秒)。像素图的属性(宽度、高度……)将反映图像的属性。在这种情况下,无法判断嵌入的原件具有哪种图像格式。
使用img = doc.extract_image(xref)提取图像。这是一个包含二进制图像数据的字典img[“image”]。还提供了许多元数据——大部分与您在图像的像素图中找到的相同。主要区别在于字符串img[“ext”],它指定图像格式:除了“png”之外,还可以出现“jpeg”、“bmp”、“tiff”等字符串。如果要存储到磁盘,请使用此字符串作为文件扩展名。此方法的执行速度应与语句pix = fitz.Pixmap(doc, xref);pix.tobytes()的组合速度进行比较。如果嵌入的图像是PNG格式,速度
Document.extract_image()
大致相同(并且二进制图像数据相同)。否则,这种方法要快上千倍,而且图像数据要小得多。
问题仍然存在:“我怎么知道那些‘外部参照’图像的数量?” . 对此有两个答案:
“检查页面对象:”循环遍历
Page.get_images()
. 它是一个列表的列表,它的项目看起来像[xref, smask, …],包含xref
图像的。然后可以将其xref
与上述方法之一一起使用。将此方法用于有效(未损坏)的文档。但是请注意,同一图像可能会被多次引用(由不同的页面),因此您可能希望提供一种避免多次提取的机制。“不需要知道:”循环遍历文档的所有外部参照列表并
Document.extract_image()
为每个外部参照执行一个。如果返回的字典为空,则继续——这xref
不是图像。如果 PDF 已损坏(无法使用的页面),请使用此方法。请注意,PDF 通常包含“伪图像”(“模板掩码”),其特殊目的是定义其他图像的透明度。您可能希望提供逻辑以将那些排除在提取之外。另请参阅下一节。
如何处理图像遮罩
PDF 中的某些图像带有图像遮罩。在最简单的形式中,蒙版表示存储为单独图像的 alpha(透明度)字节。为了重建具有掩码的图像的原始图像,必须使用从其掩码中提取的透明度字节来“丰富”它。
在 PyMuPDF 中,可以通过以下两种方式之一识别图像是否具有此类掩码:
Document.get_page_images()的一个项目具有一般的格式(xref, smask, ...),其中xref是图像的xref,smask如果是正数,那么它就是一个掩码的xref。
Document.extract_image()的(字典)结果有一个键 "smask",如果是正数,它也包含任何掩码的xref。
如果smask == 0那么 via 遇到的图像xref
可以原样处理。
要使用 PyMuPDF 恢复原始图像,必须执行如下描述的过程:

步骤 (1) 创建基本图像的像素图。步骤 (2) 对图像蒙版执行相同的操作。步骤 (3) 添加一个 alpha 通道并用透明度信息填充它。
如何将所有图片(或文件)制作成一个 PDF
我们在这里展示了三个脚本,它们获取(图像和其他)文件列表并将它们全部放在一个 PDF 中。
方法 1:将图像作为页面插入
第一个将每个图像转换为具有相同尺寸的 PDF 页面。结果将是一个 PDF,每个图像一页。它仅适用于支持的图像文件格式:
这将生成仅略大于组合图片大小的 PDF。关于性能的一些数字:
上面的脚本在我的机器上需要大约 1 分钟的时间来处理 149 张总大小为 514 MB 的图片(生成的 PDF 大小大致相同)。
我们可能使用了Page.insert_image()
而不是Page.show_pdf_page()
,结果将是一个外观相似的文件。但是,根据图像类型,它可能会存储未压缩的图像。因此,必须使用保存选项deflate = True来获得合理的文件大小,这会大大增加大量图像的运行时间。所以这里不推荐这个替代方案。
方法二:嵌入文件
第二个脚本嵌入任意文件——不仅仅是图像。由于技术原因,生成的 PDF 将只有一个(空)页面。要稍后再次访问嵌入文件,您需要一个合适的 PDF 查看器来显示和/或提取嵌入文件:
这是迄今为止最快的方法,而且它还能生成尽可能小的输出文件。上面的图片在我的机器上需要 20 秒,生成的 PDF 大小为 510 MB。
方法 3:附加文件
完成此任务的第三种方法是通过页面注释附加文件。
这与之前的脚本具有相似的性能,并且生成的文件大小也相似。它将生成 PDF 页面,其中为每个附加文件显示一个“FileAttachment”图标。
embed和attach方法都可以用于任意文件——而不仅仅是图像。
强烈建议使用很棒的包PySimpleGUI来显示可能运行较长时间跨度的任务的进度表。它是纯 Python,并且只需要多一行代码!
如何创建矢量图像
从文档页面创建图像的常用方法是Page.get_pixmap()
. 像素图表示光栅图像,因此您必须在创建时决定其质量(即分辨率)。以后不能更改。
PyMuPDF 还提供了一种以 SVG 格式(可缩放矢量图形,以 XML 语法定义)创建页面矢量图像的方法。SVG 图像在缩放级别上保持精确(当然,嵌入其中的任何光栅图形元素除外)。
指令svg = page.get_svg_image(matrix=fitz.Identity)提供一个 UTF-8 字符串svg,可以使用扩展名“.svg”存储。
如何转换图像
正如其他功能一样,PyMuPDF的图像转换很容易。在许多情况下,它可能会避免使用其他图形包,如PIL/Pillow。
Input Formats Output Formats Description
BMP . Windows Bitmap
JPEG . Joint Photographic Experts Group
JXR . JPEG Extended Range
JPX/JP2 . JPEG 2000
GIF . Graphics Interchange Format
TIFF . Tagged Image File Format
PNG PNG Portable Network Graphics
PNM PNM Portable Anymap
PGM PGM Portable Graymap
PBM PBM Portable Bitmap
PPM PPM Portable Pixmap
PAM PAM Portable Arbitrary Map
. PSD Adobe Photoshop Document
. PS Adobe Postscript
总体方案仅为以下两条线路:
备注
fitz.Pixmap(arg)的输入参数可以是包含图像的文件或字节/io.BytesIO对象。
可以通过pix.tobytes(“yyy”)创建一个字节对象,而不是输出文件,并将其传递出去。
当然,输入和输出格式必须在颜色空间和透明度方面兼容。
将 JPEG 转换为 Photoshop:
使用 PIL/Pillow保存为 JPEG :
将JPEG 转换为 Tkinter PhotoImage。任何RGB / no-alpha图像都完全相同。转换为一种便携式 Anymap格式(PPM、PGM 等)就可以了,因为所有 Tkinter 版本都支持它们:
将带有 alpha 的 PNG转换为 Tkinter PhotoImage。这需要删除 alpha 字节,然后我们才能进行 PPM 转换:
如何使用像素图:粘贴图像
这显示了如何将像素图用于纯图形、非文档目的。该脚本读取一个图像文件并创建一个由 3 * 4 个原始图块组成的新图像:

如何使用像素图:制作分形
这是另一个创建Sierpinski’s Carpet 的像素图示例——将Cantor Set推广到二维的分形。给定一张方形carpet,标记它的 9 个小方格(3 乘以 3)并剪下中间的方格。其余八个子方格,每一个都以同样的方式处理,无限继续下去。最终结果是一个面积为零且分形维数为 1.8928 的集合……
该脚本通过缩小到一个像素的粒度,将其近似图像创建为 PNG。要提高图像精度,请更改 n(精度)的值:

如何与 NumPy 交互
这显示了如何从 numpy 数组创建 PNG 文件(比大多数其他方法快几倍):
如何将图像添加到 PDF 页面
有两种方法可以将图像添加到 PDF 页面:Page.insert_image()
和Page.show_pdf_page()
。两种方法有共同点,但也有不同点。

基本代码模式Page.insert_image()
。如果不重新插入现有图像,则必须给出参数filename / stream / pixmap中的一个:
基本代码模式Page.show_pdf_page()
。源 PDF 和目标 PDF 必须是不同的文档对象(但可以从同一文件打开):
如何使用像素图:检查文本可见性
一段给定的文本在页面上是否实际可见取决于许多因素:
文本未被其他对象覆盖,但可能具有与背景相同的颜色,即白底白字等。
文本可能被图像或矢量图形覆盖。检测这是一项重要的能力,例如发现严重匿名的法律文件。
文本创建为隐藏。OCR 工具通常使用此技术将已识别的文本存储在页面上的不可见层中。
下面展示如何检测上面的情况1,或者情况2,如果覆盖物体是单色的:
方法Pixmap.color_topusage()返回一个元组(比率,像素),其中0<比率<=1,像素是颜色的像素值。请注意,我们只创建一个pixmap一次。如果有多个命中的矩形,这可以节省大量的处理时间。
上述代码的逻辑是:如果针的矩形是("almost":>95%)单色的,那么文本就不能被看到。一个典型的可见文本的结果是返回背景的颜色(大部分是白色)和一个大约0.7到0.8的比率,例如(0.685,b'xffxffxff')。