我有一个文件夹,里面有600 个 PDF 文件,每个 PDF 有20 页。我需要尽快将每页转换为高质量的 PNG 。
我为此任务编写了以下脚本:
import os
import multiprocessing
import fitz # PyMuPDF
from PIL import Image
def process_pdf(pdf_path, output_folder):
try:
pdf_name = os.path.splitext(os.path.basename(pdf_path))[0]
pdf_output_folder = os.path.join(output_folder, pdf_name)
os.makedirs(pdf_output_folder, exist_ok=True)
doc = fitz.open(pdf_path)
for i, page in enumerate(doc):
pix = page.get_pixmap(dpi=850) # Render page at high DPI
img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
img_path = os.path.join(pdf_output_folder, f"page_{i+1}.png")
img.save(img_path, "PNG")
print(f"Processed: {pdf_path}")
except Exception as e:
print(f"Error processing {pdf_path}: {e}")
def main():
input_folder = r"E:\Desktop\New folder (5)\New folder (4)"
output_folder = r"E:\Desktop\New folder (5)\New folder (5)"
pdf_files = [os.path.join(input_folder, f) for f in os.listdir(input_folder) if f.lower().endswith(".pdf")]
with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
pool.starmap(process_pdf, [(pdf, output_folder) for pdf in pdf_files])
print("All PDFs processed successfully!")
if __name__ == "__main__":
main()
问题:
这个脚本太慢了,特别是在处理大量 PDF 时。我尝试了以下优化,但速度并没有显著提高:
- 稍微降低 DPI – 从1200 DPI降低到850 DPI。(我也测试了 600-800 DPI。)
- 启用 – 减少内存使用量
alpha=False
。get_pixmap()
- 用来
ThreadPoolExecutor
代替multiprocessing.Pool
– 没有重大改进。 - 减少 PNG 压缩
optimize=False
–保存图像时设置。 - 将图像转换为灰度- 有点帮助,但我的任务需要彩色图像。
我考虑过的可能的解决方案:
- 并行处理页面而不是文件——不是一次处理一个文件,而是并行处理每个页面以充分利用 CPU 核心。
- 使用
ProcessPoolExecutor
而不是ThreadPoolExecutor
– 由于渲染是CPU 密集型的,因此多处理应该更好。 - 使用 JPEG 而不是 PNG – JPEG保存速度更快,占用存储空间更少,但我需要高质量的图像。
- 将 DPI 降低至 500-600 – 在速度和质量之间实现平衡。
- 批量写入文件而不是逐个保存- 减少 I/O 开销。
我需要帮助:
- 如何在保持高图像质量的同时显著加快PDF 到 PNG 的转换速度 ?
- 是否有更好的库或技术我应该使用?
- 有没有办法可以充分利用 CPU 内核?
任何建议都将不胜感激!
此过程不仅高度占用 CPU,还需要大量 RAM。在 MacOS (M2) 上,仅使用 4 个 CPU(即可用数量的一半)即可显著提高性能。即便如此,处理页面的平均时间约为 1.3 秒
为了进行这次测试,我有 80 个 PDF。每个 PDF 最多处理 20 页。
测试如下:
不包括文件名的输出:
Average duration per page = 1.2667s
概括:
使用fitz / PyMuPDF以 850dpi 进行渲染很慢。将渲染降低到例如 300dpi 可将每页时间缩短至约 0.17 秒
安装 Ghost 脚本工具
您可以从此站点下载 Ghost Script PDF 到图像转换软件 -> https://ghostscript.com/releases/gsdnld.html
在您的系统上安装该软件。
安装 Ghost Script Python Wrapper
然后,你需要一个 Python 工具来调用我们在上一步中安装的 SDK 中的 PDF 到图像转换函数,该工具名为ghostscript。运行命令pip install ghostscript
使用以下 Python 代码进行转换
PDF 转换自然很慢,因此仅使用 9 x 20 页文件(因为生命太短暂)。几分钟应该足以计时 9 个文件,因为只有 180 页。
这些是原始可执行 CLI 时间,没有任何 Python 开销。结果总是会有所不同,具体取决于单个图形处理器,因此具有多线程 GPU 的专用工作站将胜过我的值。因此,仅提供用于比较相同的 20 KB pdf(因此图表的文本大致压缩为每页 1 KB)作为相对“exe 与 exe”测试。
以下是基于 PDF 打印到图像/纸张设备的一些时间安排,传统上认为每分钟 60 页的速度很高。
为了进行比较,我使用了 Artifex GS 和 MuPDF。让我们展示一下 MuPdf 的最终读取时间,因为它们最容易报告,而且速度也更快。
第 1 页和第 19 页的内容实际上非常相似。但是,读取压缩 PDF 所需的时间各不相同。这里大约需要半秒到整整 1 秒,这是因为必须在(在这个 20 页的 PDF 中)近 140 个离散压缩对象之间来回遍历。单页 PDF 应该更快,而且“来回”次数不会明显减少。具有解压缩内容的较小 PDF 总是比大压缩图像 PDF 更好。
那么涉及哪些时间限制和矩形体积?
因此 Mu PDF 应该可以节省一个小时的时间。
那么 Python 应用程序中使用的其他常用工具呢?文件自然会更慢,因为通常会被显著压缩(大约是 MuPDF 大小的 -40%)。
许多建议说使用多线程,并且上述 MuPDF 时间基于 4 个线程,如果我们更改该设置会怎样?
因此,无需在 3 个或更多线程之间共享时间,即可使用此双核设备上的 2 个线程来改善连续渲染时间。
再稍微调整一下,我们就可以得到
180 pages = 64.54 seconds
因此,600 个以上 20 页的文件 = 4,302.66 秒 = 预计 1 小时 12 分钟。
在缓慢的 Windows
for
循环中:下面是一个示例脚本,它使用 Python 多处理将 PDF 的所有页面渲染为图像。您可以预期总体上比线性执行快 2-4 倍: