From 7371e813f6a768a24f8e4cb7ae39cea5a4d7f29a Mon Sep 17 00:00:00 2001 From: hugovk Date: Sat, 4 Mar 2017 19:52:49 +0200 Subject: [PATCH 1/8] pngtopam hopper.png | pamtoxvmini > hopper.p7 --- Tests/images/hopper.p7 | Bin 0 -> 16445 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Tests/images/hopper.p7 diff --git a/Tests/images/hopper.p7 b/Tests/images/hopper.p7 new file mode 100644 index 0000000000000000000000000000000000000000..474b233d52cf4e2a4cd3775cb2a084f015656742 GIT binary patch literal 16445 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 Date: Sat, 4 Mar 2017 19:54:06 +0200 Subject: [PATCH 2/8] Test XVThumbImagePlugin for correctness --- Tests/test_file_xvthumb.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Tests/test_file_xvthumb.py b/Tests/test_file_xvthumb.py index a4e1e6554..62b8a2136 100644 --- a/Tests/test_file_xvthumb.py +++ b/Tests/test_file_xvthumb.py @@ -1,10 +1,20 @@ -from helper import unittest, PillowTestCase +from helper import hopper, unittest, PillowTestCase -from PIL import XVThumbImagePlugin +from PIL import Image, XVThumbImagePlugin + +TEST_FILE = "Tests/images/hopper.p7" class TestFileXVThumb(PillowTestCase): + def test_open(self): + # Act + im = Image.open(TEST_FILE) + + # Assert + self.assertEqual(im.format, "XVThumb") + self.assert_image_similar(im, hopper("P"), 49) + def test_invalid_file(self): invalid_file = "Tests/images/flower.jpg" From a0f50d7305c42032d2bfbfff06e0dc72526a3d10 Mon Sep 17 00:00:00 2001 From: hugovk Date: Sat, 4 Mar 2017 19:58:49 +0200 Subject: [PATCH 3/8] Get integers, not single-item lists of integers --- PIL/XVThumbImagePlugin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PIL/XVThumbImagePlugin.py b/PIL/XVThumbImagePlugin.py index 6929e8b82..b974461f8 100644 --- a/PIL/XVThumbImagePlugin.py +++ b/PIL/XVThumbImagePlugin.py @@ -65,7 +65,7 @@ class XVThumbImageFile(ImageFile.ImageFile): s = s.strip().split() self.mode = "P" - self.size = int(s[0:1]), int(s[1:2]) + self.size = int(s[0]), int(s[1]) self.palette = ImagePalette.raw("RGB", PALETTE) @@ -74,6 +74,7 @@ class XVThumbImageFile(ImageFile.ImageFile): self.fp.tell(), (self.mode, 0, 1) )] + # -------------------------------------------------------------------- Image.register_open(XVThumbImageFile.format, XVThumbImageFile, _accept) From 5cf56e796f14b449ddfd9dc3e933bfcfcfb5c1b1 Mon Sep 17 00:00:00 2001 From: hugovk Date: Sat, 4 Mar 2017 20:03:34 +0200 Subject: [PATCH 4/8] Refactor to reuse _accept --- PIL/XVThumbImagePlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PIL/XVThumbImagePlugin.py b/PIL/XVThumbImagePlugin.py index b974461f8..7686b263d 100644 --- a/PIL/XVThumbImagePlugin.py +++ b/PIL/XVThumbImagePlugin.py @@ -47,7 +47,7 @@ class XVThumbImageFile(ImageFile.ImageFile): def _open(self): # check magic - if self.fp.read(6) != _MAGIC: + if not _accept(self.fp.read(6)): raise SyntaxError("not an XV thumbnail file") # Skip to beginning of next line From 94c07f68fb044d57fb5e59f2aea2b9b727b9b879 Mon Sep 17 00:00:00 2001 From: hugovk Date: Sat, 4 Mar 2017 23:28:08 +0200 Subject: [PATCH 5/8] Python 3 fix --- PIL/XVThumbImagePlugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PIL/XVThumbImagePlugin.py b/PIL/XVThumbImagePlugin.py index 7686b263d..a7d39ed89 100644 --- a/PIL/XVThumbImagePlugin.py +++ b/PIL/XVThumbImagePlugin.py @@ -18,7 +18,7 @@ # from . import Image, ImageFile, ImagePalette -from ._binary import o8 +from ._binary import i8, o8 __version__ = "0.1" @@ -58,7 +58,7 @@ class XVThumbImageFile(ImageFile.ImageFile): s = self.fp.readline() if not s: raise SyntaxError("Unexpected EOF reading XV thumbnail file") - if s[0] != b'#': + if i8(s[0]) != 35: # ie. when not a comment: '#' break # parse header line (already read) From dc3233d52c38c262cb90237ddb50bc63d0d31f93 Mon Sep 17 00:00:00 2001 From: hugovk Date: Sat, 4 Mar 2017 23:31:49 +0200 Subject: [PATCH 6/8] Created by editing hopper.p7 in a text editor --- Tests/images/hopper_bad.p7 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Tests/images/hopper_bad.p7 diff --git a/Tests/images/hopper_bad.p7 b/Tests/images/hopper_bad.p7 new file mode 100644 index 000000000..382929688 --- /dev/null +++ b/Tests/images/hopper_bad.p7 @@ -0,0 +1,2 @@ +P7 332 +# Artificially edited file to cause unexpected EOF From a03a6e2049ceab4b22b1ebf547121a6da65933cd Mon Sep 17 00:00:00 2001 From: hugovk Date: Sat, 4 Mar 2017 23:33:43 +0200 Subject: [PATCH 7/8] Test unexpected EOF --- Tests/test_file_xvthumb.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Tests/test_file_xvthumb.py b/Tests/test_file_xvthumb.py index 62b8a2136..cdf4bae6a 100644 --- a/Tests/test_file_xvthumb.py +++ b/Tests/test_file_xvthumb.py @@ -15,9 +15,21 @@ class TestFileXVThumb(PillowTestCase): self.assertEqual(im.format, "XVThumb") self.assert_image_similar(im, hopper("P"), 49) + def test_unexpected_eof(self): + # Test unexpected EOF reading XV thumbnail file + # Arrange + bad_file = "Tests/images/hopper_bad.p7" + + # Act / Assert + self.assertRaises(SyntaxError, + lambda: + XVThumbImagePlugin.XVThumbImageFile(bad_file)) + def test_invalid_file(self): + # Arrange invalid_file = "Tests/images/flower.jpg" + # Act / Assert self.assertRaises(SyntaxError, lambda: XVThumbImagePlugin.XVThumbImageFile(invalid_file)) From 3e6d867ae885aa8d66bf93ab2e9a791126b789cc Mon Sep 17 00:00:00 2001 From: Hugo Date: Mon, 6 Mar 2017 17:33:47 +0200 Subject: [PATCH 8/8] Compare to a Hopper image with a similar XV palette --- Tests/test_file_xvthumb.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Tests/test_file_xvthumb.py b/Tests/test_file_xvthumb.py index cdf4bae6a..5337a8390 100644 --- a/Tests/test_file_xvthumb.py +++ b/Tests/test_file_xvthumb.py @@ -13,7 +13,10 @@ class TestFileXVThumb(PillowTestCase): # Assert self.assertEqual(im.format, "XVThumb") - self.assert_image_similar(im, hopper("P"), 49) + + # Create a Hopper image with a similar XV palette + im_hopper = hopper().quantize(palette=im) + self.assert_image_similar(im, im_hopper, 9) def test_unexpected_eof(self): # Test unexpected EOF reading XV thumbnail file