From 93a8bc9bd3e3b7e44df4a0b44ce9fc798d7b0b17 Mon Sep 17 00:00:00 2001 From: David Schmidt Date: Wed, 4 Dec 2013 15:07:36 +0100 Subject: [PATCH 1/8] * fix palette handling for converted gifs * fix gif optimization * better auto convert paramter for gif save --- PIL/GifImagePlugin.py | 12 ++++++++---- PIL/ImagePalette.py | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/PIL/GifImagePlugin.py b/PIL/GifImagePlugin.py index aed525824..8882f9beb 100644 --- a/PIL/GifImagePlugin.py +++ b/PIL/GifImagePlugin.py @@ -237,7 +237,10 @@ def _save(im, fp, filename): # convert on the fly (EXPERIMENTAL -- I'm not sure PIL # should automatically convert images on save...) if Image.getmodebase(im.mode) == "RGB": - imOut = im.convert("P") + palette_size = 256 + if im.palette: + palette_size = len(im.palette.getdata()[1]) // 3 + imOut = im.convert("P", palette=1, colors=palette_size) rawmode = "P" else: imOut = im.convert("L") @@ -248,9 +251,7 @@ def _save(im, fp, filename): palette = im.encoderinfo["palette"] except KeyError: palette = None - if im.palette: - # use existing if possible - palette = im.palette.getdata()[1] + im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True) header, usedPaletteColors = getheader(imOut, palette, im.encoderinfo) for s in header: @@ -391,6 +392,9 @@ def getheader(im, palette=None, info=None): for i in range(len(imageBytes)): imageBytes[i] = newPositions[imageBytes[i]] im.frombytes(bytes(imageBytes)) + newPaletteBytes = paletteBytes + (768 - len(paletteBytes)) * b'\x00' + im.putpalette(newPaletteBytes) + im.palette = ImagePalette.ImagePalette("RGB", palette = paletteBytes, size = len(paletteBytes)) if not paletteBytes: paletteBytes = sourcePalette diff --git a/PIL/ImagePalette.py b/PIL/ImagePalette.py index 61affdb19..d5b9d04eb 100644 --- a/PIL/ImagePalette.py +++ b/PIL/ImagePalette.py @@ -23,13 +23,14 @@ from PIL import Image, ImageColor class ImagePalette: "Color palette for palette mapped images" - def __init__(self, mode = "RGB", palette = None): + def __init__(self, mode = "RGB", palette = None, size = 0): self.mode = mode self.rawmode = None # if set, palette contains raw data self.palette = palette or list(range(256))*len(self.mode) self.colors = {} self.dirty = None - if len(self.mode)*256 != len(self.palette): + if ((size == 0 and len(self.mode)*256 != len(self.palette)) or + (size != 0 and size != len(self.palette))): raise ValueError("wrong palette size") def getdata(self): From 232c175bd92320100f891d0d9874cf8230a19b1b Mon Sep 17 00:00:00 2001 From: David Schmidt Date: Wed, 5 Feb 2014 12:49:06 +0100 Subject: [PATCH 2/8] fixes #513 --- PIL/PngImagePlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PIL/PngImagePlugin.py b/PIL/PngImagePlugin.py index a6038d9f2..30fdfb8ac 100644 --- a/PIL/PngImagePlugin.py +++ b/PIL/PngImagePlugin.py @@ -505,7 +505,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0): else: # check palette contents if im.palette: - colors = len(im.palette.getdata()[1])//3 + colors = max(len(im.im.getpalette("RGB"))//3, 256) else: colors = 256 From 6457eed2cbedfd785df8579933d0ced0f6729df2 Mon Sep 17 00:00:00 2001 From: David Schmidt Date: Wed, 5 Feb 2014 13:49:08 +0100 Subject: [PATCH 3/8] overwrite redundant Image palette with new ImageCore Palette after quantize, fixes #513 --- PIL/Image.py | 5 ++++- PIL/PngImagePlugin.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index e71e2ad5f..442393a9e 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -734,7 +734,10 @@ class Image: if mode == "P" and palette == ADAPTIVE: im = self.im.quantize(colors) - return self._new(im) + new = self._new(im) + from PIL import ImagePalette + new.palette = ImagePalette.raw("RGB", new.im.getpalette("RGB")) + return new # colorspace conversion if dither is None: diff --git a/PIL/PngImagePlugin.py b/PIL/PngImagePlugin.py index 30fdfb8ac..d72a9c141 100644 --- a/PIL/PngImagePlugin.py +++ b/PIL/PngImagePlugin.py @@ -505,7 +505,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0): else: # check palette contents if im.palette: - colors = max(len(im.im.getpalette("RGB"))//3, 256) + colors = max(min(len(im.palette.getdata()[1])//3, 256), 2) else: colors = 256 From a77ee2d8c56c07ebf97adde4677d821cb7229ae0 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 4 Mar 2014 21:43:11 -0800 Subject: [PATCH 4/8] Fix test failure when optimizing the palette on mode L gifs --- PIL/GifImagePlugin.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/PIL/GifImagePlugin.py b/PIL/GifImagePlugin.py index 8882f9beb..c6d449425 100644 --- a/PIL/GifImagePlugin.py +++ b/PIL/GifImagePlugin.py @@ -252,6 +252,12 @@ def _save(im, fp, filename): except KeyError: palette = None im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True) + if im.encoderinfo["optimize"]: + # When the mode is L, and we optimize, we end up with + # im.mode == P and rawmode = L, which fails. + # If we're optimizing the palette, we're going to be + # in a rawmode of P anyway. + rawmode = 'P' header, usedPaletteColors = getheader(imOut, palette, im.encoderinfo) for s in header: From ae5bcb8e84ba26383dcedeac41f6cf833bcde199 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 4 Mar 2014 22:02:03 -0800 Subject: [PATCH 5/8] Test for issue #513 --- Tests/test_file_gif.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 3a6478e2a..7c4428a44 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -46,3 +46,20 @@ def test_roundtrip2(): assert_image_similar(reread.convert('RGB'), lena(), 50) +def test_palette_handling(): + # see https://github.com/python-imaging/Pillow/issues/513 + + im = Image.open('Images/lena.gif') + im = im.convert('RGB') + + im = im.resize((100,100), Image.ANTIALIAS) + im2 = im.convert('P', palette=Image.ADAPTIVE, colors=256) + + f = tempfile('temp.gif') + im2.save(f, optimize=True) + + reloaded = Image.open(f) + + assert_image_similar(im, reloaded.convert('RGB'), 10) + + From 1706e59d1c3ef8f54581948fb1d17b3399455e05 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 4 Mar 2014 22:02:22 -0800 Subject: [PATCH 6/8] cleanup tempfile --- Tests/test_file_gif.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 7c4428a44..2dcd904ff 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -38,7 +38,7 @@ def test_roundtrip(): def test_roundtrip2(): #see https://github.com/python-imaging/Pillow/issues/403 - out = 'temp.gif'#tempfile('temp.gif') + out = tempfile('temp.gif') im = Image.open('Images/lena.gif') im2 = im.copy() im2.save(out) From 226fd2e8a8f0b1a4f5ce44537ea29bbe17b94ecc Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 4 Mar 2014 22:29:27 -0800 Subject: [PATCH 7/8] Changes updated --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index ae917acb1..b06e1eca5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,9 @@ Changelog (Pillow) 2.4.0 (2014-04-01 est.) ------------------ +- Fixed palette handling when converting from mode P->RGB->P + [d_schmidt] + - Fixed DOS with invalid palette size or invalid image size in BMP file [wiredfool] From 0fc225c358a45419b547271ca2b6ad27d544d673 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 4 Mar 2014 22:29:55 -0800 Subject: [PATCH 8/8] test for issue #434 --- Tests/images/test.colors.gif | Bin 0 -> 17855 bytes Tests/test_file_gif.py | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 Tests/images/test.colors.gif diff --git a/Tests/images/test.colors.gif b/Tests/images/test.colors.gif new file mode 100644 index 0000000000000000000000000000000000000000..0faf96760bd07e176449d278325fc3e2feeb2a63 GIT binary patch literal 17855 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 literal 0 HcmV?d00001 diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 2dcd904ff..4318e178e 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -46,6 +46,7 @@ def test_roundtrip2(): assert_image_similar(reread.convert('RGB'), lena(), 50) + def test_palette_handling(): # see https://github.com/python-imaging/Pillow/issues/513 @@ -62,4 +63,25 @@ def test_palette_handling(): assert_image_similar(im, reloaded.convert('RGB'), 10) +def test_palette_434(): + # see https://github.com/python-imaging/Pillow/issues/434 + + def roundtrip(im, *args, **kwargs): + out = tempfile('temp.gif') + im.save(out, *args, **kwargs) + reloaded = Image.open(out) + + return [im, reloaded] + + orig = "Tests/images/test.colors.gif" + im = Image.open(orig) + + assert_image_equal(*roundtrip(im)) + assert_image_equal(*roundtrip(im, optimize=True)) + + im = im.convert("RGB") + # check automatic P conversion + reloaded = roundtrip(im)[1].convert('RGB') + assert_image_equal(im, reloaded) +