From c68044bf7fa63f7e6642393cb4ea344753c34d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Cuenca=20Abela?= Date: Fri, 2 Aug 2013 14:36:46 +0200 Subject: [PATCH] Fix IOError when saving progressive JPEGs. when the jpeg encoder sees the flags optimize or progressive (or progression) it will write the full image in one shot. The bufsize needs to be big enough to hold the entire image. The current heuristic is that the entire compressed image will fit in width * height bytes, but this heuristic is only applied to save operations with the flag "optimize" and not to save operations with the flag "progressive". This patch fixes this oversight. (Btw, it will probably be a good idea to have a loop that retries with a bigger bufsize in case this guess is not big enough.) --- PIL/JpegImagePlugin.py | 4 ++-- Tests/test_file_jpeg.py | 30 +++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/PIL/JpegImagePlugin.py b/PIL/JpegImagePlugin.py index deb2cd2bf..a8eb1b805 100644 --- a/PIL/JpegImagePlugin.py +++ b/PIL/JpegImagePlugin.py @@ -561,11 +561,11 @@ def _save(im, fp, filename): # is a value that's been used in a django patch. # https://github.com/jdriscoll/django-imagekit/issues/50 bufsize=0 - if "optimize" in info: + if "optimize" in info or "progressive" in info or "progression" in info: bufsize = im.size[0]*im.size[1] # 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 bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif",b"")) + 5 ) ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)], bufsize) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 1027d0174..de1c3f0e1 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -114,17 +114,29 @@ def test_optimize(): assert_true(im1.bytes >= im2.bytes) def test_optimize_large_buffer(): - #https://github.com/python-imaging/Pillow/issues/148 - f = tempfile('temp.jpg') - # this requires ~ 1.5x Image.MAXBLOCK - im = Image.new("RGB", (4096,4096), 0xff3333) - im.save(f, format="JPEG", optimize=True) + #https://github.com/python-imaging/Pillow/issues/148 + f = tempfile('temp.jpg') + # this requires ~ 1.5x Image.MAXBLOCK + im = Image.new("RGB", (4096,4096), 0xff3333) + im.save(f, format="JPEG", optimize=True) + +def test_progressive(): + im1 = roundtrip(lena()) + im2 = roundtrip(lena(), progressive=True) + assert_image_equal(im1, im2) + assert_true(im1.bytes >= im2.bytes) + +def test_progressive_large_buffer(): + f = tempfile('temp.jpg') + # this requires ~ 1.5x Image.MAXBLOCK + im = Image.new("RGB", (4096,4096), 0xff3333) + im.save(f, format="JPEG", progressive=True) def test_large_exif(): - #https://github.com/python-imaging/Pillow/issues/148 - f = tempfile('temp.jpg') - im = lena() - im.save(f,'JPEG', quality=90, exif=b"1"*65532) + #https://github.com/python-imaging/Pillow/issues/148 + f = tempfile('temp.jpg') + im = lena() + im.save(f,'JPEG', quality=90, exif=b"1"*65532) def test_progressive(): im1 = roundtrip(lena())