From 51247fb7f091cb3690c3224a1e2062b7f9d10eef Mon Sep 17 00:00:00 2001 From: Bryant Mairs Date: Mon, 11 Apr 2016 11:13:17 -0700 Subject: [PATCH 1/7] Test all applicable numpy datatypes for Image.fromarray() --- Tests/test_numpy.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py index 4af40c88b..d8c148ff3 100644 --- a/Tests/test_numpy.py +++ b/Tests/test_numpy.py @@ -43,24 +43,38 @@ class TestNumpy(PillowTestCase): # print dtype, list(i.getdata()) return i - # self.assert_image(to_image(numpy.bool, boolean=1), "1", (10, 10)) - # self.assert_image(to_image(numpy.bool8, boolean=1), "1", (10, 10)) + # Check supported 1-bit integer formats + self.assertRaises(TypeError, lambda: to_image(numpy.bool)) + self.assertRaises(TypeError, lambda: to_image(numpy.bool8)) - self.assertRaises(TypeError, lambda: to_image(numpy.uint)) + # Check supported 8-bit integer formats self.assert_image(to_image(numpy.uint8), "L", (10, 10)) - self.assertRaises(TypeError, lambda: to_image(numpy.uint16)) - self.assertRaises(TypeError, lambda: to_image(numpy.uint32)) - self.assertRaises(TypeError, lambda: to_image(numpy.uint64)) - + self.assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10)) + self.assert_image(to_image(numpy.uint8, 4), "RGBA", (10, 10)) self.assert_image(to_image(numpy.int8), "I", (10, 10)) - if Image._ENDIAN == '<': # Little endian - self.assert_image(to_image(numpy.int16), "I;16", (10, 10)) + + # Check non-fixed-size integer types + self.assertRaises(TypeError, lambda: to_image(numpy.uint)) + self.assert_image(to_image(numpy.int), "I", (10, 10)) + + # Check 16-bit integer formats + if Image._ENDIAN == '<': + self.assert_image(to_image(numpy.uint16), "I;16L", (10, 10)) else: - self.assert_image(to_image(numpy.int16), "I;16B", (10, 10)) + self.assert_image(to_image(numpy.uint16), "I;16B", (10, 10)) + self.assertRaises(TypeError, lambda: to_image(numpy.int16)) + + # Check 32-bit integer formats + self.assertRaises(TypeError, lambda: to_image(numpy.uint32)) self.assert_image(to_image(numpy.int32), "I", (10, 10)) + + # Check 64-bit integer formats + self.assertRaises(TypeError, lambda: to_image(numpy.uint64)) self.assertRaises(TypeError, lambda: to_image(numpy.int64)) + # Check floating-point formats self.assert_image(to_image(numpy.float), "F", (10, 10)) + self.assertRaises(TypeError, lambda: to_image(numpy.float16)) self.assert_image(to_image(numpy.float32), "F", (10, 10)) self.assert_image(to_image(numpy.float64), "F", (10, 10)) From f51e90bf330064e83ddaf582c8ae98c4e6747e10 Mon Sep 17 00:00:00 2001 From: Bryant Mairs Date: Mon, 11 Apr 2016 11:13:53 -0700 Subject: [PATCH 2/7] Create named constant for repeated values. --- Tests/test_numpy.py | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py index d8c148ff3..806752dc6 100644 --- a/Tests/test_numpy.py +++ b/Tests/test_numpy.py @@ -12,6 +12,7 @@ except ImportError: class TestNumpy(PillowTestCase): + TEST_IMAGE_SIZE = (10, 10) def setUp(self): try: @@ -29,14 +30,14 @@ class TestNumpy(PillowTestCase): else: data = list(range(100)) a = numpy.array(data, dtype=dtype) - a.shape = 10, 10 + a.shape = TestNumpy.TEST_IMAGE_SIZE i = Image.fromarray(a) if list(i.getdata()) != data: print("data mismatch for", dtype) else: data = list(range(100)) a = numpy.array([[x]*bands for x in data], dtype=dtype) - a.shape = 10, 10, bands + a.shape = TestNumpy.TEST_IMAGE_SIZE[0], TestNumpy.TEST_IMAGE_SIZE[1], bands i = Image.fromarray(a) if list(i.split()[0].getdata()) != list(range(100)): print("data mismatch for", dtype) @@ -48,35 +49,35 @@ class TestNumpy(PillowTestCase): self.assertRaises(TypeError, lambda: to_image(numpy.bool8)) # Check supported 8-bit integer formats - self.assert_image(to_image(numpy.uint8), "L", (10, 10)) - self.assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10)) - self.assert_image(to_image(numpy.uint8, 4), "RGBA", (10, 10)) - self.assert_image(to_image(numpy.int8), "I", (10, 10)) + self.assert_image(to_image(numpy.uint8), "L", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint8, 3), "RGB", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint8, 4), "RGBA", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.int8), "I", TestNumpy.TEST_IMAGE_SIZE) # Check non-fixed-size integer types self.assertRaises(TypeError, lambda: to_image(numpy.uint)) - self.assert_image(to_image(numpy.int), "I", (10, 10)) + self.assert_image(to_image(numpy.int), "I", TestNumpy.TEST_IMAGE_SIZE) # Check 16-bit integer formats if Image._ENDIAN == '<': - self.assert_image(to_image(numpy.uint16), "I;16L", (10, 10)) + self.assert_image(to_image(numpy.uint16), "I;16L", TestNumpy.TEST_IMAGE_SIZE) else: - self.assert_image(to_image(numpy.uint16), "I;16B", (10, 10)) + self.assert_image(to_image(numpy.uint16), "I;16B", TestNumpy.TEST_IMAGE_SIZE) self.assertRaises(TypeError, lambda: to_image(numpy.int16)) # Check 32-bit integer formats self.assertRaises(TypeError, lambda: to_image(numpy.uint32)) - self.assert_image(to_image(numpy.int32), "I", (10, 10)) + self.assert_image(to_image(numpy.int32), "I", TestNumpy.TEST_IMAGE_SIZE) # Check 64-bit integer formats self.assertRaises(TypeError, lambda: to_image(numpy.uint64)) self.assertRaises(TypeError, lambda: to_image(numpy.int64)) # Check floating-point formats - self.assert_image(to_image(numpy.float), "F", (10, 10)) + self.assert_image(to_image(numpy.float), "F", TestNumpy.TEST_IMAGE_SIZE) self.assertRaises(TypeError, lambda: to_image(numpy.float16)) - self.assert_image(to_image(numpy.float32), "F", (10, 10)) - self.assert_image(to_image(numpy.float64), "F", (10, 10)) + self.assert_image(to_image(numpy.float32), "F", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.float64), "F", TestNumpy.TEST_IMAGE_SIZE) self.assert_image(to_image(numpy.uint8, 2), "LA", (10, 10)) self.assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10)) @@ -85,10 +86,15 @@ class TestNumpy(PillowTestCase): # based on an erring example at # http://stackoverflow.com/questions/10854903/what-is-causing-dimension-dependent-attributeerror-in-pil-fromarray-function def test_3d_array(self): - a = numpy.ones((10, 10, 10), dtype=numpy.uint8) - self.assert_image(Image.fromarray(a[1, :, :]), "L", (10, 10)) - self.assert_image(Image.fromarray(a[:, 1, :]), "L", (10, 10)) - self.assert_image(Image.fromarray(a[:, :, 1]), "L", (10, 10)) + size = (5, TestNumpy.TEST_IMAGE_SIZE[0], TestNumpy.TEST_IMAGE_SIZE[1]) + a = numpy.ones(size, dtype=numpy.uint8) + self.assert_image(Image.fromarray(a[1, :, :]), "L", TestNumpy.TEST_IMAGE_SIZE) + size = (TestNumpy.TEST_IMAGE_SIZE[0], 5, TestNumpy.TEST_IMAGE_SIZE[1]) + a = numpy.ones(size, dtype=numpy.uint8) + self.assert_image(Image.fromarray(a[:, 1, :]), "L", TestNumpy.TEST_IMAGE_SIZE) + size = (TestNumpy.TEST_IMAGE_SIZE[0], TestNumpy.TEST_IMAGE_SIZE[1], 5) + a = numpy.ones(size, dtype=numpy.uint8) + self.assert_image(Image.fromarray(a[:, :, 1]), "L", TestNumpy.TEST_IMAGE_SIZE) def _test_img_equals_nparray(self, img, np): np_size = np.shape[1], np.shape[0] From 7fb24e8af0366947377e1964436a320c6c37b746 Mon Sep 17 00:00:00 2001 From: Bryant Mairs Date: Mon, 11 Apr 2016 12:35:16 -0700 Subject: [PATCH 3/7] Add test for reading and writing uint16 TIFFs. --- Tests/images/uint16_1_4660.tif | Bin 0 -> 346 bytes Tests/test_file_tiff.py | 7 +++++++ Tests/test_numpy.py | 15 +++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 Tests/images/uint16_1_4660.tif diff --git a/Tests/images/uint16_1_4660.tif b/Tests/images/uint16_1_4660.tif new file mode 100644 index 0000000000000000000000000000000000000000..86360be8df660302f58032afb6b193ded4d010f1 GIT binary patch literal 346 zcmebD)MDUZU|`^8U|?isU<9(bfS3`9%>-o&0L7W1Y>+xOB(@+U3s~ Date: Mon, 11 Apr 2016 11:33:41 -0700 Subject: [PATCH 4/7] Corrects fromarray() datatype mapping for integer datatypes. Currently failing for int16LE as of this commit. --- PIL/Image.py | 12 ++++++++---- Tests/test_numpy.py | 19 ++++++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 2341daff0..64f461358 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -2210,10 +2210,14 @@ _fromarray_typemap = { # ((1, 1), "|b1"): ("1", "1"), # broken ((1, 1), "|u1"): ("L", "L"), ((1, 1), "|i1"): ("I", "I;8"), - ((1, 1), "i2"): ("I", "I;16B"), - ((1, 1), "i4"): ("I", "I;32B"), + ((1, 1), "u2"): ("I", "I;16B"), + ((1, 1), "i2"): ("I", "I;16BS"), + ((1, 1), "u4"): ("I", "I;32B"), + ((1, 1), "i4"): ("I", "I;32BS"), ((1, 1), "f4"): ("F", "F;32BF"), ((1, 1), " Date: Mon, 18 Apr 2016 16:58:21 -0700 Subject: [PATCH 5/7] Move constant to module level. --- Tests/test_numpy.py | 56 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py index d79a6701a..aff52123c 100644 --- a/Tests/test_numpy.py +++ b/Tests/test_numpy.py @@ -10,9 +10,9 @@ except ImportError: # Skip via setUp() pass +TEST_IMAGE_SIZE = (10, 10) class TestNumpy(PillowTestCase): - TEST_IMAGE_SIZE = (10, 10) def setUp(self): try: @@ -30,14 +30,14 @@ class TestNumpy(PillowTestCase): else: data = list(range(100)) a = numpy.array(data, dtype=dtype) - a.shape = TestNumpy.TEST_IMAGE_SIZE + a.shape = TEST_IMAGE_SIZE i = Image.fromarray(a) if list(i.getdata()) != data: print("data mismatch for", dtype) else: data = list(range(100)) a = numpy.array([[x]*bands for x in data], dtype=dtype) - a.shape = TestNumpy.TEST_IMAGE_SIZE[0], TestNumpy.TEST_IMAGE_SIZE[1], bands + a.shape = TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], bands i = Image.fromarray(a) if list(i.split()[0].getdata()) != list(range(100)): print("data mismatch for", dtype) @@ -49,44 +49,44 @@ class TestNumpy(PillowTestCase): self.assertRaises(TypeError, lambda: to_image(numpy.bool8)) # Check supported 8-bit integer formats - self.assert_image(to_image(numpy.uint8), "L", TestNumpy.TEST_IMAGE_SIZE) - self.assert_image(to_image(numpy.uint8, 3), "RGB", TestNumpy.TEST_IMAGE_SIZE) - self.assert_image(to_image(numpy.uint8, 4), "RGBA", TestNumpy.TEST_IMAGE_SIZE) - self.assert_image(to_image(numpy.int8), "I", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint8, 3), "RGB", TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint8, 4), "RGBA", TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.int8), "I", TEST_IMAGE_SIZE) # Check non-fixed-size integer types - self.assert_image(to_image(numpy.uint), "I", TestNumpy.TEST_IMAGE_SIZE) - self.assert_image(to_image(numpy.int), "I", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint), "I", TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.int), "I", TEST_IMAGE_SIZE) # Check 16-bit integer formats if Image._ENDIAN == '<': - self.assert_image(to_image(numpy.uint16), "I;16", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint16), "I;16", TEST_IMAGE_SIZE) else: - self.assert_image(to_image(numpy.uint16), "I;16B", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint16), "I;16B", TEST_IMAGE_SIZE) if Image._ENDIAN == '<': - self.assert_image(to_image(numpy.int16), "I;16S", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.int16), "I;16S", TEST_IMAGE_SIZE) else: - self.assert_image(to_image(numpy.int16), "I;16BS", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.int16), "I;16BS", TEST_IMAGE_SIZE) # Check 32-bit integer formats if Image._ENDIAN == '<': - self.assert_image(to_image(numpy.uint32), "I;32", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint32), "I;32", TEST_IMAGE_SIZE) else: - self.assert_image(to_image(numpy.uint32), "I;32B", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint32), "I;32B", TEST_IMAGE_SIZE) if Image._ENDIAN == '<': - self.assert_image(to_image(numpy.int32), "I;32S", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.int32), "I;32S", TEST_IMAGE_SIZE) else: - self.assert_image(to_image(numpy.int32), "I;32BS", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.int32), "I;32BS", TEST_IMAGE_SIZE) # Check 64-bit integer formats self.assertRaises(TypeError, lambda: to_image(numpy.uint64)) self.assertRaises(TypeError, lambda: to_image(numpy.int64)) # Check floating-point formats - self.assert_image(to_image(numpy.float), "F", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.float), "F", TEST_IMAGE_SIZE) self.assertRaises(TypeError, lambda: to_image(numpy.float16)) - self.assert_image(to_image(numpy.float32), "F", TestNumpy.TEST_IMAGE_SIZE) - self.assert_image(to_image(numpy.float64), "F", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.float32), "F", TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.float64), "F", TEST_IMAGE_SIZE) self.assert_image(to_image(numpy.uint8, 2), "LA", (10, 10)) self.assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10)) @@ -95,15 +95,15 @@ class TestNumpy(PillowTestCase): # based on an erring example at # http://stackoverflow.com/questions/10854903/what-is-causing-dimension-dependent-attributeerror-in-pil-fromarray-function def test_3d_array(self): - size = (5, TestNumpy.TEST_IMAGE_SIZE[0], TestNumpy.TEST_IMAGE_SIZE[1]) + size = (5, TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1]) a = numpy.ones(size, dtype=numpy.uint8) - self.assert_image(Image.fromarray(a[1, :, :]), "L", TestNumpy.TEST_IMAGE_SIZE) - size = (TestNumpy.TEST_IMAGE_SIZE[0], 5, TestNumpy.TEST_IMAGE_SIZE[1]) + self.assert_image(Image.fromarray(a[1, :, :]), "L", TEST_IMAGE_SIZE) + size = (TEST_IMAGE_SIZE[0], 5, TEST_IMAGE_SIZE[1]) a = numpy.ones(size, dtype=numpy.uint8) - self.assert_image(Image.fromarray(a[:, 1, :]), "L", TestNumpy.TEST_IMAGE_SIZE) - size = (TestNumpy.TEST_IMAGE_SIZE[0], TestNumpy.TEST_IMAGE_SIZE[1], 5) + self.assert_image(Image.fromarray(a[:, 1, :]), "L", TEST_IMAGE_SIZE) + size = (TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], 5) a = numpy.ones(size, dtype=numpy.uint8) - self.assert_image(Image.fromarray(a[:, :, 1]), "L", TestNumpy.TEST_IMAGE_SIZE) + self.assert_image(Image.fromarray(a[:, :, 1]), "L", TEST_IMAGE_SIZE) def _test_img_equals_nparray(self, img, np): np_size = np.shape[1], np.shape[0] @@ -127,8 +127,8 @@ class TestNumpy(PillowTestCase): tmpfile = self.tempfile("temp.tif") pixel_value = 0x1234 filename = "Tests/images/uint16_1_4660.tif" - a = numpy.array([pixel_value] * 100, dtype=numpy.uint16) - a.shape = TestNumpy.TEST_IMAGE_SIZE + a = numpy.array([pixel_value] * TEST_IMAGE_SIZE[0] * TEST_IMAGE_SIZE[1], dtype=numpy.uint16) + a.shape = TEST_IMAGE_SIZE Image.fromarray(a).save(tmpfile) im_test = Image.open(tmpfile) im_good = Image.open(filename) From 9e1b4aba9ace272048d26d5737c3a8bc06c7b2fd Mon Sep 17 00:00:00 2001 From: wiredfool Date: Sat, 25 Jun 2016 14:33:26 +0100 Subject: [PATCH 6/7] These modes upconvert to 32bit I --- Tests/test_numpy.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py index aff52123c..38f0e05eb 100644 --- a/Tests/test_numpy.py +++ b/Tests/test_numpy.py @@ -55,28 +55,22 @@ class TestNumpy(PillowTestCase): self.assert_image(to_image(numpy.int8), "I", TEST_IMAGE_SIZE) # Check non-fixed-size integer types - self.assert_image(to_image(numpy.uint), "I", TEST_IMAGE_SIZE) - self.assert_image(to_image(numpy.int), "I", TEST_IMAGE_SIZE) + # These may fail, depending on the platform, since we have no native + # 64 bit int image types. + # self.assert_image(to_image(numpy.uint), "I", TEST_IMAGE_SIZE) + # self.assert_image(to_image(numpy.int), "I", TEST_IMAGE_SIZE) # Check 16-bit integer formats if Image._ENDIAN == '<': self.assert_image(to_image(numpy.uint16), "I;16", TEST_IMAGE_SIZE) else: self.assert_image(to_image(numpy.uint16), "I;16B", TEST_IMAGE_SIZE) - if Image._ENDIAN == '<': - self.assert_image(to_image(numpy.int16), "I;16S", TEST_IMAGE_SIZE) - else: - self.assert_image(to_image(numpy.int16), "I;16BS", TEST_IMAGE_SIZE) + + self.assert_image(to_image(numpy.int16), "I", TEST_IMAGE_SIZE) # Check 32-bit integer formats - if Image._ENDIAN == '<': - self.assert_image(to_image(numpy.uint32), "I;32", TEST_IMAGE_SIZE) - else: - self.assert_image(to_image(numpy.uint32), "I;32B", TEST_IMAGE_SIZE) - if Image._ENDIAN == '<': - self.assert_image(to_image(numpy.int32), "I;32S", TEST_IMAGE_SIZE) - else: - self.assert_image(to_image(numpy.int32), "I;32BS", TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.uint32), "I", TEST_IMAGE_SIZE) + self.assert_image(to_image(numpy.int32), "I", TEST_IMAGE_SIZE) # Check 64-bit integer formats self.assertRaises(TypeError, lambda: to_image(numpy.uint64)) From 0bc06f79443727a271b4d4b46bf18d7ccc0e79b8 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Sat, 25 Jun 2016 14:50:40 +0100 Subject: [PATCH 7/7] Fix filename on py2.6 --- Tests/test_file_tiff.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 6898b22aa..cd737a2d0 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -466,7 +466,7 @@ class TestFileTiff(PillowTestCase): def test_open_tiff_uint16(self): # Test an image of all '0' values pixel_value = 0x1234 - infile = "Tests/images/uint16_1_{}.tif".format(pixel_value) + infile = "Tests/images/uint16_1_4660.tif" im = Image.open(infile) self.assertEqual(im.getpixel((0, 0)), pixel_value)