Python:优化内存中的图像(使用 jpegoptim 的 StringIO 和 POpen)
Python: Optimizing Images in Memory (StringIO & POpen with jpegoptim)
我正在尝试使用各种库的 STDIN 版本(本例中为 jpegoptim)在不接触磁盘的情况下压缩图像。
此代码不return 优化(jpegoptim 压缩)图像。
有人可以帮助或解释为什么 Popen() 与 StringIO.StringIO() 对象的这种用法不是 return 图像的优化版本吗?如果我将文件保存到磁盘,它就可以正常工作。
import sys
import urllib2 as urllib
import StringIO
from subprocess import Popen, PIPE, STDOUT
fp = urllib.urlopen('http://www.path.to/unoptimized.jpg')
out_im2 = StringIO.StringIO(fp.read()) # StringIO Image
print "Image Size: %s" % format(sys.getsizeof(out_im2.getvalue()))
subp = Popen(["/usr/bin/jpegoptim", "-"], shell=True, stdout=PIPE, stdin=PIPE, stderr=STDOUT)
image_str = subp.communicate(input=out_im2.getvalue())[0]
out_im2.write(image_str)
##This should be a different size if it worked! It's not
print "Compressed JPG: %s" % format(sys.getsizeof(out_im2.getvalue()))
这是因为您正在写入同一个输入缓冲区。创建一个新的 StringIO().
StringIO 缓冲区最初扩展为第一个未压缩的 jpeg 的大小。然后你用新的较短的字符串缓冲区从 0 位置开始覆盖那个缓冲区,但它不会自动截断你的缓冲区或任何东西。 StringIO 缓冲区的大小仍然相同,实际上所有尾随数据都将留在原始图像中。
In [1]: import StringIO
In [2]: out = StringIO.StringIO("abcdefg")
In [3]: out.getvalue()
Out[3]: 'abcdefg'
In [4]: out.write("123")
In [5]: out.getvalue()
Out[5]: '123defg'
有几个问题:
- 错误覆盖
StringIO()
缓冲区的问题
使用 len
而不是 sys.getsizeof()
。后者returns内存中内部表示的大小不等于bytestring中的字节数
您可以将套接字作为标准输入传递给某些系统上的子进程:
import socket
from urllib2 import urlopen
from subprocess import check_output
saved = socket._fileobject.default_bufsize
socket._fileobject.default_bufsize = 0 # hack to disable buffering
try:
fp = urlopen('http://www.path.to/unoptimized.jpg')
finally:
socket._fileobject.default_bufsize = saved # restore back
# urlopen() has read http headers; subprocess can read the body now
image_bytes = check_output(["/usr/bin/jpegoptim", "-"], stdin=fp)
fp.close()
# use `image_bytes` bytestring here..
stderr
未设置,避免隐藏错误
我正在尝试使用各种库的 STDIN 版本(本例中为 jpegoptim)在不接触磁盘的情况下压缩图像。
此代码不return 优化(jpegoptim 压缩)图像。
有人可以帮助或解释为什么 Popen() 与 StringIO.StringIO() 对象的这种用法不是 return 图像的优化版本吗?如果我将文件保存到磁盘,它就可以正常工作。
import sys
import urllib2 as urllib
import StringIO
from subprocess import Popen, PIPE, STDOUT
fp = urllib.urlopen('http://www.path.to/unoptimized.jpg')
out_im2 = StringIO.StringIO(fp.read()) # StringIO Image
print "Image Size: %s" % format(sys.getsizeof(out_im2.getvalue()))
subp = Popen(["/usr/bin/jpegoptim", "-"], shell=True, stdout=PIPE, stdin=PIPE, stderr=STDOUT)
image_str = subp.communicate(input=out_im2.getvalue())[0]
out_im2.write(image_str)
##This should be a different size if it worked! It's not
print "Compressed JPG: %s" % format(sys.getsizeof(out_im2.getvalue()))
这是因为您正在写入同一个输入缓冲区。创建一个新的 StringIO().
StringIO 缓冲区最初扩展为第一个未压缩的 jpeg 的大小。然后你用新的较短的字符串缓冲区从 0 位置开始覆盖那个缓冲区,但它不会自动截断你的缓冲区或任何东西。 StringIO 缓冲区的大小仍然相同,实际上所有尾随数据都将留在原始图像中。
In [1]: import StringIO
In [2]: out = StringIO.StringIO("abcdefg")
In [3]: out.getvalue()
Out[3]: 'abcdefg'
In [4]: out.write("123")
In [5]: out.getvalue()
Out[5]: '123defg'
有几个问题:
- 错误覆盖
StringIO()
缓冲区的问题 使用
len
而不是sys.getsizeof()
。后者returns内存中内部表示的大小不等于bytestring中的字节数
您可以将套接字作为标准输入传递给某些系统上的子进程:
import socket
from urllib2 import urlopen
from subprocess import check_output
saved = socket._fileobject.default_bufsize
socket._fileobject.default_bufsize = 0 # hack to disable buffering
try:
fp = urlopen('http://www.path.to/unoptimized.jpg')
finally:
socket._fileobject.default_bufsize = saved # restore back
# urlopen() has read http headers; subprocess can read the body now
image_bytes = check_output(["/usr/bin/jpegoptim", "-"], stdin=fp)
fp.close()
# use `image_bytes` bytestring here..
stderr
未设置,避免隐藏错误