1

I'm trying to compress images without touching disk using the STDIN version of various libraries(jpegoptim in this example).

This code does not return an optimized(jpegoptim compressed) image.

Can someone please help or explain why this usage of Popen() with a StringIO.StringIO() object does not return the optimized version of the image? If I save the file to disk, it works just fine.

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

2 に答える 2

2

これは、同じ入力バッファに書き込んでいるためです。新しい 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'
于 2015-02-25T04:36:06.500 に答える
1

いくつかの問題があります。

  1. @doog が指摘しStringIO()たバッファの誤った上書きの問題
  2. lenの代わりに使用しsys.getsizeof()ます。後者は、バイト文字列のバイト数と等しくないメモリ内の内部表現のサイズを返します

  3. shell=Trueリスト引数と一緒に使用しないでください

一部のシステムでは、ソケットを標準入力としてサブプロセスに渡すことができます。

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エラーを非表示にしないように設定されていません。

于 2015-02-25T16:26:32.453 に答える