Python 子进程:将图像 blob 通过管道传输到 imagemagick shell 命令
Python subprocess: pipe an image blob to imagemagick shell command
我在内存中有一个图像,我希望使用 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 帮助,然后是以下内容:
By default, the image format of `file' is determined by its magic
number. To specify a particular image format, precede the filename
with an image format name and a colon (i.e. ps:image) or specify the
image type as the filename suffix (i.e. image.ps). Specify 'file' as
'-' for standard input or output. (None, None)
也许这里有我没有得到的提示。
请指出正确的方向,我是 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())
导致任何问题的不是子进程,而是您传递给 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,如果您想使用 shell=True,您将传递一个字符串:
from subprocess import check_call
check_call('cat image.jpg | convert - new_image.jpg',shell=True)
通常我会避免 shell=True
。 answer 概括了 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)
如果您想使用 communicate 写入标准输入,您也可以使用 .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())
我在内存中有一个图像,我希望使用 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 帮助,然后是以下内容:
By default, the image format of `file' is determined by its magic number. To specify a particular image format, precede the filename with an image format name and a colon (i.e. ps:image) or specify the image type as the filename suffix (i.e. image.ps). Specify 'file' as '-' for standard input or output. (None, None)
也许这里有我没有得到的提示。 请指出正确的方向,我是 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())
导致任何问题的不是子进程,而是您传递给 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,如果您想使用 shell=True,您将传递一个字符串:
from subprocess import check_call
check_call('cat image.jpg | convert - new_image.jpg',shell=True)
通常我会避免 shell=True
。 answer 概括了 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)
如果您想使用 communicate 写入标准输入,您也可以使用 .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())