【问题标题】:Python: Optimizing Images in Memory (StringIO & POpen with jpegoptim)Python:优化内存中的图像(StringIO & POpen with jpegoptim)
【发布时间】:2015-02-25 03:59:51
【问题描述】:

我正在尝试使用各种库的 STDIN 版本(本示例中为 jpegoptim)在不接触磁盘的情况下压缩图像。

此代码不返回优化的(jpegoptim 压缩)图像。

有人可以帮助或解释为什么 Popen() 与 StringIO.StringIO() 对象的这种用法不会返回图像的优化版本吗?如果我将文件保存到磁盘,它工作得很好。

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()))

【问题讨论】:

  • 仅供参考,标准输入功能需要 jpegoptim 1.4+。

标签: python popen stringio jpegoptim


【解决方案1】:

这是因为您正在写入相同的输入缓冲区。创建一个新的 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'

【讨论】:

    【解决方案2】:

    有几个问题:

    1. 不正确覆盖StringIO() 缓冲区pointed out by @doog abides 的问题
    2. 使用len 而不是sys.getsizeof()。后者返回内存中内部表示的大小不等于字节串中的字节数

    3. Don't use a list argument and shell=True together

    您可以将套接字作为标准输入传递给某些系统上的子进程:

    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 未设置以避免隐藏错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-21
      • 2014-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多