【问题标题】:Python/wand code causes "Killed" when converting large PDFs转换大型 PDF 时,Python/wand 代码会导致“Killed”
【发布时间】:2019-01-30 16:44:15
【问题描述】:

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

我试过 Pillow,但它缺少转换部分。我正在尝试提取 alpha 通道,因为我想稍后将图像提供给 OCR,所以我转而尝试this 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 或类似情况。

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

【问题讨论】:

    标签: python wand


    【解决方案1】:

    是的,你的台词:

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

    将启动 GhostScript 进程以将整个 PDF 渲染为 /tmp 中的一个巨大的临时 PNM 文件。然后,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])
    

    在这台带有this huge 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。

    【讨论】:

    • 太好了,谢谢。会玩一下,然后返回反馈和/或接受。
    • 叹息...我尝试了您的解决方案@jcupitt,但我碰壁了。显然 pyvips does not run well in Anaconda,我不够专业,无法尝试在虚拟环境中构建它。非常感谢您的帮助,我会喜欢 pyvips 的效率。
    • 嗯,好的,是的,没有用于 libvips 的 Anaconda 包。它有自己的原生二进制文件系统,不能使用标准包。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 2015-03-05
    • 2013-12-24
    • 2013-09-14
    • 2015-02-18
    • 2021-12-14
    相关资源
    最近更新 更多