首页 > 解决方案 > Python/wand 代码在转换大型 PDF 时导致“Killed”

问题描述

我一直在努力使用 Python 3.6.3 和 wand 库设置 PDF 转换为 png 和裁剪脚本。

我试过枕头,但它缺少转换部分。我正在尝试提取 alpha 通道,因为我想稍后将图像提供给 OCR,所以我转向尝试这个 SO answer中提供的代码。

出现了几个问题:第一个是如果文件很大,我会从终端收到一条“Killed”消息。第二个是文件看起来相当挑剔,即通过命令行中的 imagemagick 的 convert 或 pdftoppm 正确转换的文件,使用 wand 会引发错误。

不过,我最关心的是第一个,并且非常感谢知识渊博的编码人员的检查。我怀疑它可能来自循环的结构方式:

from wand.image import Image
from wand.color import Color


def convert_pdf(filename, path, resolution=300):
    all_pages = Image(filename=path+filename, resolution=resolution)
    for i, page in enumerate(all_pages.sequence):
        with Image(page) as img:
            img.format = 'png'
            img.background_color = Color('white')
            img.alpha_channel = 'remove'

            image_filename = '{}.png'.format(i)
            img.save(filename=path+image_filename)

我注意到脚本在进程结束时输出所有文件,而不是一个一个地输出,我猜这可能会给内存带来不必要的负担,并最终导致 SEGFAULT 或类似的东西。

感谢您查看我的问题以及任何提示。

标签: pythonwand

解决方案


是的,您的线路:

all_pages = Image(filename=path+filename, resolution=resolution)

将启动 GhostScript 进程以将整个 PDF 渲染为/tmp. 然后,Wand 会将那个庞大的文件加载到内存中,并在循环时从中分发页面。

MagickCore 的 C API 允许您指定要加载的页面,因此您可以一次渲染一个页面,但我不知道如何让 Python wand 接口来执行此操作。

你可以试试pyvips。它通过直接调用libpoppler以增量方式呈现 PDF ,因此没有正在启动和停止的进程,也没有临时文件。

例子:

#!/usr/bin/python3

import sys
import pyvips

def convert_pdf(filename, resolution=300):
    # n is number of pages to load, -1 means load all pages
    all_pages = pyvips.Image.new_from_file(filename, dpi=resolution, n=-1, \
            access="sequential")

    # That'll be RGBA ... flatten out the alpha
    all_pages = all_pages.flatten(background=255)

    # the PDF is loaded as a very tall, thin image, with the pages joined
    # top-to-bottom ... we loop down the image cutting out each page
    n_pages = all_pages.get("n-pages")
    page_width = all_pages.width
    page_height = all_pages.height / n_pages

    for i in range(0, n_pages):
        page = all_pages.crop(0, i * page_height, page_width, page_height) 
        print("writing {}.tif ..".format(i))
        page.write_to_file("{}.tif".format(i))

convert_pdf(sys.argv[1])

在这台带有巨大 PDF的 2015 年笔记本电脑上,我看到:

$ /usr/bin/time -f %M:%e ../pages.py ~/pics/Audi_US\ R8_2017-2.pdf 
writing 0.tif ..
writing 1.tif ..
....
writing 20.tif ..
720788:35.95

因此以 300dpi 渲染整个文档需要 35 秒,峰值内存使用量为 720MB。


推荐阅读