Adjust buffer size when icc_profile > MAXBLOCK (issue #148)

We were encountering some errors when saving specific JPEG images.
The error was shown in stderr as:
  IOError: encoder error -2 when writing image file

And on stdout it printed:
    Suspension not allowed here

The problem was the bufsize not contemplating the icc_profile block.
This commit is contained in:
Fran Barba 2017-06-27 15:31:52 +02:00
parent 633d751bdc
commit ebaa509d66
3 changed files with 18 additions and 2 deletions

View File

@ -732,8 +732,9 @@ def _save(im, fp, filename):
bufsize = im.size[0] * im.size[1] bufsize = im.size[0] * im.size[1]
# The exif info needs to be written as one block, + APP1, + one spare byte. # The exif info needs to be written as one block, + APP1, + one spare byte.
# Ensure that our buffer is big enough # Ensure that our buffer is big enough. Same with the icc_profile block.
bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5) bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5,
len(extra) + 1)
ImageFile._save(im, fp, [("jpeg", (0, 0)+im.size, 0, rawmode)], bufsize) ImageFile._save(im, fp, [("jpeg", (0, 0)+im.size, 0, rawmode)], bufsize)

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 KiB

View File

@ -133,6 +133,21 @@ class TestFileJpeg(PillowTestCase):
test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte
test(ImageFile.MAXBLOCK*4+3) # large block test(ImageFile.MAXBLOCK*4+3) # large block
def test_large_icc_meta(self):
# https://github.com/python-pillow/Pillow/issues/148
# Sometimes the meta data on the icc_profile block is biger than
# Image.MAXBLOCK or the image size.
im = Image.open('Tests/images/icc_profile_big.jpg')
f = self.tempfile("temp.jpg")
icc_profile = im.info["icc_profile"]
try:
im.save(f, format='JPEG', progressive=True,quality=95,
icc_profile=icc_profile, optimize=True)
assert True
except IOError:
assert False, "Failed saving image with icc larger than image size"
def test_optimize(self): def test_optimize(self):
im1 = self.roundtrip(hopper()) im1 = self.roundtrip(hopper())
im2 = self.roundtrip(hopper(), optimize=0) im2 = self.roundtrip(hopper(), optimize=0)