【问题标题】:Python subprocess: pipe an image blob to imagemagick shell commandPython 子进程:通过管道将图像 blob 传送到 imagemagick shell 命令
【发布时间】:2015-07-18 07:28:38
【问题描述】:

我在内存中有一个图像,我希望使用 Python 的 subprocess 执行 imagemagick 的 convert 方法。虽然这条线使用 Ubuntu 的终端运行良好:

cat image.png | convert - new_image.jpg

这段代码不能使用 Python:

jpgfile = Image.open('image.png');
proc = Popen(['convert', '-', 'new_image.jpg'], stdin=PIPE, shell=True)
print proc.communicate(jpgfile.tostring())

我还尝试在不使用 PIL 的情况下将图像作为常规文件读取,我尝试在 subprocess 方法和写入标准输入的不同方式之间切换。

最好的部分是,什么都没有发生,但我没有遇到真正的错误。打印标准输出时,我可以在终端上看到 imagemagick 帮助,然后是以下内容:

默认情况下,`file'的图片格式是由它的魔力决定的 数字。要指定特定的图像格式,请在文件名之前 带有图像格式名称和冒号(即 ps:image)或指定 图像类型作为文件名后缀(即 image.ps)。将“文件”指定为 '-' 用于标准输入或输出。 (无,无)

也许这里有我没有得到的提示。 请指出正确的方向,我是 Python 新手,但根据我使用 PHP 的经验,这应该是一项非常容易的任务,或者我希望如此。

编辑:

这是我最终用来处理 PIL 图像对象而不保存临时文件的解决方案。希望它可以帮助某人。 (在示例中,我从本地驱动器读取文件,但想法是从远程位置读取图像)

out = StringIO()
jpgfile = Image.open('image.png')
jpgfile.save(out, 'png', quality=100);
out.seek(0);
proc = Popen(['convert', '-', 'image_new.jpg'], stdin=PIPE)
proc.communicate(out.read())

【问题讨论】:

    标签: python image shell imagemagick subprocess


    【解决方案1】:

    导致任何问题的不是子进程,而是您传递给 imagemagick 的内容不正确,tostring() 确实传递给了imagemagick。如果你真的想复制 linux 命令,你可以从一个进程通过管道传输到另一个进程:

    from subprocess import Popen,PIPE
    proc = Popen(['cat', 'image.jpg'], stdout=PIPE)
    
    p2 = Popen(['convert', '-', 'new_image.jpg'],stdin=proc.stdout)
    
    proc.stdout.close()
    out,err = proc.communicate()
    
    print(out)
    

    当你传递一个不需要 shell=True 的 args 列表时,如果你想使用 shell=True,你将传递一个字符串:

    from subprocess import check_call
    check_call('cat image.jpg | convert - new_image.jpg',shell=True)
    

    通常我会避免shell=Trueanswer 概述了 shell=True 的作用。

    您还可以将文件对象传递给标准输入:

    with open('image.jpg') as jpgfile:
        proc = Popen(['convert', "-", 'new_image.jpg'], stdin=jpgfile)
    
    out, err = proc.communicate()
    
    print(out)
    

    但是当代码成功运行时没有输出,您可以使用 check_call 如果存在非零退出状态,您可以捕获并采取适当的操作,这将引发 CalledProcessError:

    from subprocess import check_call, CalledProcessError
    
    
    with open('image.jpg') as jpgfile:
        try:
            check_call(['convert', "-", 'new_image.jpg'], stdin=jpgfile)
        except CalledProcessError as e:
            print(e.message)
    

    如果您想使用通信写入标准输入,您还可以使用 .read 传递文件内容:

    with  open('image.jpg') as jpgfile:
         proc = Popen(['convert', '-', 'new_image.jpg'], stdin=PIPE)
         proc.communicate(jpgfile.read())
    

    如果您不想将图像存储在磁盘上,请使用tempfile:

    import tempfile
    import requests
    
    r = requests.get("http://www.reptileknowledge.com/images/ball-python.jpg")
    out = tempfile.TemporaryFile()
    out.write(r.content)
    out.seek(0)
    
    from subprocess import check_call
    check_call(['convert',"-", 'new_image.jpg'], stdin=out)
    

    使用CStringIo.StringIO 对象:

    import requests
    
    r = requests.get("http://www.reptileknowledge.com/images/ball-python.jpg")
    out = cStringIO.StringIO(r.content)
    
    from subprocess import check_call,Popen,PIPE
    p = Popen(['convert',"-", 'new_image.jpg'], stdin=PIPE)
    
    p.communicate(out.read())
    

    【讨论】:

    • 这对我没有帮助,因为我想从内存中传递图像不必在磁盘上创建物理副本。您所有的示例都与读取图像文件有关。尝试将图像对象传递给标准输入不起作用,正如我在问题中描述的那样,没有任何反应。
    • 那么图片来自哪里?
    • 我使用代理通过 HTTP 读取图像,并且我想使用 blob 本身来创建图像的优化版本,而无需将原始图像保存在磁盘上。我知道在使用其他编程语言时这应该不是问题,我不知道如何使用 Python 来实现它。
    • 谢谢!我使用了一个稍微不同的解决方案,因为我需要使用 PIL 图像对象,但你的回答肯定让我朝着正确的方向前进。
    • @iMoses,别担心,我不完全确定数据的来源,但我认为逻辑大致相同。
    猜你喜欢
    • 1970-01-01
    • 2016-03-19
    • 1970-01-01
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-11
    相关资源
    最近更新 更多