mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-31 07:57:27 +03:00 
			
		
		
		
	Replace unittest with pytest
This commit is contained in:
		
							parent
							
								
									098406c304
								
							
						
					
					
						commit
						affade7595
					
				|  | @ -1,7 +1,6 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image, ImageFilter | from PIL import Image, ImageFilter | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase |  | ||||||
| 
 |  | ||||||
| sample = Image.new("L", (7, 5)) | sample = Image.new("L", (7, 5)) | ||||||
| # fmt: off | # fmt: off | ||||||
| sample.putdata(sum([ | sample.putdata(sum([ | ||||||
|  | @ -21,226 +20,244 @@ def test_imageops_box_blur(): | ||||||
|     assert isinstance(i, Image.Image) |     assert isinstance(i, Image.Image) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestBoxBlur(PillowTestCase): | def box_blur(image, radius=1, n=1): | ||||||
|     def box_blur(self, image, radius=1, n=1): |     return image._new(image.im.box_blur(radius, n)) | ||||||
|         return image._new(image.im.box_blur(radius, n)) |  | ||||||
| 
 | 
 | ||||||
|     def assertImage(self, im, data, delta=0): |  | ||||||
|         it = iter(im.getdata()) |  | ||||||
|         for data_row in data: |  | ||||||
|             im_row = [next(it) for _ in range(im.size[0])] |  | ||||||
|             if any( |  | ||||||
|                 abs(data_v - im_v) > delta for data_v, im_v in zip(data_row, im_row) |  | ||||||
|             ): |  | ||||||
|                 self.assertEqual(im_row, data_row) |  | ||||||
|         self.assertRaises(StopIteration, next, it) |  | ||||||
| 
 | 
 | ||||||
|     def assertBlur(self, im, radius, data, passes=1, delta=0): | def assertImage(im, data, delta=0): | ||||||
|         # check grayscale image |     it = iter(im.getdata()) | ||||||
|         self.assertImage(self.box_blur(im, radius, passes), data, delta) |     for data_row in data: | ||||||
|         rgba = Image.merge("RGBA", (im, im, im, im)) |         im_row = [next(it) for _ in range(im.size[0])] | ||||||
|         for band in self.box_blur(rgba, radius, passes).split(): |         if any(abs(data_v - im_v) > delta for data_v, im_v in zip(data_row, im_row)): | ||||||
|             self.assertImage(band, data, delta) |             assert im_row == data_row | ||||||
|  |     with pytest.raises(StopIteration): | ||||||
|  |         next(it) | ||||||
| 
 | 
 | ||||||
|     def test_color_modes(self): |  | ||||||
|         self.assertRaises(ValueError, self.box_blur, sample.convert("1")) |  | ||||||
|         self.assertRaises(ValueError, self.box_blur, sample.convert("P")) |  | ||||||
|         self.box_blur(sample.convert("L")) |  | ||||||
|         self.box_blur(sample.convert("LA")) |  | ||||||
|         self.box_blur(sample.convert("LA").convert("La")) |  | ||||||
|         self.assertRaises(ValueError, self.box_blur, sample.convert("I")) |  | ||||||
|         self.assertRaises(ValueError, self.box_blur, sample.convert("F")) |  | ||||||
|         self.box_blur(sample.convert("RGB")) |  | ||||||
|         self.box_blur(sample.convert("RGBA")) |  | ||||||
|         self.box_blur(sample.convert("RGBA").convert("RGBa")) |  | ||||||
|         self.box_blur(sample.convert("CMYK")) |  | ||||||
|         self.assertRaises(ValueError, self.box_blur, sample.convert("YCbCr")) |  | ||||||
| 
 | 
 | ||||||
|     def test_radius_0(self): | def assertBlur(im, radius, data, passes=1, delta=0): | ||||||
|         self.assertBlur( |     # check grayscale image | ||||||
|             sample, |     assertImage(box_blur(im, radius, passes), data, delta) | ||||||
|             0, |     rgba = Image.merge("RGBA", (im, im, im, im)) | ||||||
|             [ |     for band in box_blur(rgba, radius, passes).split(): | ||||||
|                 # fmt: off |         assertImage(band, data, delta) | ||||||
|                 [210, 50,  20,  10,  220, 230, 80], |  | ||||||
|                 [190, 210, 20,  180, 170, 40,  110], |  | ||||||
|                 [120, 210, 250, 60,  220, 0,   220], |  | ||||||
|                 [220, 40,  230, 80,  130, 250, 40], |  | ||||||
|                 [250, 0,   80,  30,  60,  20,  110], |  | ||||||
|                 # fmt: on |  | ||||||
|             ], |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def test_radius_0_02(self): |  | ||||||
|         self.assertBlur( |  | ||||||
|             sample, |  | ||||||
|             0.02, |  | ||||||
|             [ |  | ||||||
|                 # fmt: off |  | ||||||
|                 [206, 55,  20,  17,  215, 223, 83], |  | ||||||
|                 [189, 203, 31,  171, 169, 46,  110], |  | ||||||
|                 [125, 206, 241, 69,  210, 13,  210], |  | ||||||
|                 [215, 49,  221, 82,  131, 235, 48], |  | ||||||
|                 [244, 7,   80,  32,  60,  27,  107], |  | ||||||
|                 # fmt: on |  | ||||||
|             ], |  | ||||||
|             delta=2, |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def test_radius_0_05(self): | def test_color_modes(): | ||||||
|         self.assertBlur( |     with pytest.raises(ValueError): | ||||||
|             sample, |         box_blur(sample.convert("1")) | ||||||
|             0.05, |     with pytest.raises(ValueError): | ||||||
|             [ |         box_blur(sample.convert("P")) | ||||||
|                 # fmt: off |     box_blur(sample.convert("L")) | ||||||
|                 [202, 62,  22,  27,  209, 215, 88], |     box_blur(sample.convert("LA")) | ||||||
|                 [188, 194, 44,  161, 168, 56,  111], |     box_blur(sample.convert("LA").convert("La")) | ||||||
|                 [131, 201, 229, 81,  198, 31,  198], |     with pytest.raises(ValueError): | ||||||
|                 [209, 62,  209, 86,  133, 216, 59], |         box_blur(sample.convert("I")) | ||||||
|                 [237, 17,  80,  36,  60,  35,  103], |     with pytest.raises(ValueError): | ||||||
|                 # fmt: on |         box_blur(sample.convert("F")) | ||||||
|             ], |     box_blur(sample.convert("RGB")) | ||||||
|             delta=2, |     box_blur(sample.convert("RGBA")) | ||||||
|         ) |     box_blur(sample.convert("RGBA").convert("RGBa")) | ||||||
|  |     box_blur(sample.convert("CMYK")) | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         box_blur(sample.convert("YCbCr")) | ||||||
| 
 | 
 | ||||||
|     def test_radius_0_1(self): |  | ||||||
|         self.assertBlur( |  | ||||||
|             sample, |  | ||||||
|             0.1, |  | ||||||
|             [ |  | ||||||
|                 # fmt: off |  | ||||||
|                 [196, 72,  24,  40,  200, 203, 93], |  | ||||||
|                 [187, 183, 62,  148, 166, 68,  111], |  | ||||||
|                 [139, 193, 213, 96,  182, 54,  182], |  | ||||||
|                 [201, 78,  193, 91,  133, 191, 73], |  | ||||||
|                 [227, 31,  80,  42,  61,  47,  99], |  | ||||||
|                 # fmt: on |  | ||||||
|             ], |  | ||||||
|             delta=1, |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def test_radius_0_5(self): | def test_radius_0(): | ||||||
|         self.assertBlur( |     assertBlur( | ||||||
|             sample, |         sample, | ||||||
|             0.5, |         0, | ||||||
|             [ |         [ | ||||||
|                 # fmt: off |             # fmt: off | ||||||
|                 [176, 101, 46,  83,  163, 165, 111], |             [210, 50,  20,  10,  220, 230, 80], | ||||||
|                 [176, 149, 108, 122, 144, 120, 117], |             [190, 210, 20,  180, 170, 40,  110], | ||||||
|                 [164, 171, 159, 141, 134, 119, 129], |             [120, 210, 250, 60,  220, 0,   220], | ||||||
|                 [170, 136, 133, 114, 116, 124, 109], |             [220, 40,  230, 80,  130, 250, 40], | ||||||
|                 [184, 95,  72,  70,  69,  81,  89], |             [250, 0,   80,  30,  60,  20,  110], | ||||||
|                 # fmt: on |             # fmt: on | ||||||
|             ], |         ], | ||||||
|             delta=1, |     ) | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def test_radius_1(self): |  | ||||||
|         self.assertBlur( |  | ||||||
|             sample, |  | ||||||
|             1, |  | ||||||
|             [ |  | ||||||
|                 # fmt: off |  | ||||||
|                 [170, 109, 63,  97,  146, 153, 116], |  | ||||||
|                 [168, 142, 112, 128, 126, 143, 121], |  | ||||||
|                 [169, 166, 142, 149, 126, 131, 114], |  | ||||||
|                 [159, 156, 109, 127, 94,  117, 112], |  | ||||||
|                 [164, 128, 63,  87,  76,  89,  90], |  | ||||||
|                 # fmt: on |  | ||||||
|             ], |  | ||||||
|             delta=1, |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def test_radius_1_5(self): | def test_radius_0_02(): | ||||||
|         self.assertBlur( |     assertBlur( | ||||||
|             sample, |         sample, | ||||||
|             1.5, |         0.02, | ||||||
|             [ |         [ | ||||||
|                 # fmt: off |             # fmt: off | ||||||
|                 [155, 120, 105, 112, 124, 137, 130], |             [206, 55,  20,  17,  215, 223, 83], | ||||||
|                 [160, 136, 124, 125, 127, 134, 130], |             [189, 203, 31,  171, 169, 46,  110], | ||||||
|                 [166, 147, 130, 125, 120, 121, 119], |             [125, 206, 241, 69,  210, 13,  210], | ||||||
|                 [168, 145, 119, 109, 103, 105, 110], |             [215, 49,  221, 82,  131, 235, 48], | ||||||
|                 [168, 134, 96,  85,  85,  89,  97], |             [244, 7,   80,  32,  60,  27,  107], | ||||||
|                 # fmt: on |             # fmt: on | ||||||
|             ], |         ], | ||||||
|             delta=1, |         delta=2, | ||||||
|         ) |     ) | ||||||
| 
 | 
 | ||||||
|     def test_radius_bigger_then_half(self): |  | ||||||
|         self.assertBlur( |  | ||||||
|             sample, |  | ||||||
|             3, |  | ||||||
|             [ |  | ||||||
|                 # fmt: off |  | ||||||
|                 [144, 145, 142, 128, 114, 115, 117], |  | ||||||
|                 [148, 145, 137, 122, 109, 111, 112], |  | ||||||
|                 [152, 145, 131, 117, 103, 107, 108], |  | ||||||
|                 [156, 144, 126, 111, 97,  102, 103], |  | ||||||
|                 [160, 144, 121, 106, 92,  98,  99], |  | ||||||
|                 # fmt: on |  | ||||||
|             ], |  | ||||||
|             delta=1, |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def test_radius_bigger_then_width(self): | def test_radius_0_05(): | ||||||
|         self.assertBlur( |     assertBlur( | ||||||
|             sample, |         sample, | ||||||
|             10, |         0.05, | ||||||
|             [ |         [ | ||||||
|                 [158, 153, 147, 141, 135, 129, 123], |             # fmt: off | ||||||
|                 [159, 153, 147, 141, 136, 130, 124], |             [202, 62,  22,  27,  209, 215, 88], | ||||||
|                 [159, 154, 148, 142, 136, 130, 124], |             [188, 194, 44,  161, 168, 56,  111], | ||||||
|                 [160, 154, 148, 142, 137, 131, 125], |             [131, 201, 229, 81,  198, 31,  198], | ||||||
|                 [160, 155, 149, 143, 137, 131, 125], |             [209, 62,  209, 86,  133, 216, 59], | ||||||
|             ], |             [237, 17,  80,  36,  60,  35,  103], | ||||||
|             delta=0, |             # fmt: on | ||||||
|         ) |         ], | ||||||
|  |         delta=2, | ||||||
|  |     ) | ||||||
| 
 | 
 | ||||||
|     def test_extreme_large_radius(self): |  | ||||||
|         self.assertBlur( |  | ||||||
|             sample, |  | ||||||
|             600, |  | ||||||
|             [ |  | ||||||
|                 [162, 162, 162, 162, 162, 162, 162], |  | ||||||
|                 [162, 162, 162, 162, 162, 162, 162], |  | ||||||
|                 [162, 162, 162, 162, 162, 162, 162], |  | ||||||
|                 [162, 162, 162, 162, 162, 162, 162], |  | ||||||
|                 [162, 162, 162, 162, 162, 162, 162], |  | ||||||
|             ], |  | ||||||
|             delta=1, |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def test_two_passes(self): | def test_radius_0_1(): | ||||||
|         self.assertBlur( |     assertBlur( | ||||||
|             sample, |         sample, | ||||||
|             1, |         0.1, | ||||||
|             [ |         [ | ||||||
|                 # fmt: off |             # fmt: off | ||||||
|                 [153, 123, 102, 109, 132, 135, 129], |             [196, 72,  24,  40,  200, 203, 93], | ||||||
|                 [159, 138, 123, 121, 133, 131, 126], |             [187, 183, 62,  148, 166, 68,  111], | ||||||
|                 [162, 147, 136, 124, 127, 121, 121], |             [139, 193, 213, 96,  182, 54,  182], | ||||||
|                 [159, 140, 125, 108, 111, 106, 108], |             [201, 78,  193, 91,  133, 191, 73], | ||||||
|                 [154, 126, 105, 87,  94,  93,  97], |             [227, 31,  80,  42,  61,  47,  99], | ||||||
|                 # fmt: on |             # fmt: on | ||||||
|             ], |         ], | ||||||
|             passes=2, |         delta=1, | ||||||
|             delta=1, |     ) | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def test_three_passes(self): | 
 | ||||||
|         self.assertBlur( | def test_radius_0_5(): | ||||||
|             sample, |     assertBlur( | ||||||
|             1, |         sample, | ||||||
|             [ |         0.5, | ||||||
|                 # fmt: off |         [ | ||||||
|                 [146, 131, 116, 118, 126, 131, 130], |             # fmt: off | ||||||
|                 [151, 138, 125, 123, 126, 128, 127], |             [176, 101, 46,  83,  163, 165, 111], | ||||||
|                 [154, 143, 129, 123, 120, 120, 119], |             [176, 149, 108, 122, 144, 120, 117], | ||||||
|                 [152, 139, 122, 113, 108, 108, 108], |             [164, 171, 159, 141, 134, 119, 129], | ||||||
|                 [148, 132, 112, 102, 97,  99,  100], |             [170, 136, 133, 114, 116, 124, 109], | ||||||
|                 # fmt: on |             [184, 95,  72,  70,  69,  81,  89], | ||||||
|             ], |             # fmt: on | ||||||
|             passes=3, |         ], | ||||||
|             delta=1, |         delta=1, | ||||||
|         ) |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_radius_1(): | ||||||
|  |     assertBlur( | ||||||
|  |         sample, | ||||||
|  |         1, | ||||||
|  |         [ | ||||||
|  |             # fmt: off | ||||||
|  |             [170, 109, 63,  97,  146, 153, 116], | ||||||
|  |             [168, 142, 112, 128, 126, 143, 121], | ||||||
|  |             [169, 166, 142, 149, 126, 131, 114], | ||||||
|  |             [159, 156, 109, 127, 94,  117, 112], | ||||||
|  |             [164, 128, 63,  87,  76,  89,  90], | ||||||
|  |             # fmt: on | ||||||
|  |         ], | ||||||
|  |         delta=1, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_radius_1_5(): | ||||||
|  |     assertBlur( | ||||||
|  |         sample, | ||||||
|  |         1.5, | ||||||
|  |         [ | ||||||
|  |             # fmt: off | ||||||
|  |             [155, 120, 105, 112, 124, 137, 130], | ||||||
|  |             [160, 136, 124, 125, 127, 134, 130], | ||||||
|  |             [166, 147, 130, 125, 120, 121, 119], | ||||||
|  |             [168, 145, 119, 109, 103, 105, 110], | ||||||
|  |             [168, 134, 96,  85,  85,  89,  97], | ||||||
|  |             # fmt: on | ||||||
|  |         ], | ||||||
|  |         delta=1, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_radius_bigger_then_half(): | ||||||
|  |     assertBlur( | ||||||
|  |         sample, | ||||||
|  |         3, | ||||||
|  |         [ | ||||||
|  |             # fmt: off | ||||||
|  |             [144, 145, 142, 128, 114, 115, 117], | ||||||
|  |             [148, 145, 137, 122, 109, 111, 112], | ||||||
|  |             [152, 145, 131, 117, 103, 107, 108], | ||||||
|  |             [156, 144, 126, 111, 97,  102, 103], | ||||||
|  |             [160, 144, 121, 106, 92,  98,  99], | ||||||
|  |             # fmt: on | ||||||
|  |         ], | ||||||
|  |         delta=1, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_radius_bigger_then_width(): | ||||||
|  |     assertBlur( | ||||||
|  |         sample, | ||||||
|  |         10, | ||||||
|  |         [ | ||||||
|  |             [158, 153, 147, 141, 135, 129, 123], | ||||||
|  |             [159, 153, 147, 141, 136, 130, 124], | ||||||
|  |             [159, 154, 148, 142, 136, 130, 124], | ||||||
|  |             [160, 154, 148, 142, 137, 131, 125], | ||||||
|  |             [160, 155, 149, 143, 137, 131, 125], | ||||||
|  |         ], | ||||||
|  |         delta=0, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_extreme_large_radius(): | ||||||
|  |     assertBlur( | ||||||
|  |         sample, | ||||||
|  |         600, | ||||||
|  |         [ | ||||||
|  |             [162, 162, 162, 162, 162, 162, 162], | ||||||
|  |             [162, 162, 162, 162, 162, 162, 162], | ||||||
|  |             [162, 162, 162, 162, 162, 162, 162], | ||||||
|  |             [162, 162, 162, 162, 162, 162, 162], | ||||||
|  |             [162, 162, 162, 162, 162, 162, 162], | ||||||
|  |         ], | ||||||
|  |         delta=1, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_two_passes(): | ||||||
|  |     assertBlur( | ||||||
|  |         sample, | ||||||
|  |         1, | ||||||
|  |         [ | ||||||
|  |             # fmt: off | ||||||
|  |             [153, 123, 102, 109, 132, 135, 129], | ||||||
|  |             [159, 138, 123, 121, 133, 131, 126], | ||||||
|  |             [162, 147, 136, 124, 127, 121, 121], | ||||||
|  |             [159, 140, 125, 108, 111, 106, 108], | ||||||
|  |             [154, 126, 105, 87,  94,  93,  97], | ||||||
|  |             # fmt: on | ||||||
|  |         ], | ||||||
|  |         passes=2, | ||||||
|  |         delta=1, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_three_passes(): | ||||||
|  |     assertBlur( | ||||||
|  |         sample, | ||||||
|  |         1, | ||||||
|  |         [ | ||||||
|  |             # fmt: off | ||||||
|  |             [146, 131, 116, 118, 126, 131, 130], | ||||||
|  |             [151, 138, 125, 123, 126, 128, 127], | ||||||
|  |             [154, 143, 129, 123, 120, 120, 119], | ||||||
|  |             [152, 139, 122, 113, 108, 108, 108], | ||||||
|  |             [148, 132, 112, 102, 97,  99,  100], | ||||||
|  |             # fmt: on | ||||||
|  |         ], | ||||||
|  |         passes=3, | ||||||
|  |         delta=1, | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  | @ -22,7 +22,7 @@ class TestDecompressionBomb(PillowTestCase): | ||||||
|         # Arrange |         # Arrange | ||||||
|         # Turn limit off |         # Turn limit off | ||||||
|         Image.MAX_IMAGE_PIXELS = None |         Image.MAX_IMAGE_PIXELS = None | ||||||
|         self.assertIsNone(Image.MAX_IMAGE_PIXELS) |         assert Image.MAX_IMAGE_PIXELS is None | ||||||
| 
 | 
 | ||||||
|         # Act / Assert |         # Act / Assert | ||||||
|         # Implicit assert: no warning. |         # Implicit assert: no warning. | ||||||
|  | @ -33,7 +33,7 @@ class TestDecompressionBomb(PillowTestCase): | ||||||
|     def test_warning(self): |     def test_warning(self): | ||||||
|         # Set limit to trigger warning on the test file |         # Set limit to trigger warning on the test file | ||||||
|         Image.MAX_IMAGE_PIXELS = 128 * 128 - 1 |         Image.MAX_IMAGE_PIXELS = 128 * 128 - 1 | ||||||
|         self.assertEqual(Image.MAX_IMAGE_PIXELS, 128 * 128 - 1) |         assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1 | ||||||
| 
 | 
 | ||||||
|         def open(): |         def open(): | ||||||
|             with Image.open(TEST_FILE): |             with Image.open(TEST_FILE): | ||||||
|  | @ -44,18 +44,18 @@ class TestDecompressionBomb(PillowTestCase): | ||||||
|     def test_exception(self): |     def test_exception(self): | ||||||
|         # Set limit to trigger exception on the test file |         # Set limit to trigger exception on the test file | ||||||
|         Image.MAX_IMAGE_PIXELS = 64 * 128 - 1 |         Image.MAX_IMAGE_PIXELS = 64 * 128 - 1 | ||||||
|         self.assertEqual(Image.MAX_IMAGE_PIXELS, 64 * 128 - 1) |         assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1 | ||||||
| 
 | 
 | ||||||
|         with self.assertRaises(Image.DecompressionBombError): |         with pytest.raises(Image.DecompressionBombError): | ||||||
|             with Image.open(TEST_FILE): |             with Image.open(TEST_FILE): | ||||||
|                 pass |                 pass | ||||||
| 
 | 
 | ||||||
|     def test_exception_ico(self): |     def test_exception_ico(self): | ||||||
|         with self.assertRaises(Image.DecompressionBombError): |         with pytest.raises(Image.DecompressionBombError): | ||||||
|             Image.open("Tests/images/decompression_bomb.ico") |             Image.open("Tests/images/decompression_bomb.ico") | ||||||
| 
 | 
 | ||||||
|     def test_exception_gif(self): |     def test_exception_gif(self): | ||||||
|         with self.assertRaises(Image.DecompressionBombError): |         with pytest.raises(Image.DecompressionBombError): | ||||||
|             Image.open("Tests/images/decompression_bomb.gif") |             Image.open("Tests/images/decompression_bomb.gif") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -85,11 +85,11 @@ class TestDecompressionCrop(PillowTestCase): | ||||||
|         error_values = ((-99909, -99990, 99999, 99999), (99909, 99990, -99999, -99999)) |         error_values = ((-99909, -99990, 99999, 99999), (99909, 99990, -99999, -99999)) | ||||||
| 
 | 
 | ||||||
|         for value in good_values: |         for value in good_values: | ||||||
|             self.assertEqual(im.crop(value).size, (9, 9)) |             assert im.crop(value).size == (9, 9) | ||||||
| 
 | 
 | ||||||
|         for value in warning_values: |         for value in warning_values: | ||||||
|             pytest.warns(Image.DecompressionBombWarning, im.crop, value) |             pytest.warns(Image.DecompressionBombWarning, im.crop, value) | ||||||
| 
 | 
 | ||||||
|         for value in error_values: |         for value in error_values: | ||||||
|             with self.assertRaises(Image.DecompressionBombError): |             with pytest.raises(Image.DecompressionBombError): | ||||||
|                 im.crop(value) |                 im.crop(value) | ||||||
|  |  | ||||||
|  | @ -1,84 +1,92 @@ | ||||||
| import unittest |  | ||||||
| 
 |  | ||||||
| import pytest | import pytest | ||||||
| from PIL import DcxImagePlugin, Image | from PIL import DcxImagePlugin, Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, hopper, is_pypy | from .helper import assert_image_equal, hopper, is_pypy | ||||||
| 
 | 
 | ||||||
| # Created with ImageMagick: convert hopper.ppm hopper.dcx | # Created with ImageMagick: convert hopper.ppm hopper.dcx | ||||||
| TEST_FILE = "Tests/images/hopper.dcx" | TEST_FILE = "Tests/images/hopper.dcx" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFileDcx(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     # Arrange | ||||||
|         # Arrange | 
 | ||||||
|  |     # Act | ||||||
|  |     with Image.open(TEST_FILE) as im: | ||||||
|  | 
 | ||||||
|  |         # Assert | ||||||
|  |         assert im.size == (128, 128) | ||||||
|  |         assert isinstance(im, DcxImagePlugin.DcxImageFile) | ||||||
|  |         orig = hopper() | ||||||
|  |         assert_image_equal(im, orig) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||||
|  | def test_unclosed_file(): | ||||||
|  |     def open(): | ||||||
|  |         im = Image.open(TEST_FILE) | ||||||
|  |         im.load() | ||||||
|  | 
 | ||||||
|  |     pytest.warns(ResourceWarning, open) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_closed_file(): | ||||||
|  |     def open(): | ||||||
|  |         im = Image.open(TEST_FILE) | ||||||
|  |         im.load() | ||||||
|  |         im.close() | ||||||
|  | 
 | ||||||
|  |     pytest.warns(None, open) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_context_manager(): | ||||||
|  |     def open(): | ||||||
|  |         with Image.open(TEST_FILE) as im: | ||||||
|  |             im.load() | ||||||
|  | 
 | ||||||
|  |     pytest.warns(None, open) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_invalid_file(): | ||||||
|  |     with open("Tests/images/flower.jpg", "rb") as fp: | ||||||
|  |         with pytest.raises(SyntaxError): | ||||||
|  |             DcxImagePlugin.DcxImageFile(fp) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_tell(): | ||||||
|  |     # Arrange | ||||||
|  |     with Image.open(TEST_FILE) as im: | ||||||
| 
 | 
 | ||||||
|         # Act |         # Act | ||||||
|         with Image.open(TEST_FILE) as im: |         frame = im.tell() | ||||||
| 
 | 
 | ||||||
|             # Assert |         # Assert | ||||||
|             self.assertEqual(im.size, (128, 128)) |         assert frame == 0 | ||||||
|             self.assertIsInstance(im, DcxImagePlugin.DcxImageFile) |  | ||||||
|             orig = hopper() |  | ||||||
|             assert_image_equal(im, orig) |  | ||||||
| 
 | 
 | ||||||
|     @unittest.skipIf(is_pypy(), "Requires CPython") |  | ||||||
|     def test_unclosed_file(self): |  | ||||||
|         def open(): |  | ||||||
|             im = Image.open(TEST_FILE) |  | ||||||
|             im.load() |  | ||||||
| 
 | 
 | ||||||
|         pytest.warns(ResourceWarning, open) | def test_n_frames(): | ||||||
|  |     with Image.open(TEST_FILE) as im: | ||||||
|  |         assert im.n_frames == 1 | ||||||
|  |         assert not im.is_animated | ||||||
| 
 | 
 | ||||||
|     def test_closed_file(self): |  | ||||||
|         def open(): |  | ||||||
|             im = Image.open(TEST_FILE) |  | ||||||
|             im.load() |  | ||||||
|             im.close() |  | ||||||
| 
 | 
 | ||||||
|         pytest.warns(None, open) | def test_eoferror(): | ||||||
|  |     with Image.open(TEST_FILE) as im: | ||||||
|  |         n_frames = im.n_frames | ||||||
| 
 | 
 | ||||||
|     def test_context_manager(self): |         # Test seeking past the last frame | ||||||
|         def open(): |         with pytest.raises(EOFError): | ||||||
|             with Image.open(TEST_FILE) as im: |             im.seek(n_frames) | ||||||
|                 im.load() |         assert im.tell() < n_frames | ||||||
| 
 | 
 | ||||||
|         pytest.warns(None, open) |         # Test that seeking to the last frame does not raise an error | ||||||
|  |         im.seek(n_frames - 1) | ||||||
| 
 | 
 | ||||||
|     def test_invalid_file(self): |  | ||||||
|         with open("Tests/images/flower.jpg", "rb") as fp: |  | ||||||
|             self.assertRaises(SyntaxError, DcxImagePlugin.DcxImageFile, fp) |  | ||||||
| 
 | 
 | ||||||
|     def test_tell(self): | def test_seek_too_far(): | ||||||
|         # Arrange |     # Arrange | ||||||
|         with Image.open(TEST_FILE) as im: |     with Image.open(TEST_FILE) as im: | ||||||
|  |         frame = 999  # too big on purpose | ||||||
| 
 | 
 | ||||||
|             # Act |     # Act / Assert | ||||||
|             frame = im.tell() |     with pytest.raises(EOFError): | ||||||
| 
 |         im.seek(frame) | ||||||
|             # Assert |  | ||||||
|             self.assertEqual(frame, 0) |  | ||||||
| 
 |  | ||||||
|     def test_n_frames(self): |  | ||||||
|         with Image.open(TEST_FILE) as im: |  | ||||||
|             self.assertEqual(im.n_frames, 1) |  | ||||||
|             self.assertFalse(im.is_animated) |  | ||||||
| 
 |  | ||||||
|     def test_eoferror(self): |  | ||||||
|         with Image.open(TEST_FILE) as im: |  | ||||||
|             n_frames = im.n_frames |  | ||||||
| 
 |  | ||||||
|             # Test seeking past the last frame |  | ||||||
|             self.assertRaises(EOFError, im.seek, n_frames) |  | ||||||
|             self.assertLess(im.tell(), n_frames) |  | ||||||
| 
 |  | ||||||
|             # Test that seeking to the last frame does not raise an error |  | ||||||
|             im.seek(n_frames - 1) |  | ||||||
| 
 |  | ||||||
|     def test_seek_too_far(self): |  | ||||||
|         # Arrange |  | ||||||
|         with Image.open(TEST_FILE) as im: |  | ||||||
|             frame = 999  # too big on purpose |  | ||||||
| 
 |  | ||||||
|         # Act / Assert |  | ||||||
|         self.assertRaises(EOFError, im.seek, frame) |  | ||||||
|  |  | ||||||
|  | @ -1,8 +1,10 @@ | ||||||
|  | """Test DdsImagePlugin""" | ||||||
| from io import BytesIO | from io import BytesIO | ||||||
| 
 | 
 | ||||||
|  | import pytest | ||||||
| from PIL import DdsImagePlugin, Image | from PIL import DdsImagePlugin, Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal | from .helper import assert_image_equal | ||||||
| 
 | 
 | ||||||
| TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds" | TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds" | ||||||
| TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds" | TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds" | ||||||
|  | @ -12,146 +14,148 @@ TEST_FILE_DX10_BC7_UNORM_SRGB = "Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds" | ||||||
| TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/uncompressed_rgb.dds" | TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/uncompressed_rgb.dds" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFileDds(PillowTestCase): | def test_sanity_dxt1(): | ||||||
|     """Test DdsImagePlugin""" |     """Check DXT1 images can be opened""" | ||||||
|  |     with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target: | ||||||
|  |         target = target.convert("RGBA") | ||||||
|  |     with Image.open(TEST_FILE_DXT1) as im: | ||||||
|  |         im.load() | ||||||
| 
 | 
 | ||||||
|     def test_sanity_dxt1(self): |         assert im.format == "DDS" | ||||||
|         """Check DXT1 images can be opened""" |         assert im.mode == "RGBA" | ||||||
|         with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target: |         assert im.size == (256, 256) | ||||||
|             target = target.convert("RGBA") | 
 | ||||||
|         with Image.open(TEST_FILE_DXT1) as im: |         assert_image_equal(im, target) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_sanity_dxt5(): | ||||||
|  |     """Check DXT5 images can be opened""" | ||||||
|  | 
 | ||||||
|  |     with Image.open(TEST_FILE_DXT5) as im: | ||||||
|  |         im.load() | ||||||
|  | 
 | ||||||
|  |     assert im.format == "DDS" | ||||||
|  |     assert im.mode == "RGBA" | ||||||
|  |     assert im.size == (256, 256) | ||||||
|  | 
 | ||||||
|  |     with Image.open(TEST_FILE_DXT5.replace(".dds", ".png")) as target: | ||||||
|  |         assert_image_equal(target, im) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_sanity_dxt3(): | ||||||
|  |     """Check DXT3 images can be opened""" | ||||||
|  | 
 | ||||||
|  |     with Image.open(TEST_FILE_DXT3.replace(".dds", ".png")) as target: | ||||||
|  |         with Image.open(TEST_FILE_DXT3) as im: | ||||||
|             im.load() |             im.load() | ||||||
| 
 | 
 | ||||||
|             self.assertEqual(im.format, "DDS") |             assert im.format == "DDS" | ||||||
|             self.assertEqual(im.mode, "RGBA") |             assert im.mode == "RGBA" | ||||||
|             self.assertEqual(im.size, (256, 256)) |             assert im.size == (256, 256) | ||||||
| 
 | 
 | ||||||
|             assert_image_equal(im, target) |  | ||||||
| 
 |  | ||||||
|     def test_sanity_dxt5(self): |  | ||||||
|         """Check DXT5 images can be opened""" |  | ||||||
| 
 |  | ||||||
|         with Image.open(TEST_FILE_DXT5) as im: |  | ||||||
|             im.load() |  | ||||||
| 
 |  | ||||||
|         self.assertEqual(im.format, "DDS") |  | ||||||
|         self.assertEqual(im.mode, "RGBA") |  | ||||||
|         self.assertEqual(im.size, (256, 256)) |  | ||||||
| 
 |  | ||||||
|         with Image.open(TEST_FILE_DXT5.replace(".dds", ".png")) as target: |  | ||||||
|             assert_image_equal(target, im) |             assert_image_equal(target, im) | ||||||
| 
 | 
 | ||||||
|     def test_sanity_dxt3(self): |  | ||||||
|         """Check DXT3 images can be opened""" |  | ||||||
| 
 | 
 | ||||||
|         with Image.open(TEST_FILE_DXT3.replace(".dds", ".png")) as target: | def test_dx10_bc7(): | ||||||
|             with Image.open(TEST_FILE_DXT3) as im: |     """Check DX10 images can be opened""" | ||||||
|                 im.load() |  | ||||||
| 
 | 
 | ||||||
|                 self.assertEqual(im.format, "DDS") |     with Image.open(TEST_FILE_DX10_BC7) as im: | ||||||
|                 self.assertEqual(im.mode, "RGBA") |         im.load() | ||||||
|                 self.assertEqual(im.size, (256, 256)) |  | ||||||
| 
 | 
 | ||||||
|                 assert_image_equal(target, im) |         assert im.format == "DDS" | ||||||
|  |         assert im.mode == "RGBA" | ||||||
|  |         assert im.size == (256, 256) | ||||||
| 
 | 
 | ||||||
|     def test_dx10_bc7(self): |         with Image.open(TEST_FILE_DX10_BC7.replace(".dds", ".png")) as target: | ||||||
|         """Check DX10 images can be opened""" |             assert_image_equal(target, im) | ||||||
| 
 | 
 | ||||||
|         with Image.open(TEST_FILE_DX10_BC7) as im: | 
 | ||||||
|  | def test_dx10_bc7_unorm_srgb(): | ||||||
|  |     """Check DX10 unsigned normalized integer images can be opened""" | ||||||
|  | 
 | ||||||
|  |     with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im: | ||||||
|  |         im.load() | ||||||
|  | 
 | ||||||
|  |         assert im.format == "DDS" | ||||||
|  |         assert im.mode == "RGBA" | ||||||
|  |         assert im.size == (16, 16) | ||||||
|  |         assert im.info["gamma"] == 1 / 2.2 | ||||||
|  | 
 | ||||||
|  |         with Image.open( | ||||||
|  |             TEST_FILE_DX10_BC7_UNORM_SRGB.replace(".dds", ".png") | ||||||
|  |         ) as target: | ||||||
|  |             assert_image_equal(target, im) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_unimplemented_dxgi_format(): | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|  |         Image.open("Tests/images/unimplemented_dxgi_format.dds",) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_uncompressed_rgb(): | ||||||
|  |     """Check uncompressed RGB images can be opened""" | ||||||
|  | 
 | ||||||
|  |     with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im: | ||||||
|  |         im.load() | ||||||
|  | 
 | ||||||
|  |         assert im.format == "DDS" | ||||||
|  |         assert im.mode == "RGBA" | ||||||
|  |         assert im.size == (800, 600) | ||||||
|  | 
 | ||||||
|  |         with Image.open(TEST_FILE_UNCOMPRESSED_RGB.replace(".dds", ".png")) as target: | ||||||
|  |             assert_image_equal(target, im) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test__validate_true(): | ||||||
|  |     """Check valid prefix""" | ||||||
|  |     # Arrange | ||||||
|  |     prefix = b"DDS etc" | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     output = DdsImagePlugin._validate(prefix) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert output | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test__validate_false(): | ||||||
|  |     """Check invalid prefix""" | ||||||
|  |     # Arrange | ||||||
|  |     prefix = b"something invalid" | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     output = DdsImagePlugin._validate(prefix) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert not output | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_short_header(): | ||||||
|  |     """ Check a short header""" | ||||||
|  |     with open(TEST_FILE_DXT5, "rb") as f: | ||||||
|  |         img_file = f.read() | ||||||
|  | 
 | ||||||
|  |     def short_header(): | ||||||
|  |         Image.open(BytesIO(img_file[:119])) | ||||||
|  | 
 | ||||||
|  |     with pytest.raises(IOError): | ||||||
|  |         short_header() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_short_file(): | ||||||
|  |     """ Check that the appropriate error is thrown for a short file""" | ||||||
|  | 
 | ||||||
|  |     with open(TEST_FILE_DXT5, "rb") as f: | ||||||
|  |         img_file = f.read() | ||||||
|  | 
 | ||||||
|  |     def short_file(): | ||||||
|  |         with Image.open(BytesIO(img_file[:-100])) as im: | ||||||
|             im.load() |             im.load() | ||||||
| 
 | 
 | ||||||
|             self.assertEqual(im.format, "DDS") |     with pytest.raises(IOError): | ||||||
|             self.assertEqual(im.mode, "RGBA") |         short_file() | ||||||
|             self.assertEqual(im.size, (256, 256)) |  | ||||||
| 
 | 
 | ||||||
|             with Image.open(TEST_FILE_DX10_BC7.replace(".dds", ".png")) as target: |  | ||||||
|                 assert_image_equal(target, im) |  | ||||||
| 
 | 
 | ||||||
|     def test_dx10_bc7_unorm_srgb(self): | def test_unimplemented_pixel_format(): | ||||||
|         """Check DX10 unsigned normalized integer images can be opened""" |     with pytest.raises(NotImplementedError): | ||||||
| 
 |         Image.open("Tests/images/unimplemented_pixel_format.dds",) | ||||||
|         with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im: |  | ||||||
|             im.load() |  | ||||||
| 
 |  | ||||||
|             self.assertEqual(im.format, "DDS") |  | ||||||
|             self.assertEqual(im.mode, "RGBA") |  | ||||||
|             self.assertEqual(im.size, (16, 16)) |  | ||||||
|             self.assertEqual(im.info["gamma"], 1 / 2.2) |  | ||||||
| 
 |  | ||||||
|             with Image.open( |  | ||||||
|                 TEST_FILE_DX10_BC7_UNORM_SRGB.replace(".dds", ".png") |  | ||||||
|             ) as target: |  | ||||||
|                 assert_image_equal(target, im) |  | ||||||
| 
 |  | ||||||
|     def test_unimplemented_dxgi_format(self): |  | ||||||
|         self.assertRaises( |  | ||||||
|             NotImplementedError, |  | ||||||
|             Image.open, |  | ||||||
|             "Tests/images/unimplemented_dxgi_format.dds", |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     def test_uncompressed_rgb(self): |  | ||||||
|         """Check uncompressed RGB images can be opened""" |  | ||||||
| 
 |  | ||||||
|         with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im: |  | ||||||
|             im.load() |  | ||||||
| 
 |  | ||||||
|             self.assertEqual(im.format, "DDS") |  | ||||||
|             self.assertEqual(im.mode, "RGBA") |  | ||||||
|             self.assertEqual(im.size, (800, 600)) |  | ||||||
| 
 |  | ||||||
|             with Image.open( |  | ||||||
|                 TEST_FILE_UNCOMPRESSED_RGB.replace(".dds", ".png") |  | ||||||
|             ) as target: |  | ||||||
|                 assert_image_equal(target, im) |  | ||||||
| 
 |  | ||||||
|     def test__validate_true(self): |  | ||||||
|         """Check valid prefix""" |  | ||||||
|         # Arrange |  | ||||||
|         prefix = b"DDS etc" |  | ||||||
| 
 |  | ||||||
|         # Act |  | ||||||
|         output = DdsImagePlugin._validate(prefix) |  | ||||||
| 
 |  | ||||||
|         # Assert |  | ||||||
|         self.assertTrue(output) |  | ||||||
| 
 |  | ||||||
|     def test__validate_false(self): |  | ||||||
|         """Check invalid prefix""" |  | ||||||
|         # Arrange |  | ||||||
|         prefix = b"something invalid" |  | ||||||
| 
 |  | ||||||
|         # Act |  | ||||||
|         output = DdsImagePlugin._validate(prefix) |  | ||||||
| 
 |  | ||||||
|         # Assert |  | ||||||
|         self.assertFalse(output) |  | ||||||
| 
 |  | ||||||
|     def test_short_header(self): |  | ||||||
|         """ Check a short header""" |  | ||||||
|         with open(TEST_FILE_DXT5, "rb") as f: |  | ||||||
|             img_file = f.read() |  | ||||||
| 
 |  | ||||||
|         def short_header(): |  | ||||||
|             Image.open(BytesIO(img_file[:119])) |  | ||||||
| 
 |  | ||||||
|         self.assertRaises(IOError, short_header) |  | ||||||
| 
 |  | ||||||
|     def test_short_file(self): |  | ||||||
|         """ Check that the appropriate error is thrown for a short file""" |  | ||||||
| 
 |  | ||||||
|         with open(TEST_FILE_DXT5, "rb") as f: |  | ||||||
|             img_file = f.read() |  | ||||||
| 
 |  | ||||||
|         def short_file(): |  | ||||||
|             with Image.open(BytesIO(img_file[:-100])) as im: |  | ||||||
|                 im.load() |  | ||||||
| 
 |  | ||||||
|         self.assertRaises(IOError, short_file) |  | ||||||
| 
 |  | ||||||
|     def test_unimplemented_pixel_format(self): |  | ||||||
|         self.assertRaises( |  | ||||||
|             NotImplementedError, |  | ||||||
|             Image.open, |  | ||||||
|             "Tests/images/unimplemented_pixel_format.dds", |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|  | @ -1,9 +1,7 @@ | ||||||
| import unittest |  | ||||||
| 
 |  | ||||||
| import pytest | import pytest | ||||||
| from PIL import FliImagePlugin, Image | from PIL import FliImagePlugin, Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, is_pypy | from .helper import assert_image_equal, is_pypy | ||||||
| 
 | 
 | ||||||
| # created as an export of a palette image from Gimp2.6 | # created as an export of a palette image from Gimp2.6 | ||||||
| # save as...-> hopper.fli, default options. | # save as...-> hopper.fli, default options. | ||||||
|  | @ -13,105 +11,115 @@ static_test_file = "Tests/images/hopper.fli" | ||||||
| animated_test_file = "Tests/images/a.fli" | animated_test_file = "Tests/images/a.fli" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFileFli(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     with Image.open(static_test_file) as im: | ||||||
|  |         im.load() | ||||||
|  |         assert im.mode == "P" | ||||||
|  |         assert im.size == (128, 128) | ||||||
|  |         assert im.format == "FLI" | ||||||
|  |         assert not im.is_animated | ||||||
|  | 
 | ||||||
|  |     with Image.open(animated_test_file) as im: | ||||||
|  |         assert im.mode == "P" | ||||||
|  |         assert im.size == (320, 200) | ||||||
|  |         assert im.format == "FLI" | ||||||
|  |         assert im.info["duration"] == 71 | ||||||
|  |         assert im.is_animated | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||||
|  | def test_unclosed_file(): | ||||||
|  |     def open(): | ||||||
|  |         im = Image.open(static_test_file) | ||||||
|  |         im.load() | ||||||
|  | 
 | ||||||
|  |     pytest.warns(ResourceWarning, open) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_closed_file(): | ||||||
|  |     def open(): | ||||||
|  |         im = Image.open(static_test_file) | ||||||
|  |         im.load() | ||||||
|  |         im.close() | ||||||
|  | 
 | ||||||
|  |     pytest.warns(None, open) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_context_manager(): | ||||||
|  |     def open(): | ||||||
|         with Image.open(static_test_file) as im: |         with Image.open(static_test_file) as im: | ||||||
|             im.load() |             im.load() | ||||||
|             self.assertEqual(im.mode, "P") |  | ||||||
|             self.assertEqual(im.size, (128, 128)) |  | ||||||
|             self.assertEqual(im.format, "FLI") |  | ||||||
|             self.assertFalse(im.is_animated) |  | ||||||
| 
 | 
 | ||||||
|         with Image.open(animated_test_file) as im: |     pytest.warns(None, open) | ||||||
|             self.assertEqual(im.mode, "P") |  | ||||||
|             self.assertEqual(im.size, (320, 200)) |  | ||||||
|             self.assertEqual(im.format, "FLI") |  | ||||||
|             self.assertEqual(im.info["duration"], 71) |  | ||||||
|             self.assertTrue(im.is_animated) |  | ||||||
| 
 | 
 | ||||||
|     @unittest.skipIf(is_pypy(), "Requires CPython") |  | ||||||
|     def test_unclosed_file(self): |  | ||||||
|         def open(): |  | ||||||
|             im = Image.open(static_test_file) |  | ||||||
|             im.load() |  | ||||||
| 
 | 
 | ||||||
|         pytest.warns(ResourceWarning, open) | def test_tell(): | ||||||
|  |     # Arrange | ||||||
|  |     with Image.open(static_test_file) as im: | ||||||
| 
 | 
 | ||||||
|     def test_closed_file(self): |         # Act | ||||||
|         def open(): |         frame = im.tell() | ||||||
|             im = Image.open(static_test_file) |  | ||||||
|             im.load() |  | ||||||
|             im.close() |  | ||||||
| 
 | 
 | ||||||
|         pytest.warns(None, open) |         # Assert | ||||||
|  |         assert frame == 0 | ||||||
| 
 | 
 | ||||||
|     def test_context_manager(self): |  | ||||||
|         def open(): |  | ||||||
|             with Image.open(static_test_file) as im: |  | ||||||
|                 im.load() |  | ||||||
| 
 | 
 | ||||||
|         pytest.warns(None, open) | def test_invalid_file(): | ||||||
|  |     invalid_file = "Tests/images/flower.jpg" | ||||||
| 
 | 
 | ||||||
|     def test_tell(self): |     with pytest.raises(SyntaxError): | ||||||
|         # Arrange |         FliImagePlugin.FliImageFile(invalid_file) | ||||||
|         with Image.open(static_test_file) as im: |  | ||||||
| 
 | 
 | ||||||
|             # Act |  | ||||||
|             frame = im.tell() |  | ||||||
| 
 | 
 | ||||||
|             # Assert | def test_n_frames(): | ||||||
|             self.assertEqual(frame, 0) |     with Image.open(static_test_file) as im: | ||||||
|  |         assert im.n_frames == 1 | ||||||
|  |         assert not im.is_animated | ||||||
| 
 | 
 | ||||||
|     def test_invalid_file(self): |     with Image.open(animated_test_file) as im: | ||||||
|         invalid_file = "Tests/images/flower.jpg" |         assert im.n_frames == 384 | ||||||
|  |         assert im.is_animated | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(SyntaxError, FliImagePlugin.FliImageFile, invalid_file) |  | ||||||
| 
 | 
 | ||||||
|     def test_n_frames(self): | def test_eoferror(): | ||||||
|         with Image.open(static_test_file) as im: |     with Image.open(animated_test_file) as im: | ||||||
|             self.assertEqual(im.n_frames, 1) |         n_frames = im.n_frames | ||||||
|             self.assertFalse(im.is_animated) |  | ||||||
| 
 | 
 | ||||||
|         with Image.open(animated_test_file) as im: |         # Test seeking past the last frame | ||||||
|             self.assertEqual(im.n_frames, 384) |         with pytest.raises(EOFError): | ||||||
|             self.assertTrue(im.is_animated) |             im.seek(n_frames) | ||||||
|  |         assert im.tell() < n_frames | ||||||
| 
 | 
 | ||||||
|     def test_eoferror(self): |         # Test that seeking to the last frame does not raise an error | ||||||
|         with Image.open(animated_test_file) as im: |         im.seek(n_frames - 1) | ||||||
|             n_frames = im.n_frames |  | ||||||
| 
 | 
 | ||||||
|             # Test seeking past the last frame |  | ||||||
|             self.assertRaises(EOFError, im.seek, n_frames) |  | ||||||
|             self.assertLess(im.tell(), n_frames) |  | ||||||
| 
 | 
 | ||||||
|             # Test that seeking to the last frame does not raise an error | def test_seek_tell(): | ||||||
|             im.seek(n_frames - 1) |     with Image.open(animated_test_file) as im: | ||||||
| 
 | 
 | ||||||
|     def test_seek_tell(self): |         layer_number = im.tell() | ||||||
|         with Image.open(animated_test_file) as im: |         assert layer_number == 0 | ||||||
| 
 | 
 | ||||||
|             layer_number = im.tell() |         im.seek(0) | ||||||
|             self.assertEqual(layer_number, 0) |         layer_number = im.tell() | ||||||
|  |         assert layer_number == 0 | ||||||
| 
 | 
 | ||||||
|             im.seek(0) |         im.seek(1) | ||||||
|             layer_number = im.tell() |         layer_number = im.tell() | ||||||
|             self.assertEqual(layer_number, 0) |         assert layer_number == 1 | ||||||
| 
 | 
 | ||||||
|             im.seek(1) |         im.seek(2) | ||||||
|             layer_number = im.tell() |         layer_number = im.tell() | ||||||
|             self.assertEqual(layer_number, 1) |         assert layer_number == 2 | ||||||
| 
 | 
 | ||||||
|             im.seek(2) |         im.seek(1) | ||||||
|             layer_number = im.tell() |         layer_number = im.tell() | ||||||
|             self.assertEqual(layer_number, 2) |         assert layer_number == 1 | ||||||
| 
 | 
 | ||||||
|             im.seek(1) |  | ||||||
|             layer_number = im.tell() |  | ||||||
|             self.assertEqual(layer_number, 1) |  | ||||||
| 
 | 
 | ||||||
|     def test_seek(self): | def test_seek(): | ||||||
|         with Image.open(animated_test_file) as im: |     with Image.open(animated_test_file) as im: | ||||||
|             im.seek(50) |         im.seek(50) | ||||||
| 
 | 
 | ||||||
|             with Image.open("Tests/images/a_fli.png") as expected: |         with Image.open("Tests/images/a_fli.png") as expected: | ||||||
|                 assert_image_equal(im, expected) |             assert_image_equal(im, expected) | ||||||
|  |  | ||||||
|  | @ -1,9 +1,6 @@ | ||||||
| import unittest | import pytest | ||||||
| 
 |  | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase |  | ||||||
| 
 |  | ||||||
| try: | try: | ||||||
|     from PIL import FpxImagePlugin |     from PIL import FpxImagePlugin | ||||||
| except ImportError: | except ImportError: | ||||||
|  | @ -11,18 +8,23 @@ except ImportError: | ||||||
| else: | else: | ||||||
|     olefile_installed = True |     olefile_installed = True | ||||||
| 
 | 
 | ||||||
|  | pytestmark = pytest.mark.skipif( | ||||||
|  |     not olefile_installed, reason="olefile package not installed" | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| @unittest.skipUnless(olefile_installed, "olefile package not installed") |  | ||||||
| class TestFileFpx(PillowTestCase): |  | ||||||
|     def test_invalid_file(self): |  | ||||||
|         # Test an invalid OLE file |  | ||||||
|         invalid_file = "Tests/images/flower.jpg" |  | ||||||
|         self.assertRaises(SyntaxError, FpxImagePlugin.FpxImageFile, invalid_file) |  | ||||||
| 
 | 
 | ||||||
|         # Test a valid OLE file, but not an FPX file | def test_invalid_file(): | ||||||
|         ole_file = "Tests/images/test-ole-file.doc" |     # Test an invalid OLE file | ||||||
|         self.assertRaises(SyntaxError, FpxImagePlugin.FpxImageFile, ole_file) |     invalid_file = "Tests/images/flower.jpg" | ||||||
|  |     with pytest.raises(SyntaxError): | ||||||
|  |         FpxImagePlugin.FpxImageFile(invalid_file) | ||||||
| 
 | 
 | ||||||
|     def test_fpx_invalid_number_of_bands(self): |     # Test a valid OLE file, but not an FPX file | ||||||
|         with self.assertRaisesRegex(IOError, "Invalid number of bands"): |     ole_file = "Tests/images/test-ole-file.doc" | ||||||
|             Image.open("Tests/images/input_bw_five_bands.fpx") |     with pytest.raises(SyntaxError): | ||||||
|  |         FpxImagePlugin.FpxImageFile(ole_file) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_fpx_invalid_number_of_bands(): | ||||||
|  |     with pytest.raises(IOError, match="Invalid number of bands"): | ||||||
|  |         Image.open("Tests/images/input_bw_five_bands.fpx") | ||||||
|  |  | ||||||
|  | @ -1,15 +1,17 @@ | ||||||
|  | import pytest | ||||||
| from PIL import GbrImagePlugin, Image | from PIL import GbrImagePlugin, Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal | from .helper import assert_image_equal | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFileGbr(PillowTestCase): | def test_invalid_file(): | ||||||
|     def test_invalid_file(self): |     invalid_file = "Tests/images/flower.jpg" | ||||||
|         invalid_file = "Tests/images/flower.jpg" |  | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(SyntaxError, GbrImagePlugin.GbrImageFile, invalid_file) |     with pytest.raises(SyntaxError): | ||||||
|  |         GbrImagePlugin.GbrImageFile(invalid_file) | ||||||
| 
 | 
 | ||||||
|     def test_gbr_file(self): | 
 | ||||||
|         with Image.open("Tests/images/gbr.gbr") as im: | def test_gbr_file(): | ||||||
|             with Image.open("Tests/images/gbr.png") as target: |     with Image.open("Tests/images/gbr.gbr") as im: | ||||||
|                 assert_image_equal(target, im) |         with Image.open("Tests/images/gbr.png") as target: | ||||||
|  |             assert_image_equal(target, im) | ||||||
|  |  | ||||||
|  | @ -1,122 +1,128 @@ | ||||||
| from PIL import GimpGradientFile | from PIL import GimpGradientFile | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase | 
 | ||||||
|  | def test_linear_pos_le_middle(): | ||||||
|  |     # Arrange | ||||||
|  |     middle = 0.5 | ||||||
|  |     pos = 0.25 | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     ret = GimpGradientFile.linear(middle, pos) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert ret == 0.25 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImage(PillowTestCase): | def test_linear_pos_le_small_middle(): | ||||||
|     def test_linear_pos_le_middle(self): |     # Arrange | ||||||
|         # Arrange |     middle = 1e-11 | ||||||
|         middle = 0.5 |     pos = 1e-12 | ||||||
|         pos = 0.25 |  | ||||||
| 
 | 
 | ||||||
|         # Act |     # Act | ||||||
|         ret = GimpGradientFile.linear(middle, pos) |     ret = GimpGradientFile.linear(middle, pos) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         self.assertEqual(ret, 0.25) |     assert ret == 0.0 | ||||||
| 
 | 
 | ||||||
|     def test_linear_pos_le_small_middle(self): |  | ||||||
|         # Arrange |  | ||||||
|         middle = 1e-11 |  | ||||||
|         pos = 1e-12 |  | ||||||
| 
 | 
 | ||||||
|         # Act | def test_linear_pos_gt_middle(): | ||||||
|         ret = GimpGradientFile.linear(middle, pos) |     # Arrange | ||||||
|  |     middle = 0.5 | ||||||
|  |     pos = 0.75 | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Act | ||||||
|         self.assertEqual(ret, 0.0) |     ret = GimpGradientFile.linear(middle, pos) | ||||||
| 
 | 
 | ||||||
|     def test_linear_pos_gt_middle(self): |     # Assert | ||||||
|         # Arrange |     assert ret == 0.75 | ||||||
|         middle = 0.5 |  | ||||||
|         pos = 0.75 |  | ||||||
| 
 | 
 | ||||||
|         # Act |  | ||||||
|         ret = GimpGradientFile.linear(middle, pos) |  | ||||||
| 
 | 
 | ||||||
|         # Assert | def test_linear_pos_gt_small_middle(): | ||||||
|         self.assertEqual(ret, 0.75) |     # Arrange | ||||||
|  |     middle = 1 - 1e-11 | ||||||
|  |     pos = 1 - 1e-12 | ||||||
| 
 | 
 | ||||||
|     def test_linear_pos_gt_small_middle(self): |     # Act | ||||||
|         # Arrange |     ret = GimpGradientFile.linear(middle, pos) | ||||||
|         middle = 1 - 1e-11 |  | ||||||
|         pos = 1 - 1e-12 |  | ||||||
| 
 | 
 | ||||||
|         # Act |     # Assert | ||||||
|         ret = GimpGradientFile.linear(middle, pos) |     assert ret == 1.0 | ||||||
| 
 | 
 | ||||||
|         # Assert |  | ||||||
|         self.assertEqual(ret, 1.0) |  | ||||||
| 
 | 
 | ||||||
|     def test_curved(self): | def test_curved(): | ||||||
|         # Arrange |     # Arrange | ||||||
|         middle = 0.5 |     middle = 0.5 | ||||||
|         pos = 0.75 |     pos = 0.75 | ||||||
| 
 | 
 | ||||||
|         # Act |     # Act | ||||||
|         ret = GimpGradientFile.curved(middle, pos) |     ret = GimpGradientFile.curved(middle, pos) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         self.assertEqual(ret, 0.75) |     assert ret == 0.75 | ||||||
| 
 | 
 | ||||||
|     def test_sine(self): |  | ||||||
|         # Arrange |  | ||||||
|         middle = 0.5 |  | ||||||
|         pos = 0.75 |  | ||||||
| 
 | 
 | ||||||
|         # Act | def test_sine(): | ||||||
|         ret = GimpGradientFile.sine(middle, pos) |     # Arrange | ||||||
|  |     middle = 0.5 | ||||||
|  |     pos = 0.75 | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Act | ||||||
|         self.assertEqual(ret, 0.8535533905932737) |     ret = GimpGradientFile.sine(middle, pos) | ||||||
| 
 | 
 | ||||||
|     def test_sphere_increasing(self): |     # Assert | ||||||
|         # Arrange |     assert ret == 0.8535533905932737 | ||||||
|         middle = 0.5 |  | ||||||
|         pos = 0.75 |  | ||||||
| 
 | 
 | ||||||
|         # Act |  | ||||||
|         ret = GimpGradientFile.sphere_increasing(middle, pos) |  | ||||||
| 
 | 
 | ||||||
|         # Assert | def test_sphere_increasing(): | ||||||
|         self.assertAlmostEqual(ret, 0.9682458365518543) |     # Arrange | ||||||
|  |     middle = 0.5 | ||||||
|  |     pos = 0.75 | ||||||
| 
 | 
 | ||||||
|     def test_sphere_decreasing(self): |     # Act | ||||||
|         # Arrange |     ret = GimpGradientFile.sphere_increasing(middle, pos) | ||||||
|         middle = 0.5 |  | ||||||
|         pos = 0.75 |  | ||||||
| 
 | 
 | ||||||
|         # Act |     # Assert | ||||||
|         ret = GimpGradientFile.sphere_decreasing(middle, pos) |     assert round(abs(ret - 0.9682458365518543), 7) == 0 | ||||||
| 
 | 
 | ||||||
|         # Assert |  | ||||||
|         self.assertEqual(ret, 0.3385621722338523) |  | ||||||
| 
 | 
 | ||||||
|     def test_load_via_imagepalette(self): | def test_sphere_decreasing(): | ||||||
|         # Arrange |     # Arrange | ||||||
|         from PIL import ImagePalette |     middle = 0.5 | ||||||
|  |     pos = 0.75 | ||||||
| 
 | 
 | ||||||
|         test_file = "Tests/images/gimp_gradient.ggr" |     # Act | ||||||
|  |     ret = GimpGradientFile.sphere_decreasing(middle, pos) | ||||||
| 
 | 
 | ||||||
|         # Act |     # Assert | ||||||
|         palette = ImagePalette.load(test_file) |     assert ret == 0.3385621722338523 | ||||||
| 
 | 
 | ||||||
|         # Assert |  | ||||||
|         # load returns raw palette information |  | ||||||
|         self.assertEqual(len(palette[0]), 1024) |  | ||||||
|         self.assertEqual(palette[1], "RGBA") |  | ||||||
| 
 | 
 | ||||||
|     def test_load_1_3_via_imagepalette(self): | def test_load_via_imagepalette(): | ||||||
|         # Arrange |     # Arrange | ||||||
|         from PIL import ImagePalette |     from PIL import ImagePalette | ||||||
| 
 | 
 | ||||||
|         # GIMP 1.3 gradient files contain a name field |     test_file = "Tests/images/gimp_gradient.ggr" | ||||||
|         test_file = "Tests/images/gimp_gradient_with_name.ggr" |  | ||||||
| 
 | 
 | ||||||
|         # Act |     # Act | ||||||
|         palette = ImagePalette.load(test_file) |     palette = ImagePalette.load(test_file) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         # load returns raw palette information |     # load returns raw palette information | ||||||
|         self.assertEqual(len(palette[0]), 1024) |     assert len(palette[0]) == 1024 | ||||||
|         self.assertEqual(palette[1], "RGBA") |     assert palette[1] == "RGBA" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_load_1_3_via_imagepalette(): | ||||||
|  |     # Arrange | ||||||
|  |     from PIL import ImagePalette | ||||||
|  | 
 | ||||||
|  |     # GIMP 1.3 gradient files contain a name field | ||||||
|  |     test_file = "Tests/images/gimp_gradient_with_name.ggr" | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     palette = ImagePalette.load(test_file) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     # load returns raw palette information | ||||||
|  |     assert len(palette[0]) == 1024 | ||||||
|  |     assert palette[1] == "RGBA" | ||||||
|  |  | ||||||
|  | @ -1,28 +1,30 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image, McIdasImagePlugin | from PIL import Image, McIdasImagePlugin | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal | from .helper import assert_image_equal | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFileMcIdas(PillowTestCase): | def test_invalid_file(): | ||||||
|     def test_invalid_file(self): |     invalid_file = "Tests/images/flower.jpg" | ||||||
|         invalid_file = "Tests/images/flower.jpg" |  | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(SyntaxError, McIdasImagePlugin.McIdasImageFile, invalid_file) |     with pytest.raises(SyntaxError): | ||||||
|  |         McIdasImagePlugin.McIdasImageFile(invalid_file) | ||||||
| 
 | 
 | ||||||
|     def test_valid_file(self): |  | ||||||
|         # Arrange |  | ||||||
|         # https://ghrc.nsstc.nasa.gov/hydro/details/cmx3g8 |  | ||||||
|         # https://ghrc.nsstc.nasa.gov/pub/fieldCampaigns/camex3/cmx3g8/browse/ |  | ||||||
|         test_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara" |  | ||||||
|         saved_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png" |  | ||||||
| 
 | 
 | ||||||
|         # Act | def test_valid_file(): | ||||||
|         with Image.open(test_file) as im: |     # Arrange | ||||||
|             im.load() |     # https://ghrc.nsstc.nasa.gov/hydro/details/cmx3g8 | ||||||
|  |     # https://ghrc.nsstc.nasa.gov/pub/fieldCampaigns/camex3/cmx3g8/browse/ | ||||||
|  |     test_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara" | ||||||
|  |     saved_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png" | ||||||
| 
 | 
 | ||||||
|             # Assert |     # Act | ||||||
|             self.assertEqual(im.format, "MCIDAS") |     with Image.open(test_file) as im: | ||||||
|             self.assertEqual(im.mode, "I") |         im.load() | ||||||
|             self.assertEqual(im.size, (1800, 400)) | 
 | ||||||
|             with Image.open(saved_file) as im2: |         # Assert | ||||||
|                 assert_image_equal(im, im2) |         assert im.format == "MCIDAS" | ||||||
|  |         assert im.mode == "I" | ||||||
|  |         assert im.size == (1800, 400) | ||||||
|  |         with Image.open(saved_file) as im2: | ||||||
|  |             assert_image_equal(im, im2) | ||||||
|  |  | ||||||
|  | @ -1,8 +1,7 @@ | ||||||
| import unittest | import pytest | ||||||
| 
 |  | ||||||
| from PIL import Image, ImagePalette, features | from PIL import Image, ImagePalette, features | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_similar, hopper | from .helper import assert_image_similar, hopper | ||||||
| 
 | 
 | ||||||
| try: | try: | ||||||
|     from PIL import MicImagePlugin |     from PIL import MicImagePlugin | ||||||
|  | @ -14,52 +13,59 @@ else: | ||||||
| TEST_FILE = "Tests/images/hopper.mic" | TEST_FILE = "Tests/images/hopper.mic" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @unittest.skipUnless(olefile_installed, "olefile package not installed") | pytestmark = [ | ||||||
| @unittest.skipUnless(features.check("libtiff"), "libtiff not installed") |     pytest.mark.skipif(not olefile_installed, reason="olefile package not installed"), | ||||||
| class TestFileMic(PillowTestCase): |     pytest.mark.skipif(not features.check("libtiff"), reason="libtiff not installed"), | ||||||
|     def test_sanity(self): | ] | ||||||
|         with Image.open(TEST_FILE) as im: |  | ||||||
|             im.load() |  | ||||||
|             self.assertEqual(im.mode, "RGBA") |  | ||||||
|             self.assertEqual(im.size, (128, 128)) |  | ||||||
|             self.assertEqual(im.format, "MIC") |  | ||||||
| 
 | 
 | ||||||
|             # Adjust for the gamma of 2.2 encoded into the file |  | ||||||
|             lut = ImagePalette.make_gamma_lut(1 / 2.2) |  | ||||||
|             im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()]) |  | ||||||
| 
 | 
 | ||||||
|             im2 = hopper("RGBA") | def test_sanity(): | ||||||
|             assert_image_similar(im, im2, 10) |     with Image.open(TEST_FILE) as im: | ||||||
|  |         im.load() | ||||||
|  |         assert im.mode == "RGBA" | ||||||
|  |         assert im.size == (128, 128) | ||||||
|  |         assert im.format == "MIC" | ||||||
| 
 | 
 | ||||||
|     def test_n_frames(self): |         # Adjust for the gamma of 2.2 encoded into the file | ||||||
|         with Image.open(TEST_FILE) as im: |         lut = ImagePalette.make_gamma_lut(1 / 2.2) | ||||||
|  |         im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()]) | ||||||
| 
 | 
 | ||||||
|             self.assertEqual(im.n_frames, 1) |         im2 = hopper("RGBA") | ||||||
|  |         assert_image_similar(im, im2, 10) | ||||||
| 
 | 
 | ||||||
|     def test_is_animated(self): |  | ||||||
|         with Image.open(TEST_FILE) as im: |  | ||||||
| 
 | 
 | ||||||
|             self.assertFalse(im.is_animated) | def test_n_frames(): | ||||||
|  |     with Image.open(TEST_FILE) as im: | ||||||
|  |         assert im.n_frames == 1 | ||||||
| 
 | 
 | ||||||
|     def test_tell(self): |  | ||||||
|         with Image.open(TEST_FILE) as im: |  | ||||||
| 
 | 
 | ||||||
|             self.assertEqual(im.tell(), 0) | def test_is_animated(): | ||||||
|  |     with Image.open(TEST_FILE) as im: | ||||||
|  |         assert not im.is_animated | ||||||
| 
 | 
 | ||||||
|     def test_seek(self): |  | ||||||
|         with Image.open(TEST_FILE) as im: |  | ||||||
| 
 | 
 | ||||||
|             im.seek(0) | def test_tell(): | ||||||
|             self.assertEqual(im.tell(), 0) |     with Image.open(TEST_FILE) as im: | ||||||
|  |         assert im.tell() == 0 | ||||||
| 
 | 
 | ||||||
|             self.assertRaises(EOFError, im.seek, 99) |  | ||||||
|             self.assertEqual(im.tell(), 0) |  | ||||||
| 
 | 
 | ||||||
|     def test_invalid_file(self): | def test_seek(): | ||||||
|         # Test an invalid OLE file |     with Image.open(TEST_FILE) as im: | ||||||
|         invalid_file = "Tests/images/flower.jpg" |         im.seek(0) | ||||||
|         self.assertRaises(SyntaxError, MicImagePlugin.MicImageFile, invalid_file) |         assert im.tell() == 0 | ||||||
| 
 | 
 | ||||||
|         # Test a valid OLE file, but not a MIC file |         with pytest.raises(EOFError): | ||||||
|         ole_file = "Tests/images/test-ole-file.doc" |             im.seek(99) | ||||||
|         self.assertRaises(SyntaxError, MicImagePlugin.MicImageFile, ole_file) |         assert im.tell() == 0 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_invalid_file(): | ||||||
|  |     # Test an invalid OLE file | ||||||
|  |     invalid_file = "Tests/images/flower.jpg" | ||||||
|  |     with pytest.raises(SyntaxError): | ||||||
|  |         MicImagePlugin.MicImageFile(invalid_file) | ||||||
|  | 
 | ||||||
|  |     # Test a valid OLE file, but not a MIC file | ||||||
|  |     ole_file = "Tests/images/test-ole-file.doc" | ||||||
|  |     with pytest.raises(SyntaxError): | ||||||
|  |         MicImagePlugin.MicImageFile(ole_file) | ||||||
|  |  | ||||||
|  | @ -1,202 +1,221 @@ | ||||||
| import unittest |  | ||||||
| from io import BytesIO | from io import BytesIO | ||||||
| 
 | 
 | ||||||
| import pytest | import pytest | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_similar, is_pypy | from .helper import assert_image_similar, is_pypy | ||||||
| 
 | 
 | ||||||
| test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"] | test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFileMpo(PillowTestCase): | def setup_module(): | ||||||
|     def setUp(self): |     codecs = dir(Image.core) | ||||||
|         codecs = dir(Image.core) |     if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs: | ||||||
|         if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs: |         pytest.skip("jpeg support not available") | ||||||
|             self.skipTest("jpeg support not available") |  | ||||||
| 
 | 
 | ||||||
|     def frame_roundtrip(self, im, **options): |  | ||||||
|         # Note that for now, there is no MPO saving functionality |  | ||||||
|         out = BytesIO() |  | ||||||
|         im.save(out, "MPO", **options) |  | ||||||
|         test_bytes = out.tell() |  | ||||||
|         out.seek(0) |  | ||||||
|         im = Image.open(out) |  | ||||||
|         im.bytes = test_bytes  # for testing only |  | ||||||
|         return im |  | ||||||
| 
 | 
 | ||||||
|     def test_sanity(self): | def frame_roundtrip(im, **options): | ||||||
|         for test_file in test_files: |     # Note that for now, there is no MPO saving functionality | ||||||
|             with Image.open(test_file) as im: |     out = BytesIO() | ||||||
|                 im.load() |     im.save(out, "MPO", **options) | ||||||
|                 self.assertEqual(im.mode, "RGB") |     test_bytes = out.tell() | ||||||
|                 self.assertEqual(im.size, (640, 480)) |     out.seek(0) | ||||||
|                 self.assertEqual(im.format, "MPO") |     im = Image.open(out) | ||||||
|  |     im.bytes = test_bytes  # for testing only | ||||||
|  |     return im | ||||||
| 
 | 
 | ||||||
|     @unittest.skipIf(is_pypy(), "Requires CPython") | 
 | ||||||
|     def test_unclosed_file(self): | def test_sanity(): | ||||||
|         def open(): |     for test_file in test_files: | ||||||
|             im = Image.open(test_files[0]) |         with Image.open(test_file) as im: | ||||||
|  |             im.load() | ||||||
|  |             assert im.mode == "RGB" | ||||||
|  |             assert im.size == (640, 480) | ||||||
|  |             assert im.format == "MPO" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||||
|  | def test_unclosed_file(): | ||||||
|  |     def open(): | ||||||
|  |         im = Image.open(test_files[0]) | ||||||
|  |         im.load() | ||||||
|  | 
 | ||||||
|  |     pytest.warns(ResourceWarning, open) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_closed_file(): | ||||||
|  |     def open(): | ||||||
|  |         im = Image.open(test_files[0]) | ||||||
|  |         im.load() | ||||||
|  |         im.close() | ||||||
|  | 
 | ||||||
|  |     pytest.warns(None, open) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_context_manager(): | ||||||
|  |     def open(): | ||||||
|  |         with Image.open(test_files[0]) as im: | ||||||
|             im.load() |             im.load() | ||||||
| 
 | 
 | ||||||
|         pytest.warns(ResourceWarning, open) |     pytest.warns(None, open) | ||||||
| 
 | 
 | ||||||
|     def test_closed_file(self): |  | ||||||
|         def open(): |  | ||||||
|             im = Image.open(test_files[0]) |  | ||||||
|             im.load() |  | ||||||
|             im.close() |  | ||||||
| 
 | 
 | ||||||
|         pytest.warns(None, open) | def test_app(): | ||||||
| 
 |     for test_file in test_files: | ||||||
|     def test_context_manager(self): |         # Test APP/COM reader (@PIL135) | ||||||
|         def open(): |         with Image.open(test_file) as im: | ||||||
|             with Image.open(test_files[0]) as im: |             assert im.applist[0][0] == "APP1" | ||||||
|                 im.load() |             assert im.applist[1][0] == "APP2" | ||||||
| 
 |             assert ( | ||||||
|         pytest.warns(None, open) |                 im.applist[1][1][:16] | ||||||
| 
 |                 == b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00" | ||||||
|     def test_app(self): |  | ||||||
|         for test_file in test_files: |  | ||||||
|             # Test APP/COM reader (@PIL135) |  | ||||||
|             with Image.open(test_file) as im: |  | ||||||
|                 self.assertEqual(im.applist[0][0], "APP1") |  | ||||||
|                 self.assertEqual(im.applist[1][0], "APP2") |  | ||||||
|                 self.assertEqual( |  | ||||||
|                     im.applist[1][1][:16], |  | ||||||
|                     b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00", |  | ||||||
|                 ) |  | ||||||
|                 self.assertEqual(len(im.applist), 2) |  | ||||||
| 
 |  | ||||||
|     def test_exif(self): |  | ||||||
|         for test_file in test_files: |  | ||||||
|             with Image.open(test_file) as im: |  | ||||||
|                 info = im._getexif() |  | ||||||
|                 self.assertEqual(info[272], "Nintendo 3DS") |  | ||||||
|                 self.assertEqual(info[296], 2) |  | ||||||
|                 self.assertEqual(info[34665], 188) |  | ||||||
| 
 |  | ||||||
|     def test_frame_size(self): |  | ||||||
|         # This image has been hexedited to contain a different size |  | ||||||
|         # in the EXIF data of the second frame |  | ||||||
|         with Image.open("Tests/images/sugarshack_frame_size.mpo") as im: |  | ||||||
|             self.assertEqual(im.size, (640, 480)) |  | ||||||
| 
 |  | ||||||
|             im.seek(1) |  | ||||||
|             self.assertEqual(im.size, (680, 480)) |  | ||||||
| 
 |  | ||||||
|     def test_parallax(self): |  | ||||||
|         # Nintendo |  | ||||||
|         with Image.open("Tests/images/sugarshack.mpo") as im: |  | ||||||
|             exif = im.getexif() |  | ||||||
|             self.assertEqual( |  | ||||||
|                 exif.get_ifd(0x927C)[0x1101]["Parallax"], -44.798187255859375 |  | ||||||
|             ) |             ) | ||||||
|  |             assert len(im.applist) == 2 | ||||||
| 
 | 
 | ||||||
|         # Fujifilm |  | ||||||
|         with Image.open("Tests/images/fujifilm.mpo") as im: |  | ||||||
|             im.seek(1) |  | ||||||
|             exif = im.getexif() |  | ||||||
|             self.assertEqual(exif.get_ifd(0x927C)[0xB211], -3.125) |  | ||||||
| 
 | 
 | ||||||
|     def test_mp(self): | def test_exif(): | ||||||
|         for test_file in test_files: |     for test_file in test_files: | ||||||
|             with Image.open(test_file) as im: |         with Image.open(test_file) as im: | ||||||
|                 mpinfo = im._getmp() |             info = im._getexif() | ||||||
|                 self.assertEqual(mpinfo[45056], b"0100") |             assert info[272] == "Nintendo 3DS" | ||||||
|                 self.assertEqual(mpinfo[45057], 2) |             assert info[296] == 2 | ||||||
|  |             assert info[34665] == 188 | ||||||
| 
 | 
 | ||||||
|     def test_mp_offset(self): | 
 | ||||||
|         # This image has been manually hexedited to have an IFD offset of 10 | def test_frame_size(): | ||||||
|         # in APP2 data, in contrast to normal 8 |     # This image has been hexedited to contain a different size | ||||||
|         with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im: |     # in the EXIF data of the second frame | ||||||
|  |     with Image.open("Tests/images/sugarshack_frame_size.mpo") as im: | ||||||
|  |         assert im.size == (640, 480) | ||||||
|  | 
 | ||||||
|  |         im.seek(1) | ||||||
|  |         assert im.size == (680, 480) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_parallax(): | ||||||
|  |     # Nintendo | ||||||
|  |     with Image.open("Tests/images/sugarshack.mpo") as im: | ||||||
|  |         exif = im.getexif() | ||||||
|  |         assert exif.get_ifd(0x927C)[0x1101]["Parallax"] == -44.798187255859375 | ||||||
|  | 
 | ||||||
|  |     # Fujifilm | ||||||
|  |     with Image.open("Tests/images/fujifilm.mpo") as im: | ||||||
|  |         im.seek(1) | ||||||
|  |         exif = im.getexif() | ||||||
|  |         assert exif.get_ifd(0x927C)[0xB211] == -3.125 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_mp(): | ||||||
|  |     for test_file in test_files: | ||||||
|  |         with Image.open(test_file) as im: | ||||||
|             mpinfo = im._getmp() |             mpinfo = im._getmp() | ||||||
|             self.assertEqual(mpinfo[45056], b"0100") |             assert mpinfo[45056] == b"0100" | ||||||
|             self.assertEqual(mpinfo[45057], 2) |             assert mpinfo[45057] == 2 | ||||||
| 
 | 
 | ||||||
|     def test_mp_no_data(self): |  | ||||||
|         # This image has been manually hexedited to have the second frame |  | ||||||
|         # beyond the end of the file |  | ||||||
|         with Image.open("Tests/images/sugarshack_no_data.mpo") as im: |  | ||||||
|             with self.assertRaises(ValueError): |  | ||||||
|                 im.seek(1) |  | ||||||
| 
 | 
 | ||||||
|     def test_mp_attribute(self): | def test_mp_offset(): | ||||||
|         for test_file in test_files: |     # This image has been manually hexedited to have an IFD offset of 10 | ||||||
|             with Image.open(test_file) as im: |     # in APP2 data, in contrast to normal 8 | ||||||
|                 mpinfo = im._getmp() |     with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im: | ||||||
|             frameNumber = 0 |         mpinfo = im._getmp() | ||||||
|             for mpentry in mpinfo[45058]: |         assert mpinfo[45056] == b"0100" | ||||||
|                 mpattr = mpentry["Attribute"] |         assert mpinfo[45057] == 2 | ||||||
|                 if frameNumber: |  | ||||||
|                     self.assertFalse(mpattr["RepresentativeImageFlag"]) |  | ||||||
|                 else: |  | ||||||
|                     self.assertTrue(mpattr["RepresentativeImageFlag"]) |  | ||||||
|                 self.assertFalse(mpattr["DependentParentImageFlag"]) |  | ||||||
|                 self.assertFalse(mpattr["DependentChildImageFlag"]) |  | ||||||
|                 self.assertEqual(mpattr["ImageDataFormat"], "JPEG") |  | ||||||
|                 self.assertEqual(mpattr["MPType"], "Multi-Frame Image: (Disparity)") |  | ||||||
|                 self.assertEqual(mpattr["Reserved"], 0) |  | ||||||
|                 frameNumber += 1 |  | ||||||
| 
 | 
 | ||||||
|     def test_seek(self): |  | ||||||
|         for test_file in test_files: |  | ||||||
|             with Image.open(test_file) as im: |  | ||||||
|                 self.assertEqual(im.tell(), 0) |  | ||||||
|                 # prior to first image raises an error, both blatant and borderline |  | ||||||
|                 self.assertRaises(EOFError, im.seek, -1) |  | ||||||
|                 self.assertRaises(EOFError, im.seek, -523) |  | ||||||
|                 # after the final image raises an error, |  | ||||||
|                 # both blatant and borderline |  | ||||||
|                 self.assertRaises(EOFError, im.seek, 2) |  | ||||||
|                 self.assertRaises(EOFError, im.seek, 523) |  | ||||||
|                 # bad calls shouldn't change the frame |  | ||||||
|                 self.assertEqual(im.tell(), 0) |  | ||||||
|                 # this one will work |  | ||||||
|                 im.seek(1) |  | ||||||
|                 self.assertEqual(im.tell(), 1) |  | ||||||
|                 # and this one, too |  | ||||||
|                 im.seek(0) |  | ||||||
|                 self.assertEqual(im.tell(), 0) |  | ||||||
| 
 | 
 | ||||||
|     def test_n_frames(self): | def test_mp_no_data(): | ||||||
|         with Image.open("Tests/images/sugarshack.mpo") as im: |     # This image has been manually hexedited to have the second frame | ||||||
|             self.assertEqual(im.n_frames, 2) |     # beyond the end of the file | ||||||
|             self.assertTrue(im.is_animated) |     with Image.open("Tests/images/sugarshack_no_data.mpo") as im: | ||||||
|  |         with pytest.raises(ValueError): | ||||||
|  |             im.seek(1) | ||||||
| 
 | 
 | ||||||
|     def test_eoferror(self): |  | ||||||
|         with Image.open("Tests/images/sugarshack.mpo") as im: |  | ||||||
|             n_frames = im.n_frames |  | ||||||
| 
 | 
 | ||||||
|             # Test seeking past the last frame | def test_mp_attribute(): | ||||||
|             self.assertRaises(EOFError, im.seek, n_frames) |     for test_file in test_files: | ||||||
|             self.assertLess(im.tell(), n_frames) |         with Image.open(test_file) as im: | ||||||
|  |             mpinfo = im._getmp() | ||||||
|  |         frameNumber = 0 | ||||||
|  |         for mpentry in mpinfo[45058]: | ||||||
|  |             mpattr = mpentry["Attribute"] | ||||||
|  |             if frameNumber: | ||||||
|  |                 assert not mpattr["RepresentativeImageFlag"] | ||||||
|  |             else: | ||||||
|  |                 assert mpattr["RepresentativeImageFlag"] | ||||||
|  |             assert not mpattr["DependentParentImageFlag"] | ||||||
|  |             assert not mpattr["DependentChildImageFlag"] | ||||||
|  |             assert mpattr["ImageDataFormat"] == "JPEG" | ||||||
|  |             assert mpattr["MPType"] == "Multi-Frame Image: (Disparity)" | ||||||
|  |             assert mpattr["Reserved"] == 0 | ||||||
|  |             frameNumber += 1 | ||||||
| 
 | 
 | ||||||
|             # Test that seeking to the last frame does not raise an error |  | ||||||
|             im.seek(n_frames - 1) |  | ||||||
| 
 | 
 | ||||||
|     def test_image_grab(self): | def test_seek(): | ||||||
|         for test_file in test_files: |     for test_file in test_files: | ||||||
|             with Image.open(test_file) as im: |         with Image.open(test_file) as im: | ||||||
|                 self.assertEqual(im.tell(), 0) |             assert im.tell() == 0 | ||||||
|                 im0 = im.tobytes() |             # prior to first image raises an error, both blatant and borderline | ||||||
|                 im.seek(1) |             with pytest.raises(EOFError): | ||||||
|                 self.assertEqual(im.tell(), 1) |                 im.seek(-1) | ||||||
|                 im1 = im.tobytes() |             with pytest.raises(EOFError): | ||||||
|                 im.seek(0) |                 im.seek(-523) | ||||||
|                 self.assertEqual(im.tell(), 0) |             # after the final image raises an error, | ||||||
|                 im02 = im.tobytes() |             # both blatant and borderline | ||||||
|                 self.assertEqual(im0, im02) |             with pytest.raises(EOFError): | ||||||
|                 self.assertNotEqual(im0, im1) |                 im.seek(2) | ||||||
|  |             with pytest.raises(EOFError): | ||||||
|  |                 im.seek(523) | ||||||
|  |             # bad calls shouldn't change the frame | ||||||
|  |             assert im.tell() == 0 | ||||||
|  |             # this one will work | ||||||
|  |             im.seek(1) | ||||||
|  |             assert im.tell() == 1 | ||||||
|  |             # and this one, too | ||||||
|  |             im.seek(0) | ||||||
|  |             assert im.tell() == 0 | ||||||
| 
 | 
 | ||||||
|     def test_save(self): | 
 | ||||||
|         # Note that only individual frames can be saved at present | def test_n_frames(): | ||||||
|         for test_file in test_files: |     with Image.open("Tests/images/sugarshack.mpo") as im: | ||||||
|             with Image.open(test_file) as im: |         assert im.n_frames == 2 | ||||||
|                 self.assertEqual(im.tell(), 0) |         assert im.is_animated | ||||||
|                 jpg0 = self.frame_roundtrip(im) | 
 | ||||||
|                 assert_image_similar(im, jpg0, 30) | 
 | ||||||
|                 im.seek(1) | def test_eoferror(): | ||||||
|                 self.assertEqual(im.tell(), 1) |     with Image.open("Tests/images/sugarshack.mpo") as im: | ||||||
|                 jpg1 = self.frame_roundtrip(im) |         n_frames = im.n_frames | ||||||
|                 assert_image_similar(im, jpg1, 30) | 
 | ||||||
|  |         # Test seeking past the last frame | ||||||
|  |         with pytest.raises(EOFError): | ||||||
|  |             im.seek(n_frames) | ||||||
|  |         assert im.tell() < n_frames | ||||||
|  | 
 | ||||||
|  |         # Test that seeking to the last frame does not raise an error | ||||||
|  |         im.seek(n_frames - 1) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_image_grab(): | ||||||
|  |     for test_file in test_files: | ||||||
|  |         with Image.open(test_file) as im: | ||||||
|  |             assert im.tell() == 0 | ||||||
|  |             im0 = im.tobytes() | ||||||
|  |             im.seek(1) | ||||||
|  |             assert im.tell() == 1 | ||||||
|  |             im1 = im.tobytes() | ||||||
|  |             im.seek(0) | ||||||
|  |             assert im.tell() == 0 | ||||||
|  |             im02 = im.tobytes() | ||||||
|  |             assert im0 == im02 | ||||||
|  |             assert im0 != im1 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_save(): | ||||||
|  |     # Note that only individual frames can be saved at present | ||||||
|  |     for test_file in test_files: | ||||||
|  |         with Image.open(test_file) as im: | ||||||
|  |             assert im.tell() == 0 | ||||||
|  |             jpg0 = frame_roundtrip(im) | ||||||
|  |             assert_image_similar(im, jpg0, 30) | ||||||
|  |             im.seek(1) | ||||||
|  |             assert im.tell() == 1 | ||||||
|  |             jpg1 = frame_roundtrip(im) | ||||||
|  |             assert_image_similar(im, jpg1, 30) | ||||||
|  |  | ||||||
|  | @ -1,23 +1,25 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image, PixarImagePlugin | from PIL import Image, PixarImagePlugin | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_similar, hopper | from .helper import assert_image_similar, hopper | ||||||
| 
 | 
 | ||||||
| TEST_FILE = "Tests/images/hopper.pxr" | TEST_FILE = "Tests/images/hopper.pxr" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFilePixar(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     with Image.open(TEST_FILE) as im: | ||||||
|         with Image.open(TEST_FILE) as im: |         im.load() | ||||||
|             im.load() |         assert im.mode == "RGB" | ||||||
|             self.assertEqual(im.mode, "RGB") |         assert im.size == (128, 128) | ||||||
|             self.assertEqual(im.size, (128, 128)) |         assert im.format == "PIXAR" | ||||||
|             self.assertEqual(im.format, "PIXAR") |         assert im.get_format_mimetype() is None | ||||||
|             self.assertIsNone(im.get_format_mimetype()) |  | ||||||
| 
 | 
 | ||||||
|             im2 = hopper() |         im2 = hopper() | ||||||
|             assert_image_similar(im, im2, 4.8) |         assert_image_similar(im, im2, 4.8) | ||||||
| 
 | 
 | ||||||
|     def test_invalid_file(self): |  | ||||||
|         invalid_file = "Tests/images/flower.jpg" |  | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(SyntaxError, PixarImagePlugin.PixarImageFile, invalid_file) | def test_invalid_file(): | ||||||
|  |     invalid_file = "Tests/images/flower.jpg" | ||||||
|  | 
 | ||||||
|  |     with pytest.raises(SyntaxError): | ||||||
|  |         PixarImagePlugin.PixarImageFile(invalid_file) | ||||||
|  |  | ||||||
|  | @ -1,116 +1,129 @@ | ||||||
| import unittest |  | ||||||
| 
 |  | ||||||
| import pytest | import pytest | ||||||
| from PIL import Image, PsdImagePlugin | from PIL import Image, PsdImagePlugin | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_similar, hopper, is_pypy | from .helper import assert_image_similar, hopper, is_pypy | ||||||
| 
 | 
 | ||||||
| test_file = "Tests/images/hopper.psd" | test_file = "Tests/images/hopper.psd" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImagePsd(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     with Image.open(test_file) as im: | ||||||
|  |         im.load() | ||||||
|  |         assert im.mode == "RGB" | ||||||
|  |         assert im.size == (128, 128) | ||||||
|  |         assert im.format == "PSD" | ||||||
|  | 
 | ||||||
|  |         im2 = hopper() | ||||||
|  |         assert_image_similar(im, im2, 4.8) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||||
|  | def test_unclosed_file(): | ||||||
|  |     def open(): | ||||||
|  |         im = Image.open(test_file) | ||||||
|  |         im.load() | ||||||
|  | 
 | ||||||
|  |     pytest.warns(ResourceWarning, open) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_closed_file(): | ||||||
|  |     def open(): | ||||||
|  |         im = Image.open(test_file) | ||||||
|  |         im.load() | ||||||
|  |         im.close() | ||||||
|  | 
 | ||||||
|  |     pytest.warns(None, open) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_context_manager(): | ||||||
|  |     def open(): | ||||||
|         with Image.open(test_file) as im: |         with Image.open(test_file) as im: | ||||||
|             im.load() |             im.load() | ||||||
|             self.assertEqual(im.mode, "RGB") |  | ||||||
|             self.assertEqual(im.size, (128, 128)) |  | ||||||
|             self.assertEqual(im.format, "PSD") |  | ||||||
| 
 | 
 | ||||||
|             im2 = hopper() |     pytest.warns(None, open) | ||||||
|             assert_image_similar(im, im2, 4.8) |  | ||||||
| 
 | 
 | ||||||
|     @unittest.skipIf(is_pypy(), "Requires CPython") |  | ||||||
|     def test_unclosed_file(self): |  | ||||||
|         def open(): |  | ||||||
|             im = Image.open(test_file) |  | ||||||
|             im.load() |  | ||||||
| 
 | 
 | ||||||
|         pytest.warns(ResourceWarning, open) | def test_invalid_file(): | ||||||
|  |     invalid_file = "Tests/images/flower.jpg" | ||||||
| 
 | 
 | ||||||
|     def test_closed_file(self): |     with pytest.raises(SyntaxError): | ||||||
|         def open(): |         PsdImagePlugin.PsdImageFile(invalid_file) | ||||||
|             im = Image.open(test_file) |  | ||||||
|             im.load() |  | ||||||
|             im.close() |  | ||||||
| 
 | 
 | ||||||
|         pytest.warns(None, open) |  | ||||||
| 
 | 
 | ||||||
|     def test_context_manager(self): | def test_n_frames(): | ||||||
|         def open(): |     with Image.open("Tests/images/hopper_merged.psd") as im: | ||||||
|             with Image.open(test_file) as im: |         assert im.n_frames == 1 | ||||||
|                 im.load() |         assert not im.is_animated | ||||||
| 
 | 
 | ||||||
|         pytest.warns(None, open) |     with Image.open(test_file) as im: | ||||||
|  |         assert im.n_frames == 2 | ||||||
|  |         assert im.is_animated | ||||||
| 
 | 
 | ||||||
|     def test_invalid_file(self): |  | ||||||
|         invalid_file = "Tests/images/flower.jpg" |  | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(SyntaxError, PsdImagePlugin.PsdImageFile, invalid_file) | def test_eoferror(): | ||||||
|  |     with Image.open(test_file) as im: | ||||||
|  |         # PSD seek index starts at 1 rather than 0 | ||||||
|  |         n_frames = im.n_frames + 1 | ||||||
| 
 | 
 | ||||||
|     def test_n_frames(self): |         # Test seeking past the last frame | ||||||
|         with Image.open("Tests/images/hopper_merged.psd") as im: |         with pytest.raises(EOFError): | ||||||
|             self.assertEqual(im.n_frames, 1) |             im.seek(n_frames) | ||||||
|             self.assertFalse(im.is_animated) |         assert im.tell() < n_frames | ||||||
| 
 | 
 | ||||||
|         with Image.open(test_file) as im: |         # Test that seeking to the last frame does not raise an error | ||||||
|             self.assertEqual(im.n_frames, 2) |         im.seek(n_frames - 1) | ||||||
|             self.assertTrue(im.is_animated) |  | ||||||
| 
 | 
 | ||||||
|     def test_eoferror(self): |  | ||||||
|         with Image.open(test_file) as im: |  | ||||||
|             # PSD seek index starts at 1 rather than 0 |  | ||||||
|             n_frames = im.n_frames + 1 |  | ||||||
| 
 | 
 | ||||||
|             # Test seeking past the last frame | def test_seek_tell(): | ||||||
|             self.assertRaises(EOFError, im.seek, n_frames) |     with Image.open(test_file) as im: | ||||||
|             self.assertLess(im.tell(), n_frames) |  | ||||||
| 
 | 
 | ||||||
|             # Test that seeking to the last frame does not raise an error |         layer_number = im.tell() | ||||||
|             im.seek(n_frames - 1) |         assert layer_number == 1 | ||||||
| 
 | 
 | ||||||
|     def test_seek_tell(self): |         with pytest.raises(EOFError): | ||||||
|         with Image.open(test_file) as im: |             im.seek(0) | ||||||
| 
 | 
 | ||||||
|             layer_number = im.tell() |         im.seek(1) | ||||||
|             self.assertEqual(layer_number, 1) |         layer_number = im.tell() | ||||||
|  |         assert layer_number == 1 | ||||||
| 
 | 
 | ||||||
|             self.assertRaises(EOFError, im.seek, 0) |         im.seek(2) | ||||||
|  |         layer_number = im.tell() | ||||||
|  |         assert layer_number == 2 | ||||||
| 
 | 
 | ||||||
|             im.seek(1) |  | ||||||
|             layer_number = im.tell() |  | ||||||
|             self.assertEqual(layer_number, 1) |  | ||||||
| 
 | 
 | ||||||
|             im.seek(2) | def test_seek_eoferror(): | ||||||
|             layer_number = im.tell() |     with Image.open(test_file) as im: | ||||||
|             self.assertEqual(layer_number, 2) |  | ||||||
| 
 | 
 | ||||||
|     def test_seek_eoferror(self): |         with pytest.raises(EOFError): | ||||||
|         with Image.open(test_file) as im: |             im.seek(-1) | ||||||
| 
 | 
 | ||||||
|             self.assertRaises(EOFError, im.seek, -1) |  | ||||||
| 
 | 
 | ||||||
|     def test_open_after_exclusive_load(self): | def test_open_after_exclusive_load(): | ||||||
|         with Image.open(test_file) as im: |     with Image.open(test_file) as im: | ||||||
|             im.load() |         im.load() | ||||||
|             im.seek(im.tell() + 1) |         im.seek(im.tell() + 1) | ||||||
|             im.load() |         im.load() | ||||||
| 
 | 
 | ||||||
|     def test_icc_profile(self): |  | ||||||
|         with Image.open(test_file) as im: |  | ||||||
|             self.assertIn("icc_profile", im.info) |  | ||||||
| 
 | 
 | ||||||
|             icc_profile = im.info["icc_profile"] | def test_icc_profile(): | ||||||
|             self.assertEqual(len(icc_profile), 3144) |     with Image.open(test_file) as im: | ||||||
|  |         assert "icc_profile" in im.info | ||||||
| 
 | 
 | ||||||
|     def test_no_icc_profile(self): |         icc_profile = im.info["icc_profile"] | ||||||
|         with Image.open("Tests/images/hopper_merged.psd") as im: |         assert len(icc_profile) == 3144 | ||||||
|             self.assertNotIn("icc_profile", im.info) |  | ||||||
| 
 | 
 | ||||||
|     def test_combined_larger_than_size(self): |  | ||||||
|         # The 'combined' sizes of the individual parts is larger than the |  | ||||||
|         # declared 'size' of the extra data field, resulting in a backwards seek. |  | ||||||
| 
 | 
 | ||||||
|         # If we instead take the 'size' of the extra data field as the source of truth, | def test_no_icc_profile(): | ||||||
|         # then the seek can't be negative |     with Image.open("Tests/images/hopper_merged.psd") as im: | ||||||
|         with self.assertRaises(IOError): |         assert "icc_profile" not in im.info | ||||||
|             Image.open("Tests/images/combined_larger_than_size.psd") | 
 | ||||||
|  | 
 | ||||||
|  | def test_combined_larger_than_size(): | ||||||
|  |     # The 'combined' sizes of the individual parts is larger than the | ||||||
|  |     # declared 'size' of the extra data field, resulting in a backwards seek. | ||||||
|  | 
 | ||||||
|  |     # If we instead take the 'size' of the extra data field as the source of truth, | ||||||
|  |     # then the seek can't be negative | ||||||
|  |     with pytest.raises(IOError): | ||||||
|  |         Image.open("Tests/images/combined_larger_than_size.psd") | ||||||
|  |  | ||||||
|  | @ -1,47 +1,51 @@ | ||||||
| import os | import os | ||||||
| import unittest |  | ||||||
| 
 | 
 | ||||||
|  | import pytest | ||||||
| from PIL import Image, SunImagePlugin | from PIL import Image, SunImagePlugin | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper | from .helper import assert_image_equal, assert_image_similar, hopper | ||||||
| 
 | 
 | ||||||
| EXTRA_DIR = "Tests/images/sunraster" | EXTRA_DIR = "Tests/images/sunraster" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFileSun(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     # Arrange | ||||||
|         # Arrange |     # Created with ImageMagick: convert hopper.jpg hopper.ras | ||||||
|         # Created with ImageMagick: convert hopper.jpg hopper.ras |     test_file = "Tests/images/hopper.ras" | ||||||
|         test_file = "Tests/images/hopper.ras" |  | ||||||
| 
 | 
 | ||||||
|         # Act |     # Act | ||||||
|         with Image.open(test_file) as im: |     with Image.open(test_file) as im: | ||||||
| 
 | 
 | ||||||
|             # Assert |         # Assert | ||||||
|             self.assertEqual(im.size, (128, 128)) |         assert im.size == (128, 128) | ||||||
| 
 | 
 | ||||||
|             assert_image_similar(im, hopper(), 5)  # visually verified |         assert_image_similar(im, hopper(), 5)  # visually verified | ||||||
| 
 | 
 | ||||||
|         invalid_file = "Tests/images/flower.jpg" |     invalid_file = "Tests/images/flower.jpg" | ||||||
|         self.assertRaises(SyntaxError, SunImagePlugin.SunImageFile, invalid_file) |     with pytest.raises(SyntaxError): | ||||||
|  |         SunImagePlugin.SunImageFile(invalid_file) | ||||||
| 
 | 
 | ||||||
|     def test_im1(self): | 
 | ||||||
|         with Image.open("Tests/images/sunraster.im1") as im: | def test_im1(): | ||||||
|             with Image.open("Tests/images/sunraster.im1.png") as target: |     with Image.open("Tests/images/sunraster.im1") as im: | ||||||
|  |         with Image.open("Tests/images/sunraster.im1.png") as target: | ||||||
|  |             assert_image_equal(im, target) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.skipif( | ||||||
|  |     not os.path.exists(EXTRA_DIR), reason="Extra image files not installed" | ||||||
|  | ) | ||||||
|  | def test_others(): | ||||||
|  |     files = ( | ||||||
|  |         os.path.join(EXTRA_DIR, f) | ||||||
|  |         for f in os.listdir(EXTRA_DIR) | ||||||
|  |         if os.path.splitext(f)[1] in (".sun", ".SUN", ".ras") | ||||||
|  |     ) | ||||||
|  |     for path in files: | ||||||
|  |         with Image.open(path) as im: | ||||||
|  |             im.load() | ||||||
|  |             assert isinstance(im, SunImagePlugin.SunImageFile) | ||||||
|  |             target_path = "%s.png" % os.path.splitext(path)[0] | ||||||
|  |             # im.save(target_file) | ||||||
|  |             with Image.open(target_path) as target: | ||||||
|                 assert_image_equal(im, target) |                 assert_image_equal(im, target) | ||||||
| 
 |  | ||||||
|     @unittest.skipUnless(os.path.exists(EXTRA_DIR), "Extra image files not installed") |  | ||||||
|     def test_others(self): |  | ||||||
|         files = ( |  | ||||||
|             os.path.join(EXTRA_DIR, f) |  | ||||||
|             for f in os.listdir(EXTRA_DIR) |  | ||||||
|             if os.path.splitext(f)[1] in (".sun", ".SUN", ".ras") |  | ||||||
|         ) |  | ||||||
|         for path in files: |  | ||||||
|             with Image.open(path) as im: |  | ||||||
|                 im.load() |  | ||||||
|                 self.assertIsInstance(im, SunImagePlugin.SunImageFile) |  | ||||||
|                 target_path = "%s.png" % os.path.splitext(path)[0] |  | ||||||
|                 # im.save(target_file) |  | ||||||
|                 with Image.open(target_path) as target: |  | ||||||
|                     assert_image_equal(im, target) |  | ||||||
|  |  | ||||||
|  | @ -1,9 +1,7 @@ | ||||||
| import unittest |  | ||||||
| 
 |  | ||||||
| import pytest | import pytest | ||||||
| from PIL import Image, TarIO | from PIL import Image, TarIO | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, is_pypy | from .helper import is_pypy | ||||||
| 
 | 
 | ||||||
| codecs = dir(Image.core) | codecs = dir(Image.core) | ||||||
| 
 | 
 | ||||||
|  | @ -11,41 +9,44 @@ codecs = dir(Image.core) | ||||||
| TEST_TAR_FILE = "Tests/images/hopper.tar" | TEST_TAR_FILE = "Tests/images/hopper.tar" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFileTar(PillowTestCase): | def setup_module(): | ||||||
|     def setUp(self): |     if "zip_decoder" not in codecs and "jpeg_decoder" not in codecs: | ||||||
|         if "zip_decoder" not in codecs and "jpeg_decoder" not in codecs: |         pytest.skip("neither jpeg nor zip support available") | ||||||
|             self.skipTest("neither jpeg nor zip support available") |  | ||||||
| 
 | 
 | ||||||
|     def test_sanity(self): |  | ||||||
|         for codec, test_path, format in [ |  | ||||||
|             ["zip_decoder", "hopper.png", "PNG"], |  | ||||||
|             ["jpeg_decoder", "hopper.jpg", "JPEG"], |  | ||||||
|         ]: |  | ||||||
|             if codec in codecs: |  | ||||||
|                 with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar: |  | ||||||
|                     with Image.open(tar) as im: |  | ||||||
|                         im.load() |  | ||||||
|                         self.assertEqual(im.mode, "RGB") |  | ||||||
|                         self.assertEqual(im.size, (128, 128)) |  | ||||||
|                         self.assertEqual(im.format, format) |  | ||||||
| 
 | 
 | ||||||
|     @unittest.skipIf(is_pypy(), "Requires CPython") | def test_sanity(): | ||||||
|     def test_unclosed_file(self): |     for codec, test_path, format in [ | ||||||
|         def open(): |         ["zip_decoder", "hopper.png", "PNG"], | ||||||
|             TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") |         ["jpeg_decoder", "hopper.jpg", "JPEG"], | ||||||
|  |     ]: | ||||||
|  |         if codec in codecs: | ||||||
|  |             with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar: | ||||||
|  |                 with Image.open(tar) as im: | ||||||
|  |                     im.load() | ||||||
|  |                     assert im.mode == "RGB" | ||||||
|  |                     assert im.size == (128, 128) | ||||||
|  |                     assert im.format == format | ||||||
| 
 | 
 | ||||||
|         pytest.warns(ResourceWarning, open) |  | ||||||
| 
 | 
 | ||||||
|     def test_close(self): | @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||||
|         def open(): | def test_unclosed_file(): | ||||||
|             tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") |     def open(): | ||||||
|             tar.close() |         TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") | ||||||
| 
 | 
 | ||||||
|         pytest.warns(None, open) |     pytest.warns(ResourceWarning, open) | ||||||
| 
 | 
 | ||||||
|     def test_contextmanager(self): |  | ||||||
|         def open(): |  | ||||||
|             with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"): |  | ||||||
|                 pass |  | ||||||
| 
 | 
 | ||||||
|         pytest.warns(None, open) | def test_close(): | ||||||
|  |     def open(): | ||||||
|  |         tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") | ||||||
|  |         tar.close() | ||||||
|  | 
 | ||||||
|  |     pytest.warns(None, open) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_contextmanager(): | ||||||
|  |     def open(): | ||||||
|  |         with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"): | ||||||
|  |             pass | ||||||
|  | 
 | ||||||
|  |     pytest.warns(None, open) | ||||||
|  |  | ||||||
|  | @ -1,33 +1,36 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image, XpmImagePlugin | from PIL import Image, XpmImagePlugin | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_similar, hopper | from .helper import assert_image_similar, hopper | ||||||
| 
 | 
 | ||||||
| TEST_FILE = "Tests/images/hopper.xpm" | TEST_FILE = "Tests/images/hopper.xpm" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFileXpm(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     with Image.open(TEST_FILE) as im: | ||||||
|         with Image.open(TEST_FILE) as im: |         im.load() | ||||||
|             im.load() |         assert im.mode == "P" | ||||||
|             self.assertEqual(im.mode, "P") |         assert im.size == (128, 128) | ||||||
|             self.assertEqual(im.size, (128, 128)) |         assert im.format == "XPM" | ||||||
|             self.assertEqual(im.format, "XPM") |  | ||||||
| 
 | 
 | ||||||
|             # large error due to quantization->44 colors. |         # large error due to quantization->44 colors. | ||||||
|             assert_image_similar(im.convert("RGB"), hopper("RGB"), 60) |         assert_image_similar(im.convert("RGB"), hopper("RGB"), 60) | ||||||
| 
 | 
 | ||||||
|     def test_invalid_file(self): |  | ||||||
|         invalid_file = "Tests/images/flower.jpg" |  | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(SyntaxError, XpmImagePlugin.XpmImageFile, invalid_file) | def test_invalid_file(): | ||||||
|  |     invalid_file = "Tests/images/flower.jpg" | ||||||
| 
 | 
 | ||||||
|     def test_load_read(self): |     with pytest.raises(SyntaxError): | ||||||
|         # Arrange |         XpmImagePlugin.XpmImageFile(invalid_file) | ||||||
|         with Image.open(TEST_FILE) as im: |  | ||||||
|             dummy_bytes = 1 |  | ||||||
| 
 | 
 | ||||||
|             # Act |  | ||||||
|             data = im.load_read(dummy_bytes) |  | ||||||
| 
 | 
 | ||||||
|         # Assert | def test_load_read(): | ||||||
|         self.assertEqual(len(data), 16384) |     # Arrange | ||||||
|  |     with Image.open(TEST_FILE) as im: | ||||||
|  |         dummy_bytes = 1 | ||||||
|  | 
 | ||||||
|  |         # Act | ||||||
|  |         data = im.load_read(dummy_bytes) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert len(data) == 16384 | ||||||
|  |  | ||||||
|  | @ -1,35 +1,37 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image, XVThumbImagePlugin | from PIL import Image, XVThumbImagePlugin | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_similar, hopper | from .helper import assert_image_similar, hopper | ||||||
| 
 | 
 | ||||||
| TEST_FILE = "Tests/images/hopper.p7" | TEST_FILE = "Tests/images/hopper.p7" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFileXVThumb(PillowTestCase): | def test_open(): | ||||||
|     def test_open(self): |     # Act | ||||||
|         # Act |     with Image.open(TEST_FILE) as im: | ||||||
|         with Image.open(TEST_FILE) as im: |  | ||||||
| 
 | 
 | ||||||
|             # Assert |         # Assert | ||||||
|             self.assertEqual(im.format, "XVThumb") |         assert im.format == "XVThumb" | ||||||
| 
 | 
 | ||||||
|             # Create a Hopper image with a similar XV palette |         # Create a Hopper image with a similar XV palette | ||||||
|             im_hopper = hopper().quantize(palette=im) |         im_hopper = hopper().quantize(palette=im) | ||||||
|             assert_image_similar(im, im_hopper, 9) |         assert_image_similar(im, im_hopper, 9) | ||||||
| 
 | 
 | ||||||
|     def test_unexpected_eof(self): |  | ||||||
|         # Test unexpected EOF reading XV thumbnail file |  | ||||||
|         # Arrange |  | ||||||
|         bad_file = "Tests/images/hopper_bad.p7" |  | ||||||
| 
 | 
 | ||||||
|         # Act / Assert | def test_unexpected_eof(): | ||||||
|         self.assertRaises(SyntaxError, XVThumbImagePlugin.XVThumbImageFile, bad_file) |     # Test unexpected EOF reading XV thumbnail file | ||||||
|  |     # Arrange | ||||||
|  |     bad_file = "Tests/images/hopper_bad.p7" | ||||||
| 
 | 
 | ||||||
|     def test_invalid_file(self): |     # Act / Assert | ||||||
|         # Arrange |     with pytest.raises(SyntaxError): | ||||||
|         invalid_file = "Tests/images/flower.jpg" |         XVThumbImagePlugin.XVThumbImageFile(bad_file) | ||||||
| 
 | 
 | ||||||
|         # Act / Assert | 
 | ||||||
|         self.assertRaises( | def test_invalid_file(): | ||||||
|             SyntaxError, XVThumbImagePlugin.XVThumbImageFile, invalid_file |     # Arrange | ||||||
|         ) |     invalid_file = "Tests/images/flower.jpg" | ||||||
|  | 
 | ||||||
|  |     # Act / Assert | ||||||
|  |     with pytest.raises(SyntaxError): | ||||||
|  |         XVThumbImagePlugin.XVThumbImageFile(invalid_file) | ||||||
|  |  | ||||||
|  | @ -1,103 +1,109 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, hopper | from .helper import assert_image_equal, hopper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageCrop(PillowTestCase): | def test_crop(): | ||||||
|     def test_crop(self): |     def crop(mode): | ||||||
|         def crop(mode): |         im = hopper(mode) | ||||||
|             im = hopper(mode) |         assert_image_equal(im.crop(), im) | ||||||
|             assert_image_equal(im.crop(), im) |  | ||||||
| 
 | 
 | ||||||
|             cropped = im.crop((50, 50, 100, 100)) |         cropped = im.crop((50, 50, 100, 100)) | ||||||
|             self.assertEqual(cropped.mode, mode) |         assert cropped.mode == mode | ||||||
|             self.assertEqual(cropped.size, (50, 50)) |         assert cropped.size == (50, 50) | ||||||
| 
 | 
 | ||||||
|         for mode in "1", "P", "L", "RGB", "I", "F": |     for mode in "1", "P", "L", "RGB", "I", "F": | ||||||
|             crop(mode) |         crop(mode) | ||||||
| 
 | 
 | ||||||
|     def test_wide_crop(self): |  | ||||||
|         def crop(*bbox): |  | ||||||
|             i = im.crop(bbox) |  | ||||||
|             h = i.histogram() |  | ||||||
|             while h and not h[-1]: |  | ||||||
|                 del h[-1] |  | ||||||
|             return tuple(h) |  | ||||||
| 
 | 
 | ||||||
|         im = Image.new("L", (100, 100), 1) | def test_wide_crop(): | ||||||
|  |     def crop(*bbox): | ||||||
|  |         i = im.crop(bbox) | ||||||
|  |         h = i.histogram() | ||||||
|  |         while h and not h[-1]: | ||||||
|  |             del h[-1] | ||||||
|  |         return tuple(h) | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(crop(0, 0, 100, 100), (0, 10000)) |     im = Image.new("L", (100, 100), 1) | ||||||
|         self.assertEqual(crop(25, 25, 75, 75), (0, 2500)) |  | ||||||
| 
 | 
 | ||||||
|         # sides |     assert crop(0, 0, 100, 100) == (0, 10000) | ||||||
|         self.assertEqual(crop(-25, 0, 25, 50), (1250, 1250)) |     assert crop(25, 25, 75, 75) == (0, 2500) | ||||||
|         self.assertEqual(crop(0, -25, 50, 25), (1250, 1250)) |  | ||||||
|         self.assertEqual(crop(75, 0, 125, 50), (1250, 1250)) |  | ||||||
|         self.assertEqual(crop(0, 75, 50, 125), (1250, 1250)) |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(crop(-25, 25, 125, 75), (2500, 5000)) |     # sides | ||||||
|         self.assertEqual(crop(25, -25, 75, 125), (2500, 5000)) |     assert crop(-25, 0, 25, 50) == (1250, 1250) | ||||||
|  |     assert crop(0, -25, 50, 25) == (1250, 1250) | ||||||
|  |     assert crop(75, 0, 125, 50) == (1250, 1250) | ||||||
|  |     assert crop(0, 75, 50, 125) == (1250, 1250) | ||||||
| 
 | 
 | ||||||
|         # corners |     assert crop(-25, 25, 125, 75) == (2500, 5000) | ||||||
|         self.assertEqual(crop(-25, -25, 25, 25), (1875, 625)) |     assert crop(25, -25, 75, 125) == (2500, 5000) | ||||||
|         self.assertEqual(crop(75, -25, 125, 25), (1875, 625)) |  | ||||||
|         self.assertEqual(crop(75, 75, 125, 125), (1875, 625)) |  | ||||||
|         self.assertEqual(crop(-25, 75, 25, 125), (1875, 625)) |  | ||||||
| 
 | 
 | ||||||
|     def test_negative_crop(self): |     # corners | ||||||
|         # Check negative crop size (@PIL171) |     assert crop(-25, -25, 25, 25) == (1875, 625) | ||||||
|  |     assert crop(75, -25, 125, 25) == (1875, 625) | ||||||
|  |     assert crop(75, 75, 125, 125) == (1875, 625) | ||||||
|  |     assert crop(-25, 75, 25, 125) == (1875, 625) | ||||||
| 
 | 
 | ||||||
|         im = Image.new("L", (512, 512)) |  | ||||||
|         im = im.crop((400, 400, 200, 200)) |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(im.size, (0, 0)) | def test_negative_crop(): | ||||||
|         self.assertEqual(len(im.getdata()), 0) |     # Check negative crop size (@PIL171) | ||||||
|         self.assertRaises(IndexError, lambda: im.getdata()[0]) |  | ||||||
| 
 | 
 | ||||||
|     def test_crop_float(self): |     im = Image.new("L", (512, 512)) | ||||||
|         # Check cropping floats are rounded to nearest integer |     im = im.crop((400, 400, 200, 200)) | ||||||
|         # https://github.com/python-pillow/Pillow/issues/1744 |  | ||||||
| 
 | 
 | ||||||
|         # Arrange |     assert im.size == (0, 0) | ||||||
|         im = Image.new("RGB", (10, 10)) |     assert len(im.getdata()) == 0 | ||||||
|         self.assertEqual(im.size, (10, 10)) |     with pytest.raises(IndexError): | ||||||
|  |         im.getdata()[0] | ||||||
| 
 | 
 | ||||||
|         # Act |  | ||||||
|         cropped = im.crop((0.9, 1.1, 4.2, 5.8)) |  | ||||||
| 
 | 
 | ||||||
|         # Assert | def test_crop_float(): | ||||||
|         self.assertEqual(cropped.size, (3, 5)) |     # Check cropping floats are rounded to nearest integer | ||||||
|  |     # https://github.com/python-pillow/Pillow/issues/1744 | ||||||
| 
 | 
 | ||||||
|     def test_crop_crash(self): |     # Arrange | ||||||
|         # Image.crop crashes prepatch with an access violation |     im = Image.new("RGB", (10, 10)) | ||||||
|         # apparently a use after free on windows, see |     assert im.size == (10, 10) | ||||||
|         # https://github.com/python-pillow/Pillow/issues/1077 |  | ||||||
| 
 | 
 | ||||||
|         test_img = "Tests/images/bmp/g/pal8-0.bmp" |     # Act | ||||||
|         extents = (1, 1, 10, 10) |     cropped = im.crop((0.9, 1.1, 4.2, 5.8)) | ||||||
|         # works prepatch |  | ||||||
|         with Image.open(test_img) as img: |  | ||||||
|             img2 = img.crop(extents) |  | ||||||
|         img2.load() |  | ||||||
| 
 | 
 | ||||||
|         # fail prepatch |     # Assert | ||||||
|         with Image.open(test_img) as img: |     assert cropped.size == (3, 5) | ||||||
|             img = img.crop(extents) |  | ||||||
|         img.load() |  | ||||||
| 
 | 
 | ||||||
|     def test_crop_zero(self): |  | ||||||
| 
 | 
 | ||||||
|         im = Image.new("RGB", (0, 0), "white") | def test_crop_crash(): | ||||||
|  |     # Image.crop crashes prepatch with an access violation | ||||||
|  |     # apparently a use after free on Windows, see | ||||||
|  |     # https://github.com/python-pillow/Pillow/issues/1077 | ||||||
| 
 | 
 | ||||||
|         cropped = im.crop((0, 0, 0, 0)) |     test_img = "Tests/images/bmp/g/pal8-0.bmp" | ||||||
|         self.assertEqual(cropped.size, (0, 0)) |     extents = (1, 1, 10, 10) | ||||||
|  |     # works prepatch | ||||||
|  |     with Image.open(test_img) as img: | ||||||
|  |         img2 = img.crop(extents) | ||||||
|  |     img2.load() | ||||||
| 
 | 
 | ||||||
|         cropped = im.crop((10, 10, 20, 20)) |     # fail prepatch | ||||||
|         self.assertEqual(cropped.size, (10, 10)) |     with Image.open(test_img) as img: | ||||||
|         self.assertEqual(cropped.getdata()[0], (0, 0, 0)) |         img = img.crop(extents) | ||||||
|  |     img.load() | ||||||
| 
 | 
 | ||||||
|         im = Image.new("RGB", (0, 0)) |  | ||||||
| 
 | 
 | ||||||
|         cropped = im.crop((10, 10, 20, 20)) | def test_crop_zero(): | ||||||
|         self.assertEqual(cropped.size, (10, 10)) | 
 | ||||||
|         self.assertEqual(cropped.getdata()[2], (0, 0, 0)) |     im = Image.new("RGB", (0, 0), "white") | ||||||
|  | 
 | ||||||
|  |     cropped = im.crop((0, 0, 0, 0)) | ||||||
|  |     assert cropped.size == (0, 0) | ||||||
|  | 
 | ||||||
|  |     cropped = im.crop((10, 10, 20, 20)) | ||||||
|  |     assert cropped.size == (10, 10) | ||||||
|  |     assert cropped.getdata()[0] == (0, 0, 0) | ||||||
|  | 
 | ||||||
|  |     im = Image.new("RGB", (0, 0)) | ||||||
|  | 
 | ||||||
|  |     cropped = im.crop((10, 10, 20, 20)) | ||||||
|  |     assert cropped.size == (10, 10) | ||||||
|  |     assert cropped.getdata()[2] == (0, 0, 0) | ||||||
|  |  | ||||||
|  | @ -1,73 +1,77 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, fromstring, tostring | from .helper import fromstring, tostring | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageDraft(PillowTestCase): | def setup_module(): | ||||||
|     def setUp(self): |     codecs = dir(Image.core) | ||||||
|         codecs = dir(Image.core) |     if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs: | ||||||
|         if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs: |         pytest.skip("jpeg support not available") | ||||||
|             self.skipTest("jpeg support not available") |  | ||||||
| 
 | 
 | ||||||
|     def draft_roundtrip(self, in_mode, in_size, req_mode, req_size): |  | ||||||
|         im = Image.new(in_mode, in_size) |  | ||||||
|         data = tostring(im, "JPEG") |  | ||||||
|         im = fromstring(data) |  | ||||||
|         mode, box = im.draft(req_mode, req_size) |  | ||||||
|         scale, _ = im.decoderconfig |  | ||||||
|         self.assertEqual(box[:2], (0, 0)) |  | ||||||
|         self.assertTrue((im.width - scale) < box[2] <= im.width) |  | ||||||
|         self.assertTrue((im.height - scale) < box[3] <= im.height) |  | ||||||
|         return im |  | ||||||
| 
 | 
 | ||||||
|     def test_size(self): | def draft_roundtrip(in_mode, in_size, req_mode, req_size): | ||||||
|         for in_size, req_size, out_size in [ |     im = Image.new(in_mode, in_size) | ||||||
|             ((435, 361), (2048, 2048), (435, 361)),  # bigger |     data = tostring(im, "JPEG") | ||||||
|             ((435, 361), (435, 361), (435, 361)),  # same |     im = fromstring(data) | ||||||
|             ((128, 128), (64, 64), (64, 64)), |     mode, box = im.draft(req_mode, req_size) | ||||||
|             ((128, 128), (32, 32), (32, 32)), |     scale, _ = im.decoderconfig | ||||||
|             ((128, 128), (16, 16), (16, 16)), |     assert box[:2] == (0, 0) | ||||||
|             # large requested width |     assert (im.width - scale) < box[2] <= im.width | ||||||
|             ((435, 361), (218, 128), (435, 361)),  # almost 2x |     assert (im.height - scale) < box[3] <= im.height | ||||||
|             ((435, 361), (217, 128), (218, 181)),  # more than 2x |     return im | ||||||
|             ((435, 361), (109, 64), (218, 181)),  # almost 4x |  | ||||||
|             ((435, 361), (108, 64), (109, 91)),  # more than 4x |  | ||||||
|             ((435, 361), (55, 32), (109, 91)),  # almost 8x |  | ||||||
|             ((435, 361), (54, 32), (55, 46)),  # more than 8x |  | ||||||
|             ((435, 361), (27, 16), (55, 46)),  # more than 16x |  | ||||||
|             # and vice versa |  | ||||||
|             ((435, 361), (128, 181), (435, 361)),  # almost 2x |  | ||||||
|             ((435, 361), (128, 180), (218, 181)),  # more than 2x |  | ||||||
|             ((435, 361), (64, 91), (218, 181)),  # almost 4x |  | ||||||
|             ((435, 361), (64, 90), (109, 91)),  # more than 4x |  | ||||||
|             ((435, 361), (32, 46), (109, 91)),  # almost 8x |  | ||||||
|             ((435, 361), (32, 45), (55, 46)),  # more than 8x |  | ||||||
|             ((435, 361), (16, 22), (55, 46)),  # more than 16x |  | ||||||
|         ]: |  | ||||||
|             im = self.draft_roundtrip("L", in_size, None, req_size) |  | ||||||
|             im.load() |  | ||||||
|             self.assertEqual(im.size, out_size) |  | ||||||
| 
 | 
 | ||||||
|     def test_mode(self): |  | ||||||
|         for in_mode, req_mode, out_mode in [ |  | ||||||
|             ("RGB", "1", "RGB"), |  | ||||||
|             ("RGB", "L", "L"), |  | ||||||
|             ("RGB", "RGB", "RGB"), |  | ||||||
|             ("RGB", "YCbCr", "YCbCr"), |  | ||||||
|             ("L", "1", "L"), |  | ||||||
|             ("L", "L", "L"), |  | ||||||
|             ("L", "RGB", "L"), |  | ||||||
|             ("L", "YCbCr", "L"), |  | ||||||
|             ("CMYK", "1", "CMYK"), |  | ||||||
|             ("CMYK", "L", "CMYK"), |  | ||||||
|             ("CMYK", "RGB", "CMYK"), |  | ||||||
|             ("CMYK", "YCbCr", "CMYK"), |  | ||||||
|         ]: |  | ||||||
|             im = self.draft_roundtrip(in_mode, (64, 64), req_mode, None) |  | ||||||
|             im.load() |  | ||||||
|             self.assertEqual(im.mode, out_mode) |  | ||||||
| 
 | 
 | ||||||
|     def test_several_drafts(self): | def test_size(): | ||||||
|         im = self.draft_roundtrip("L", (128, 128), None, (64, 64)) |     for in_size, req_size, out_size in [ | ||||||
|         im.draft(None, (64, 64)) |         ((435, 361), (2048, 2048), (435, 361)),  # bigger | ||||||
|  |         ((435, 361), (435, 361), (435, 361)),  # same | ||||||
|  |         ((128, 128), (64, 64), (64, 64)), | ||||||
|  |         ((128, 128), (32, 32), (32, 32)), | ||||||
|  |         ((128, 128), (16, 16), (16, 16)), | ||||||
|  |         # large requested width | ||||||
|  |         ((435, 361), (218, 128), (435, 361)),  # almost 2x | ||||||
|  |         ((435, 361), (217, 128), (218, 181)),  # more than 2x | ||||||
|  |         ((435, 361), (109, 64), (218, 181)),  # almost 4x | ||||||
|  |         ((435, 361), (108, 64), (109, 91)),  # more than 4x | ||||||
|  |         ((435, 361), (55, 32), (109, 91)),  # almost 8x | ||||||
|  |         ((435, 361), (54, 32), (55, 46)),  # more than 8x | ||||||
|  |         ((435, 361), (27, 16), (55, 46)),  # more than 16x | ||||||
|  |         # and vice versa | ||||||
|  |         ((435, 361), (128, 181), (435, 361)),  # almost 2x | ||||||
|  |         ((435, 361), (128, 180), (218, 181)),  # more than 2x | ||||||
|  |         ((435, 361), (64, 91), (218, 181)),  # almost 4x | ||||||
|  |         ((435, 361), (64, 90), (109, 91)),  # more than 4x | ||||||
|  |         ((435, 361), (32, 46), (109, 91)),  # almost 8x | ||||||
|  |         ((435, 361), (32, 45), (55, 46)),  # more than 8x | ||||||
|  |         ((435, 361), (16, 22), (55, 46)),  # more than 16x | ||||||
|  |     ]: | ||||||
|  |         im = draft_roundtrip("L", in_size, None, req_size) | ||||||
|         im.load() |         im.load() | ||||||
|  |         assert im.size == out_size | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_mode(): | ||||||
|  |     for in_mode, req_mode, out_mode in [ | ||||||
|  |         ("RGB", "1", "RGB"), | ||||||
|  |         ("RGB", "L", "L"), | ||||||
|  |         ("RGB", "RGB", "RGB"), | ||||||
|  |         ("RGB", "YCbCr", "YCbCr"), | ||||||
|  |         ("L", "1", "L"), | ||||||
|  |         ("L", "L", "L"), | ||||||
|  |         ("L", "RGB", "L"), | ||||||
|  |         ("L", "YCbCr", "L"), | ||||||
|  |         ("CMYK", "1", "CMYK"), | ||||||
|  |         ("CMYK", "L", "CMYK"), | ||||||
|  |         ("CMYK", "RGB", "CMYK"), | ||||||
|  |         ("CMYK", "YCbCr", "CMYK"), | ||||||
|  |     ]: | ||||||
|  |         im = draft_roundtrip(in_mode, (64, 64), req_mode, None) | ||||||
|  |         im.load() | ||||||
|  |         assert im.mode == out_mode | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_several_drafts(): | ||||||
|  |     im = draft_roundtrip("L", (128, 128), None, (64, 64)) | ||||||
|  |     im.draft(None, (64, 64)) | ||||||
|  |     im.load() | ||||||
|  |  | ||||||
|  | @ -1,17 +1,16 @@ | ||||||
| from .helper import PillowTestCase, hopper | from .helper import hopper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageEntropy(PillowTestCase): | def test_entropy(): | ||||||
|     def test_entropy(self): |     def entropy(mode): | ||||||
|         def entropy(mode): |         return hopper(mode).entropy() | ||||||
|             return hopper(mode).entropy() |  | ||||||
| 
 | 
 | ||||||
|         self.assertAlmostEqual(entropy("1"), 0.9138803254693582) |     assert round(abs(entropy("1") - 0.9138803254693582), 7) == 0 | ||||||
|         self.assertAlmostEqual(entropy("L"), 7.063008716585465) |     assert round(abs(entropy("L") - 7.063008716585465), 7) == 0 | ||||||
|         self.assertAlmostEqual(entropy("I"), 7.063008716585465) |     assert round(abs(entropy("I") - 7.063008716585465), 7) == 0 | ||||||
|         self.assertAlmostEqual(entropy("F"), 7.063008716585465) |     assert round(abs(entropy("F") - 7.063008716585465), 7) == 0 | ||||||
|         self.assertAlmostEqual(entropy("P"), 5.0530452472519745) |     assert round(abs(entropy("P") - 5.0530452472519745), 7) == 0 | ||||||
|         self.assertAlmostEqual(entropy("RGB"), 8.821286587714319) |     assert round(abs(entropy("RGB") - 8.821286587714319), 7) == 0 | ||||||
|         self.assertAlmostEqual(entropy("RGBA"), 7.42724306524488) |     assert round(abs(entropy("RGBA") - 7.42724306524488), 7) == 0 | ||||||
|         self.assertAlmostEqual(entropy("CMYK"), 7.4272430652448795) |     assert round(abs(entropy("CMYK") - 7.4272430652448795), 7) == 0 | ||||||
|         self.assertAlmostEqual(entropy("YCbCr"), 7.698360534903628) |     assert round(abs(entropy("YCbCr") - 7.698360534903628), 7) == 0 | ||||||
|  |  | ||||||
|  | @ -1,143 +1,155 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image, ImageFilter | from PIL import Image, ImageFilter | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, hopper | from .helper import assert_image_equal, hopper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageFilter(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     def apply_filter(filter_to_apply): | ||||||
|         def filter(filter): |         for mode in ["L", "RGB", "CMYK"]: | ||||||
|             for mode in ["L", "RGB", "CMYK"]: |             im = hopper(mode) | ||||||
|                 im = hopper(mode) |             out = im.filter(filter_to_apply) | ||||||
|                 out = im.filter(filter) |             assert out.mode == im.mode | ||||||
|                 self.assertEqual(out.mode, im.mode) |             assert out.size == im.size | ||||||
|                 self.assertEqual(out.size, im.size) |  | ||||||
| 
 | 
 | ||||||
|         filter(ImageFilter.BLUR) |     apply_filter(ImageFilter.BLUR) | ||||||
|         filter(ImageFilter.CONTOUR) |     apply_filter(ImageFilter.CONTOUR) | ||||||
|         filter(ImageFilter.DETAIL) |     apply_filter(ImageFilter.DETAIL) | ||||||
|         filter(ImageFilter.EDGE_ENHANCE) |     apply_filter(ImageFilter.EDGE_ENHANCE) | ||||||
|         filter(ImageFilter.EDGE_ENHANCE_MORE) |     apply_filter(ImageFilter.EDGE_ENHANCE_MORE) | ||||||
|         filter(ImageFilter.EMBOSS) |     apply_filter(ImageFilter.EMBOSS) | ||||||
|         filter(ImageFilter.FIND_EDGES) |     apply_filter(ImageFilter.FIND_EDGES) | ||||||
|         filter(ImageFilter.SMOOTH) |     apply_filter(ImageFilter.SMOOTH) | ||||||
|         filter(ImageFilter.SMOOTH_MORE) |     apply_filter(ImageFilter.SMOOTH_MORE) | ||||||
|         filter(ImageFilter.SHARPEN) |     apply_filter(ImageFilter.SHARPEN) | ||||||
|         filter(ImageFilter.MaxFilter) |     apply_filter(ImageFilter.MaxFilter) | ||||||
|         filter(ImageFilter.MedianFilter) |     apply_filter(ImageFilter.MedianFilter) | ||||||
|         filter(ImageFilter.MinFilter) |     apply_filter(ImageFilter.MinFilter) | ||||||
|         filter(ImageFilter.ModeFilter) |     apply_filter(ImageFilter.ModeFilter) | ||||||
|         filter(ImageFilter.GaussianBlur) |     apply_filter(ImageFilter.GaussianBlur) | ||||||
|         filter(ImageFilter.GaussianBlur(5)) |     apply_filter(ImageFilter.GaussianBlur(5)) | ||||||
|         filter(ImageFilter.BoxBlur(5)) |     apply_filter(ImageFilter.BoxBlur(5)) | ||||||
|         filter(ImageFilter.UnsharpMask) |     apply_filter(ImageFilter.UnsharpMask) | ||||||
|         filter(ImageFilter.UnsharpMask(10)) |     apply_filter(ImageFilter.UnsharpMask(10)) | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(TypeError, filter, "hello") |     with pytest.raises(TypeError): | ||||||
|  |         apply_filter("hello") | ||||||
| 
 | 
 | ||||||
|     def test_crash(self): |  | ||||||
| 
 | 
 | ||||||
|         # crashes on small images | def test_crash(): | ||||||
|         im = Image.new("RGB", (1, 1)) |  | ||||||
|         im.filter(ImageFilter.SMOOTH) |  | ||||||
| 
 | 
 | ||||||
|         im = Image.new("RGB", (2, 2)) |     # crashes on small images | ||||||
|         im.filter(ImageFilter.SMOOTH) |     im = Image.new("RGB", (1, 1)) | ||||||
|  |     im.filter(ImageFilter.SMOOTH) | ||||||
| 
 | 
 | ||||||
|         im = Image.new("RGB", (3, 3)) |     im = Image.new("RGB", (2, 2)) | ||||||
|         im.filter(ImageFilter.SMOOTH) |     im.filter(ImageFilter.SMOOTH) | ||||||
| 
 | 
 | ||||||
|     def test_modefilter(self): |     im = Image.new("RGB", (3, 3)) | ||||||
|         def modefilter(mode): |     im.filter(ImageFilter.SMOOTH) | ||||||
|             im = Image.new(mode, (3, 3), None) |  | ||||||
|             im.putdata(list(range(9))) |  | ||||||
|             # image is: |  | ||||||
|             #   0 1 2 |  | ||||||
|             #   3 4 5 |  | ||||||
|             #   6 7 8 |  | ||||||
|             mod = im.filter(ImageFilter.ModeFilter).getpixel((1, 1)) |  | ||||||
|             im.putdata([0, 0, 1, 2, 5, 1, 5, 2, 0])  # mode=0 |  | ||||||
|             mod2 = im.filter(ImageFilter.ModeFilter).getpixel((1, 1)) |  | ||||||
|             return mod, mod2 |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(modefilter("1"), (4, 0)) |  | ||||||
|         self.assertEqual(modefilter("L"), (4, 0)) |  | ||||||
|         self.assertEqual(modefilter("P"), (4, 0)) |  | ||||||
|         self.assertEqual(modefilter("RGB"), ((4, 0, 0), (0, 0, 0))) |  | ||||||
| 
 | 
 | ||||||
|     def test_rankfilter(self): | def test_modefilter(): | ||||||
|         def rankfilter(mode): |     def modefilter(mode): | ||||||
|             im = Image.new(mode, (3, 3), None) |         im = Image.new(mode, (3, 3), None) | ||||||
|             im.putdata(list(range(9))) |         im.putdata(list(range(9))) | ||||||
|             # image is: |         # image is: | ||||||
|             #   0 1 2 |         #   0 1 2 | ||||||
|             #   3 4 5 |         #   3 4 5 | ||||||
|             #   6 7 8 |         #   6 7 8 | ||||||
|             minimum = im.filter(ImageFilter.MinFilter).getpixel((1, 1)) |         mod = im.filter(ImageFilter.ModeFilter).getpixel((1, 1)) | ||||||
|             med = im.filter(ImageFilter.MedianFilter).getpixel((1, 1)) |         im.putdata([0, 0, 1, 2, 5, 1, 5, 2, 0])  # mode=0 | ||||||
|             maximum = im.filter(ImageFilter.MaxFilter).getpixel((1, 1)) |         mod2 = im.filter(ImageFilter.ModeFilter).getpixel((1, 1)) | ||||||
|             return minimum, med, maximum |         return mod, mod2 | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(rankfilter("1"), (0, 4, 8)) |     assert modefilter("1") == (4, 0) | ||||||
|         self.assertEqual(rankfilter("L"), (0, 4, 8)) |     assert modefilter("L") == (4, 0) | ||||||
|         self.assertRaises(ValueError, rankfilter, "P") |     assert modefilter("P") == (4, 0) | ||||||
|         self.assertEqual(rankfilter("RGB"), ((0, 0, 0), (4, 0, 0), (8, 0, 0))) |     assert modefilter("RGB") == ((4, 0, 0), (0, 0, 0)) | ||||||
|         self.assertEqual(rankfilter("I"), (0, 4, 8)) |  | ||||||
|         self.assertEqual(rankfilter("F"), (0.0, 4.0, 8.0)) |  | ||||||
| 
 | 
 | ||||||
|     def test_rankfilter_properties(self): |  | ||||||
|         rankfilter = ImageFilter.RankFilter(1, 2) |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(rankfilter.size, 1) | def test_rankfilter(): | ||||||
|         self.assertEqual(rankfilter.rank, 2) |     def rankfilter(mode): | ||||||
|  |         im = Image.new(mode, (3, 3), None) | ||||||
|  |         im.putdata(list(range(9))) | ||||||
|  |         # image is: | ||||||
|  |         #   0 1 2 | ||||||
|  |         #   3 4 5 | ||||||
|  |         #   6 7 8 | ||||||
|  |         minimum = im.filter(ImageFilter.MinFilter).getpixel((1, 1)) | ||||||
|  |         med = im.filter(ImageFilter.MedianFilter).getpixel((1, 1)) | ||||||
|  |         maximum = im.filter(ImageFilter.MaxFilter).getpixel((1, 1)) | ||||||
|  |         return minimum, med, maximum | ||||||
| 
 | 
 | ||||||
|     def test_builtinfilter_p(self): |     assert rankfilter("1") == (0, 4, 8) | ||||||
|         builtinFilter = ImageFilter.BuiltinFilter() |     assert rankfilter("L") == (0, 4, 8) | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         rankfilter("P") | ||||||
|  |     assert rankfilter("RGB") == ((0, 0, 0), (4, 0, 0), (8, 0, 0)) | ||||||
|  |     assert rankfilter("I") == (0, 4, 8) | ||||||
|  |     assert rankfilter("F") == (0.0, 4.0, 8.0) | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(ValueError, builtinFilter.filter, hopper("P")) |  | ||||||
| 
 | 
 | ||||||
|     def test_kernel_not_enough_coefficients(self): | def test_rankfilter_properties(): | ||||||
|         self.assertRaises(ValueError, lambda: ImageFilter.Kernel((3, 3), (0, 0))) |     rankfilter = ImageFilter.RankFilter(1, 2) | ||||||
| 
 | 
 | ||||||
|     def test_consistency_3x3(self): |     assert rankfilter.size == 1 | ||||||
|         with Image.open("Tests/images/hopper.bmp") as source: |     assert rankfilter.rank == 2 | ||||||
|             with Image.open("Tests/images/hopper_emboss.bmp") as reference: | 
 | ||||||
|                 kernel = ImageFilter.Kernel(  # noqa: E127 | 
 | ||||||
|                     (3, 3), | def test_builtinfilter_p(): | ||||||
|                     # fmt: off |     builtinFilter = ImageFilter.BuiltinFilter() | ||||||
|                     (-1, -1,  0, | 
 | ||||||
|                      -1,  0,  1, |     with pytest.raises(ValueError): | ||||||
|                       0,  1,  1), |         builtinFilter.filter(hopper("P")) | ||||||
|                     # fmt: on | 
 | ||||||
|                     0.3, | 
 | ||||||
|  | def test_kernel_not_enough_coefficients(): | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         ImageFilter.Kernel((3, 3), (0, 0)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_consistency_3x3(): | ||||||
|  |     with Image.open("Tests/images/hopper.bmp") as source: | ||||||
|  |         with Image.open("Tests/images/hopper_emboss.bmp") as reference: | ||||||
|  |             kernel = ImageFilter.Kernel(  # noqa: E127 | ||||||
|  |                 (3, 3), | ||||||
|  |                 # fmt: off | ||||||
|  |                 (-1, -1,  0, | ||||||
|  |                  -1,  0,  1, | ||||||
|  |                   0,  1,  1), | ||||||
|  |                 # fmt: on | ||||||
|  |                 0.3, | ||||||
|  |             ) | ||||||
|  |             source = source.split() * 2 | ||||||
|  |             reference = reference.split() * 2 | ||||||
|  | 
 | ||||||
|  |             for mode in ["L", "LA", "RGB", "CMYK"]: | ||||||
|  |                 assert_image_equal( | ||||||
|  |                     Image.merge(mode, source[: len(mode)]).filter(kernel), | ||||||
|  |                     Image.merge(mode, reference[: len(mode)]), | ||||||
|                 ) |                 ) | ||||||
|                 source = source.split() * 2 |  | ||||||
|                 reference = reference.split() * 2 |  | ||||||
| 
 | 
 | ||||||
|                 for mode in ["L", "LA", "RGB", "CMYK"]: |  | ||||||
|                     assert_image_equal( |  | ||||||
|                         Image.merge(mode, source[: len(mode)]).filter(kernel), |  | ||||||
|                         Image.merge(mode, reference[: len(mode)]), |  | ||||||
|                     ) |  | ||||||
| 
 | 
 | ||||||
|     def test_consistency_5x5(self): | def test_consistency_5x5(): | ||||||
|         with Image.open("Tests/images/hopper.bmp") as source: |     with Image.open("Tests/images/hopper.bmp") as source: | ||||||
|             with Image.open("Tests/images/hopper_emboss_more.bmp") as reference: |         with Image.open("Tests/images/hopper_emboss_more.bmp") as reference: | ||||||
|                 kernel = ImageFilter.Kernel(  # noqa: E127 |             kernel = ImageFilter.Kernel(  # noqa: E127 | ||||||
|                     (5, 5), |                 (5, 5), | ||||||
|                     # fmt: off |                 # fmt: off | ||||||
|                     (-1, -1, -1, -1,  0, |                 (-1, -1, -1, -1,  0, | ||||||
|                      -1, -1, -1,  0,  1, |                  -1, -1, -1,  0,  1, | ||||||
|                      -1, -1,  0,  1,  1, |                  -1, -1,  0,  1,  1, | ||||||
|                      -1,  0,  1,  1,  1, |                  -1,  0,  1,  1,  1, | ||||||
|                       0,  1,  1,  1,  1), |                   0,  1,  1,  1,  1), | ||||||
|                     # fmt: on |                 # fmt: on | ||||||
|                     0.3, |                 0.3, | ||||||
|  |             ) | ||||||
|  |             source = source.split() * 2 | ||||||
|  |             reference = reference.split() * 2 | ||||||
|  | 
 | ||||||
|  |             for mode in ["L", "LA", "RGB", "CMYK"]: | ||||||
|  |                 assert_image_equal( | ||||||
|  |                     Image.merge(mode, source[: len(mode)]).filter(kernel), | ||||||
|  |                     Image.merge(mode, reference[: len(mode)]), | ||||||
|                 ) |                 ) | ||||||
|                 source = source.split() * 2 |  | ||||||
|                 reference = reference.split() * 2 |  | ||||||
| 
 |  | ||||||
|                 for mode in ["L", "LA", "RGB", "CMYK"]: |  | ||||||
|                     assert_image_equal( |  | ||||||
|                         Image.merge(mode, source[: len(mode)]).filter(kernel), |  | ||||||
|                         Image.merge(mode, reference[: len(mode)]), |  | ||||||
|                     ) |  | ||||||
|  |  | ||||||
|  | @ -1,14 +1,16 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, hopper | from .helper import assert_image_equal, hopper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageFromBytes(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     im1 = hopper() | ||||||
|         im1 = hopper() |     im2 = Image.frombytes(im1.mode, im1.size, im1.tobytes()) | ||||||
|         im2 = Image.frombytes(im1.mode, im1.size, im1.tobytes()) |  | ||||||
| 
 | 
 | ||||||
|         assert_image_equal(im1, im2) |     assert_image_equal(im1, im2) | ||||||
| 
 | 
 | ||||||
|     def test_not_implemented(self): | 
 | ||||||
|         self.assertRaises(NotImplementedError, Image.fromstring) | def test_not_implemented(): | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|  |         Image.fromstring() | ||||||
|  |  | ||||||
|  | @ -1,39 +1,48 @@ | ||||||
| from .helper import PillowTestCase, assert_image_equal, hopper | import pytest | ||||||
|  | 
 | ||||||
|  | from .helper import assert_image_equal, hopper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImagePoint(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     im = hopper() | ||||||
|         im = hopper() |  | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(ValueError, im.point, list(range(256))) |     with pytest.raises(ValueError): | ||||||
|         im.point(list(range(256)) * 3) |         im.point(list(range(256))) | ||||||
|         im.point(lambda x: x) |     im.point(list(range(256)) * 3) | ||||||
|  |     im.point(lambda x: x) | ||||||
| 
 | 
 | ||||||
|         im = im.convert("I") |     im = im.convert("I") | ||||||
|         self.assertRaises(ValueError, im.point, list(range(256))) |     with pytest.raises(ValueError): | ||||||
|         im.point(lambda x: x * 1) |         im.point(list(range(256))) | ||||||
|         im.point(lambda x: x + 1) |     im.point(lambda x: x * 1) | ||||||
|         im.point(lambda x: x * 1 + 1) |     im.point(lambda x: x + 1) | ||||||
|         self.assertRaises(TypeError, im.point, lambda x: x - 1) |     im.point(lambda x: x * 1 + 1) | ||||||
|         self.assertRaises(TypeError, im.point, lambda x: x / 1) |     with pytest.raises(TypeError): | ||||||
|  |         im.point(lambda x: x - 1) | ||||||
|  |     with pytest.raises(TypeError): | ||||||
|  |         im.point(lambda x: x / 1) | ||||||
| 
 | 
 | ||||||
|     def test_16bit_lut(self): |  | ||||||
|         """ Tests for 16 bit -> 8 bit lut for converting I->L images |  | ||||||
|             see https://github.com/python-pillow/Pillow/issues/440 |  | ||||||
|             """ |  | ||||||
|         im = hopper("I") |  | ||||||
|         im.point(list(range(256)) * 256, "L") |  | ||||||
| 
 | 
 | ||||||
|     def test_f_lut(self): | def test_16bit_lut(): | ||||||
|         """ Tests for floating point lut of 8bit gray image """ |     """ Tests for 16 bit -> 8 bit lut for converting I->L images | ||||||
|         im = hopper("L") |         see https://github.com/python-pillow/Pillow/issues/440 | ||||||
|         lut = [0.5 * float(x) for x in range(256)] |         """ | ||||||
|  |     im = hopper("I") | ||||||
|  |     im.point(list(range(256)) * 256, "L") | ||||||
| 
 | 
 | ||||||
|         out = im.point(lut, "F") |  | ||||||
| 
 | 
 | ||||||
|         int_lut = [x // 2 for x in range(256)] | def test_f_lut(): | ||||||
|         assert_image_equal(out.convert("L"), im.point(int_lut, "L")) |     """ Tests for floating point lut of 8bit gray image """ | ||||||
|  |     im = hopper("L") | ||||||
|  |     lut = [0.5 * float(x) for x in range(256)] | ||||||
| 
 | 
 | ||||||
|     def test_f_mode(self): |     out = im.point(lut, "F") | ||||||
|         im = hopper("F") | 
 | ||||||
|         self.assertRaises(ValueError, im.point, None) |     int_lut = [x // 2 for x in range(256)] | ||||||
|  |     assert_image_equal(out.convert("L"), im.point(int_lut, "L")) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_f_mode(): | ||||||
|  |     im = hopper("F") | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         im.point(None) | ||||||
|  |  | ||||||
|  | @ -3,83 +3,87 @@ from array import array | ||||||
| 
 | 
 | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, hopper | from .helper import assert_image_equal, hopper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImagePutData(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     im1 = hopper() | ||||||
| 
 | 
 | ||||||
|         im1 = hopper() |     data = list(im1.getdata()) | ||||||
| 
 | 
 | ||||||
|         data = list(im1.getdata()) |     im2 = Image.new(im1.mode, im1.size, 0) | ||||||
|  |     im2.putdata(data) | ||||||
| 
 | 
 | ||||||
|         im2 = Image.new(im1.mode, im1.size, 0) |     assert_image_equal(im1, im2) | ||||||
|         im2.putdata(data) |  | ||||||
| 
 | 
 | ||||||
|         assert_image_equal(im1, im2) |     # readonly | ||||||
|  |     im2 = Image.new(im1.mode, im2.size, 0) | ||||||
|  |     im2.readonly = 1 | ||||||
|  |     im2.putdata(data) | ||||||
| 
 | 
 | ||||||
|         # readonly |     assert not im2.readonly | ||||||
|         im2 = Image.new(im1.mode, im2.size, 0) |     assert_image_equal(im1, im2) | ||||||
|         im2.readonly = 1 |  | ||||||
|         im2.putdata(data) |  | ||||||
| 
 | 
 | ||||||
|         self.assertFalse(im2.readonly) |  | ||||||
|         assert_image_equal(im1, im2) |  | ||||||
| 
 | 
 | ||||||
|     def test_long_integers(self): | def test_long_integers(): | ||||||
|         # see bug-200802-systemerror |     # see bug-200802-systemerror | ||||||
|         def put(value): |     def put(value): | ||||||
|             im = Image.new("RGBA", (1, 1)) |         im = Image.new("RGBA", (1, 1)) | ||||||
|             im.putdata([value]) |         im.putdata([value]) | ||||||
|             return im.getpixel((0, 0)) |         return im.getpixel((0, 0)) | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(put(0xFFFFFFFF), (255, 255, 255, 255)) |     assert put(0xFFFFFFFF) == (255, 255, 255, 255) | ||||||
|         self.assertEqual(put(0xFFFFFFFF), (255, 255, 255, 255)) |     assert put(0xFFFFFFFF) == (255, 255, 255, 255) | ||||||
|         self.assertEqual(put(-1), (255, 255, 255, 255)) |     assert put(-1) == (255, 255, 255, 255) | ||||||
|         self.assertEqual(put(-1), (255, 255, 255, 255)) |     assert put(-1) == (255, 255, 255, 255) | ||||||
|         if sys.maxsize > 2 ** 32: |     if sys.maxsize > 2 ** 32: | ||||||
|             self.assertEqual(put(sys.maxsize), (255, 255, 255, 255)) |         assert put(sys.maxsize) == (255, 255, 255, 255) | ||||||
|         else: |     else: | ||||||
|             self.assertEqual(put(sys.maxsize), (255, 255, 255, 127)) |         assert put(sys.maxsize) == (255, 255, 255, 127) | ||||||
| 
 | 
 | ||||||
|     def test_pypy_performance(self): |  | ||||||
|         im = Image.new("L", (256, 256)) |  | ||||||
|         im.putdata(list(range(256)) * 256) |  | ||||||
| 
 | 
 | ||||||
|     def test_mode_i(self): | def test_pypy_performance(): | ||||||
|         src = hopper("L") |     im = Image.new("L", (256, 256)) | ||||||
|         data = list(src.getdata()) |     im.putdata(list(range(256)) * 256) | ||||||
|         im = Image.new("I", src.size, 0) |  | ||||||
|         im.putdata(data, 2, 256) |  | ||||||
| 
 | 
 | ||||||
|         target = [2 * elt + 256 for elt in data] |  | ||||||
|         self.assertEqual(list(im.getdata()), target) |  | ||||||
| 
 | 
 | ||||||
|     def test_mode_F(self): | def test_mode_i(): | ||||||
|         src = hopper("L") |     src = hopper("L") | ||||||
|         data = list(src.getdata()) |     data = list(src.getdata()) | ||||||
|         im = Image.new("F", src.size, 0) |     im = Image.new("I", src.size, 0) | ||||||
|         im.putdata(data, 2.0, 256.0) |     im.putdata(data, 2, 256) | ||||||
| 
 | 
 | ||||||
|         target = [2.0 * float(elt) + 256.0 for elt in data] |     target = [2 * elt + 256 for elt in data] | ||||||
|         self.assertEqual(list(im.getdata()), target) |     assert list(im.getdata()) == target | ||||||
| 
 | 
 | ||||||
|     def test_array_B(self): |  | ||||||
|         # shouldn't segfault |  | ||||||
|         # see https://github.com/python-pillow/Pillow/issues/1008 |  | ||||||
| 
 | 
 | ||||||
|         arr = array("B", [0]) * 15000 | def test_mode_F(): | ||||||
|         im = Image.new("L", (150, 100)) |     src = hopper("L") | ||||||
|         im.putdata(arr) |     data = list(src.getdata()) | ||||||
|  |     im = Image.new("F", src.size, 0) | ||||||
|  |     im.putdata(data, 2.0, 256.0) | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(len(im.getdata()), len(arr)) |     target = [2.0 * float(elt) + 256.0 for elt in data] | ||||||
|  |     assert list(im.getdata()) == target | ||||||
| 
 | 
 | ||||||
|     def test_array_F(self): |  | ||||||
|         # shouldn't segfault |  | ||||||
|         # see https://github.com/python-pillow/Pillow/issues/1008 |  | ||||||
| 
 | 
 | ||||||
|         im = Image.new("F", (150, 100)) | def test_array_B(): | ||||||
|         arr = array("f", [0.0]) * 15000 |     # shouldn't segfault | ||||||
|         im.putdata(arr) |     # see https://github.com/python-pillow/Pillow/issues/1008 | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(len(im.getdata()), len(arr)) |     arr = array("B", [0]) * 15000 | ||||||
|  |     im = Image.new("L", (150, 100)) | ||||||
|  |     im.putdata(arr) | ||||||
|  | 
 | ||||||
|  |     assert len(im.getdata()) == len(arr) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_array_F(): | ||||||
|  |     # shouldn't segfault | ||||||
|  |     # see https://github.com/python-pillow/Pillow/issues/1008 | ||||||
|  | 
 | ||||||
|  |     im = Image.new("F", (150, 100)) | ||||||
|  |     arr = array("f", [0.0]) * 15000 | ||||||
|  |     im.putdata(arr) | ||||||
|  | 
 | ||||||
|  |     assert len(im.getdata()) == len(arr) | ||||||
|  |  | ||||||
|  | @ -1,67 +1,74 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image, assert_image_similar, hopper | from .helper import assert_image, assert_image_similar, hopper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageQuantize(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     image = hopper() | ||||||
|         image = hopper() |     converted = image.quantize() | ||||||
|         converted = image.quantize() |     assert_image(converted, "P", converted.size) | ||||||
|         assert_image(converted, "P", converted.size) |     assert_image_similar(converted.convert("RGB"), image, 10) | ||||||
|         assert_image_similar(converted.convert("RGB"), image, 10) |  | ||||||
| 
 | 
 | ||||||
|         image = hopper() |     image = hopper() | ||||||
|         converted = image.quantize(palette=hopper("P")) |     converted = image.quantize(palette=hopper("P")) | ||||||
|         assert_image(converted, "P", converted.size) |     assert_image(converted, "P", converted.size) | ||||||
|         assert_image_similar(converted.convert("RGB"), image, 60) |     assert_image_similar(converted.convert("RGB"), image, 60) | ||||||
| 
 | 
 | ||||||
|     def test_libimagequant_quantize(self): |  | ||||||
|         image = hopper() |  | ||||||
|         try: |  | ||||||
|             converted = image.quantize(100, Image.LIBIMAGEQUANT) |  | ||||||
|         except ValueError as ex: |  | ||||||
|             if "dependency" in str(ex).lower(): |  | ||||||
|                 self.skipTest("libimagequant support not available") |  | ||||||
|             else: |  | ||||||
|                 raise |  | ||||||
|         assert_image(converted, "P", converted.size) |  | ||||||
|         assert_image_similar(converted.convert("RGB"), image, 15) |  | ||||||
|         self.assertEqual(len(converted.getcolors()), 100) |  | ||||||
| 
 | 
 | ||||||
|     def test_octree_quantize(self): | def test_libimagequant_quantize(): | ||||||
|         image = hopper() |     image = hopper() | ||||||
|         converted = image.quantize(100, Image.FASTOCTREE) |     try: | ||||||
|         assert_image(converted, "P", converted.size) |         converted = image.quantize(100, Image.LIBIMAGEQUANT) | ||||||
|         assert_image_similar(converted.convert("RGB"), image, 20) |     except ValueError as ex: | ||||||
|         self.assertEqual(len(converted.getcolors()), 100) |         if "dependency" in str(ex).lower(): | ||||||
|  |             pytest.skip("libimagequant support not available") | ||||||
|  |         else: | ||||||
|  |             raise | ||||||
|  |     assert_image(converted, "P", converted.size) | ||||||
|  |     assert_image_similar(converted.convert("RGB"), image, 15) | ||||||
|  |     assert len(converted.getcolors()) == 100 | ||||||
| 
 | 
 | ||||||
|     def test_rgba_quantize(self): |  | ||||||
|         image = hopper("RGBA") |  | ||||||
|         self.assertRaises(ValueError, image.quantize, method=0) |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(image.quantize().convert().mode, "RGBA") | def test_octree_quantize(): | ||||||
|  |     image = hopper() | ||||||
|  |     converted = image.quantize(100, Image.FASTOCTREE) | ||||||
|  |     assert_image(converted, "P", converted.size) | ||||||
|  |     assert_image_similar(converted.convert("RGB"), image, 20) | ||||||
|  |     assert len(converted.getcolors()) == 100 | ||||||
| 
 | 
 | ||||||
|     def test_quantize(self): |  | ||||||
|         with Image.open("Tests/images/caption_6_33_22.png") as image: |  | ||||||
|             image = image.convert("RGB") |  | ||||||
|         converted = image.quantize() |  | ||||||
|         assert_image(converted, "P", converted.size) |  | ||||||
|         assert_image_similar(converted.convert("RGB"), image, 1) |  | ||||||
| 
 | 
 | ||||||
|     def test_quantize_no_dither(self): | def test_rgba_quantize(): | ||||||
|         image = hopper() |     image = hopper("RGBA") | ||||||
|         with Image.open("Tests/images/caption_6_33_22.png") as palette: |     with pytest.raises(ValueError): | ||||||
|             palette = palette.convert("P") |         image.quantize(method=0) | ||||||
| 
 | 
 | ||||||
|         converted = image.quantize(dither=0, palette=palette) |     assert image.quantize().convert().mode == "RGBA" | ||||||
|         assert_image(converted, "P", converted.size) |  | ||||||
| 
 | 
 | ||||||
|     def test_quantize_dither_diff(self): |  | ||||||
|         image = hopper() |  | ||||||
|         with Image.open("Tests/images/caption_6_33_22.png") as palette: |  | ||||||
|             palette = palette.convert("P") |  | ||||||
| 
 | 
 | ||||||
|         dither = image.quantize(dither=1, palette=palette) | def test_quantize(): | ||||||
|         nodither = image.quantize(dither=0, palette=palette) |     with Image.open("Tests/images/caption_6_33_22.png") as image: | ||||||
|  |         image = image.convert("RGB") | ||||||
|  |     converted = image.quantize() | ||||||
|  |     assert_image(converted, "P", converted.size) | ||||||
|  |     assert_image_similar(converted.convert("RGB"), image, 1) | ||||||
| 
 | 
 | ||||||
|         self.assertNotEqual(dither.tobytes(), nodither.tobytes()) | 
 | ||||||
|  | def test_quantize_no_dither(): | ||||||
|  |     image = hopper() | ||||||
|  |     with Image.open("Tests/images/caption_6_33_22.png") as palette: | ||||||
|  |         palette = palette.convert("P") | ||||||
|  | 
 | ||||||
|  |     converted = image.quantize(dither=0, palette=palette) | ||||||
|  |     assert_image(converted, "P", converted.size) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_quantize_dither_diff(): | ||||||
|  |     image = hopper() | ||||||
|  |     with Image.open("Tests/images/caption_6_33_22.png") as palette: | ||||||
|  |         palette = palette.convert("P") | ||||||
|  | 
 | ||||||
|  |     dither = image.quantize(dither=1, palette=palette) | ||||||
|  |     nodither = image.quantize(dither=0, palette=palette) | ||||||
|  | 
 | ||||||
|  |     assert dither.tobytes() != nodither.tobytes() | ||||||
|  |  | ||||||
|  | @ -1,127 +1,140 @@ | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper | from .helper import assert_image_equal, assert_image_similar, hopper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageRotate(PillowTestCase): | def rotate(im, mode, angle, center=None, translate=None): | ||||||
|     def rotate(self, im, mode, angle, center=None, translate=None): |     out = im.rotate(angle, center=center, translate=translate) | ||||||
|         out = im.rotate(angle, center=center, translate=translate) |     assert out.mode == mode | ||||||
|         self.assertEqual(out.mode, mode) |     assert out.size == im.size  # default rotate clips output | ||||||
|         self.assertEqual(out.size, im.size)  # default rotate clips output |     out = im.rotate(angle, center=center, translate=translate, expand=1) | ||||||
|         out = im.rotate(angle, center=center, translate=translate, expand=1) |     assert out.mode == mode | ||||||
|         self.assertEqual(out.mode, mode) |     if angle % 180 == 0: | ||||||
|         if angle % 180 == 0: |         assert out.size == im.size | ||||||
|             self.assertEqual(out.size, im.size) |     elif im.size == (0, 0): | ||||||
|         elif im.size == (0, 0): |         assert out.size == im.size | ||||||
|             self.assertEqual(out.size, im.size) |     else: | ||||||
|         else: |         assert out.size != im.size | ||||||
|             self.assertNotEqual(out.size, im.size) |  | ||||||
| 
 | 
 | ||||||
|     def test_mode(self): |  | ||||||
|         for mode in ("1", "P", "L", "RGB", "I", "F"): |  | ||||||
|             im = hopper(mode) |  | ||||||
|             self.rotate(im, mode, 45) |  | ||||||
| 
 | 
 | ||||||
|     def test_angle(self): | def test_mode(): | ||||||
|         for angle in (0, 90, 180, 270): |     for mode in ("1", "P", "L", "RGB", "I", "F"): | ||||||
|             with Image.open("Tests/images/test-card.png") as im: |         im = hopper(mode) | ||||||
|                 self.rotate(im, im.mode, angle) |         rotate(im, mode, 45) | ||||||
| 
 | 
 | ||||||
|     def test_zero(self): |  | ||||||
|         for angle in (0, 45, 90, 180, 270): |  | ||||||
|             im = Image.new("RGB", (0, 0)) |  | ||||||
|             self.rotate(im, im.mode, angle) |  | ||||||
| 
 | 
 | ||||||
|     def test_resample(self): | def test_angle(): | ||||||
|         # Target image creation, inspected by eye. |     for angle in (0, 90, 180, 270): | ||||||
|         # >>> im = Image.open('Tests/images/hopper.ppm') |         with Image.open("Tests/images/test-card.png") as im: | ||||||
|         # >>> im = im.rotate(45, resample=Image.BICUBIC, expand=True) |             rotate(im, im.mode, angle) | ||||||
|         # >>> im.save('Tests/images/hopper_45.png') |  | ||||||
| 
 | 
 | ||||||
|         with Image.open("Tests/images/hopper_45.png") as target: |  | ||||||
|             for (resample, epsilon) in ( |  | ||||||
|                 (Image.NEAREST, 10), |  | ||||||
|                 (Image.BILINEAR, 5), |  | ||||||
|                 (Image.BICUBIC, 0), |  | ||||||
|             ): |  | ||||||
|                 im = hopper() |  | ||||||
|                 im = im.rotate(45, resample=resample, expand=True) |  | ||||||
|                 assert_image_similar(im, target, epsilon) |  | ||||||
| 
 | 
 | ||||||
|     def test_center_0(self): | def test_zero(): | ||||||
|         im = hopper() |     for angle in (0, 45, 90, 180, 270): | ||||||
|         im = im.rotate(45, center=(0, 0), resample=Image.BICUBIC) |         im = Image.new("RGB", (0, 0)) | ||||||
|  |         rotate(im, im.mode, angle) | ||||||
| 
 | 
 | ||||||
|         with Image.open("Tests/images/hopper_45.png") as target: |  | ||||||
|             target_origin = target.size[1] / 2 |  | ||||||
|             target = target.crop((0, target_origin, 128, target_origin + 128)) |  | ||||||
| 
 | 
 | ||||||
|         assert_image_similar(im, target, 15) | def test_resample(): | ||||||
|  |     # Target image creation, inspected by eye. | ||||||
|  |     # >>> im = Image.open('Tests/images/hopper.ppm') | ||||||
|  |     # >>> im = im.rotate(45, resample=Image.BICUBIC, expand=True) | ||||||
|  |     # >>> im.save('Tests/images/hopper_45.png') | ||||||
| 
 | 
 | ||||||
|     def test_center_14(self): |     with Image.open("Tests/images/hopper_45.png") as target: | ||||||
|         im = hopper() |         for (resample, epsilon) in ( | ||||||
|         im = im.rotate(45, center=(14, 14), resample=Image.BICUBIC) |             (Image.NEAREST, 10), | ||||||
|  |             (Image.BILINEAR, 5), | ||||||
|  |             (Image.BICUBIC, 0), | ||||||
|  |         ): | ||||||
|  |             im = hopper() | ||||||
|  |             im = im.rotate(45, resample=resample, expand=True) | ||||||
|  |             assert_image_similar(im, target, epsilon) | ||||||
| 
 | 
 | ||||||
|         with Image.open("Tests/images/hopper_45.png") as target: |  | ||||||
|             target_origin = target.size[1] / 2 - 14 |  | ||||||
|             target = target.crop((6, target_origin, 128 + 6, target_origin + 128)) |  | ||||||
| 
 | 
 | ||||||
|             assert_image_similar(im, target, 10) | def test_center_0(): | ||||||
|  |     im = hopper() | ||||||
|  |     im = im.rotate(45, center=(0, 0), resample=Image.BICUBIC) | ||||||
| 
 | 
 | ||||||
|     def test_translate(self): |     with Image.open("Tests/images/hopper_45.png") as target: | ||||||
|         im = hopper() |         target_origin = target.size[1] / 2 | ||||||
|         with Image.open("Tests/images/hopper_45.png") as target: |         target = target.crop((0, target_origin, 128, target_origin + 128)) | ||||||
|             target_origin = (target.size[1] / 2 - 64) - 5 |  | ||||||
|             target = target.crop( |  | ||||||
|                 (target_origin, target_origin, target_origin + 128, target_origin + 128) |  | ||||||
|             ) |  | ||||||
| 
 | 
 | ||||||
|         im = im.rotate(45, translate=(5, 5), resample=Image.BICUBIC) |     assert_image_similar(im, target, 15) | ||||||
| 
 | 
 | ||||||
|         assert_image_similar(im, target, 1) |  | ||||||
| 
 | 
 | ||||||
|     def test_fastpath_center(self): | def test_center_14(): | ||||||
|         # if the center is -1,-1 and we rotate by 90<=x<=270 the |     im = hopper() | ||||||
|         # resulting image should be black |     im = im.rotate(45, center=(14, 14), resample=Image.BICUBIC) | ||||||
|         for angle in (90, 180, 270): |  | ||||||
|             im = hopper().rotate(angle, center=(-1, -1)) |  | ||||||
|             assert_image_equal(im, Image.new("RGB", im.size, "black")) |  | ||||||
| 
 | 
 | ||||||
|     def test_fastpath_translate(self): |     with Image.open("Tests/images/hopper_45.png") as target: | ||||||
|         # if we post-translate by -128 |         target_origin = target.size[1] / 2 - 14 | ||||||
|         # resulting image should be black |         target = target.crop((6, target_origin, 128 + 6, target_origin + 128)) | ||||||
|         for angle in (0, 90, 180, 270): |  | ||||||
|             im = hopper().rotate(angle, translate=(-128, -128)) |  | ||||||
|             assert_image_equal(im, Image.new("RGB", im.size, "black")) |  | ||||||
| 
 | 
 | ||||||
|     def test_center(self): |         assert_image_similar(im, target, 10) | ||||||
|         im = hopper() |  | ||||||
|         self.rotate(im, im.mode, 45, center=(0, 0)) |  | ||||||
|         self.rotate(im, im.mode, 45, translate=(im.size[0] / 2, 0)) |  | ||||||
|         self.rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0] / 2, 0)) |  | ||||||
| 
 | 
 | ||||||
|     def test_rotate_no_fill(self): |  | ||||||
|         im = Image.new("RGB", (100, 100), "green") |  | ||||||
|         im = im.rotate(45) |  | ||||||
|         with Image.open("Tests/images/rotate_45_no_fill.png") as target: |  | ||||||
|             assert_image_equal(im, target) |  | ||||||
| 
 | 
 | ||||||
|     def test_rotate_with_fill(self): | def test_translate(): | ||||||
|         im = Image.new("RGB", (100, 100), "green") |     im = hopper() | ||||||
|         im = im.rotate(45, fillcolor="white") |     with Image.open("Tests/images/hopper_45.png") as target: | ||||||
|         with Image.open("Tests/images/rotate_45_with_fill.png") as target: |         target_origin = (target.size[1] / 2 - 64) - 5 | ||||||
|             assert_image_equal(im, target) |         target = target.crop( | ||||||
|  |             (target_origin, target_origin, target_origin + 128, target_origin + 128) | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
|     def test_alpha_rotate_no_fill(self): |     im = im.rotate(45, translate=(5, 5), resample=Image.BICUBIC) | ||||||
|         # Alpha images are handled differently internally |  | ||||||
|         im = Image.new("RGBA", (10, 10), "green") |  | ||||||
|         im = im.rotate(45, expand=1) |  | ||||||
|         corner = im.getpixel((0, 0)) |  | ||||||
|         self.assertEqual(corner, (0, 0, 0, 0)) |  | ||||||
| 
 | 
 | ||||||
|     def test_alpha_rotate_with_fill(self): |     assert_image_similar(im, target, 1) | ||||||
|         # Alpha images are handled differently internally | 
 | ||||||
|         im = Image.new("RGBA", (10, 10), "green") | 
 | ||||||
|         im = im.rotate(45, expand=1, fillcolor=(255, 0, 0, 255)) | def test_fastpath_center(): | ||||||
|         corner = im.getpixel((0, 0)) |     # if the center is -1,-1 and we rotate by 90<=x<=270 the | ||||||
|         self.assertEqual(corner, (255, 0, 0, 255)) |     # resulting image should be black | ||||||
|  |     for angle in (90, 180, 270): | ||||||
|  |         im = hopper().rotate(angle, center=(-1, -1)) | ||||||
|  |         assert_image_equal(im, Image.new("RGB", im.size, "black")) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_fastpath_translate(): | ||||||
|  |     # if we post-translate by -128 | ||||||
|  |     # resulting image should be black | ||||||
|  |     for angle in (0, 90, 180, 270): | ||||||
|  |         im = hopper().rotate(angle, translate=(-128, -128)) | ||||||
|  |         assert_image_equal(im, Image.new("RGB", im.size, "black")) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_center(): | ||||||
|  |     im = hopper() | ||||||
|  |     rotate(im, im.mode, 45, center=(0, 0)) | ||||||
|  |     rotate(im, im.mode, 45, translate=(im.size[0] / 2, 0)) | ||||||
|  |     rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0] / 2, 0)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_rotate_no_fill(): | ||||||
|  |     im = Image.new("RGB", (100, 100), "green") | ||||||
|  |     im = im.rotate(45) | ||||||
|  |     with Image.open("Tests/images/rotate_45_no_fill.png") as target: | ||||||
|  |         assert_image_equal(im, target) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_rotate_with_fill(): | ||||||
|  |     im = Image.new("RGB", (100, 100), "green") | ||||||
|  |     im = im.rotate(45, fillcolor="white") | ||||||
|  |     with Image.open("Tests/images/rotate_45_with_fill.png") as target: | ||||||
|  |         assert_image_equal(im, target) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_alpha_rotate_no_fill(): | ||||||
|  |     # Alpha images are handled differently internally | ||||||
|  |     im = Image.new("RGBA", (10, 10), "green") | ||||||
|  |     im = im.rotate(45, expand=1) | ||||||
|  |     corner = im.getpixel((0, 0)) | ||||||
|  |     assert corner == (0, 0, 0, 0) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_alpha_rotate_with_fill(): | ||||||
|  |     # Alpha images are handled differently internally | ||||||
|  |     im = Image.new("RGBA", (10, 10), "green") | ||||||
|  |     im = im.rotate(45, expand=1, fillcolor=(255, 0, 0, 255)) | ||||||
|  |     corner = im.getpixel((0, 0)) | ||||||
|  |     assert corner == (255, 0, 0, 255) | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import ( | from .helper import ( | ||||||
|     PillowTestCase, |  | ||||||
|     assert_image_equal, |     assert_image_equal, | ||||||
|     assert_image_similar, |     assert_image_similar, | ||||||
|     fromstring, |     fromstring, | ||||||
|  | @ -10,98 +10,103 @@ from .helper import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageThumbnail(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     im = hopper() | ||||||
|         im = hopper() |     assert im.thumbnail((100, 100)) is None | ||||||
|         self.assertIsNone(im.thumbnail((100, 100))) |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(im.size, (100, 100)) |     assert im.size == (100, 100) | ||||||
| 
 | 
 | ||||||
|     def test_aspect(self): |  | ||||||
|         im = Image.new("L", (128, 128)) |  | ||||||
|         im.thumbnail((100, 100)) |  | ||||||
|         self.assertEqual(im.size, (100, 100)) |  | ||||||
| 
 | 
 | ||||||
|         im = Image.new("L", (128, 256)) | def test_aspect(): | ||||||
|         im.thumbnail((100, 100)) |     im = Image.new("L", (128, 128)) | ||||||
|         self.assertEqual(im.size, (50, 100)) |     im.thumbnail((100, 100)) | ||||||
|  |     assert im.size == (100, 100) | ||||||
| 
 | 
 | ||||||
|         im = Image.new("L", (128, 256)) |     im = Image.new("L", (128, 256)) | ||||||
|         im.thumbnail((50, 100)) |     im.thumbnail((100, 100)) | ||||||
|         self.assertEqual(im.size, (50, 100)) |     assert im.size == (50, 100) | ||||||
| 
 | 
 | ||||||
|         im = Image.new("L", (256, 128)) |     im = Image.new("L", (128, 256)) | ||||||
|         im.thumbnail((100, 100)) |     im.thumbnail((50, 100)) | ||||||
|         self.assertEqual(im.size, (100, 50)) |     assert im.size == (50, 100) | ||||||
| 
 | 
 | ||||||
|         im = Image.new("L", (256, 128)) |     im = Image.new("L", (256, 128)) | ||||||
|         im.thumbnail((100, 50)) |     im.thumbnail((100, 100)) | ||||||
|         self.assertEqual(im.size, (100, 50)) |     assert im.size == (100, 50) | ||||||
| 
 | 
 | ||||||
|         im = Image.new("L", (128, 128)) |     im = Image.new("L", (256, 128)) | ||||||
|         im.thumbnail((100, 100)) |     im.thumbnail((100, 50)) | ||||||
|         self.assertEqual(im.size, (100, 100)) |     assert im.size == (100, 50) | ||||||
| 
 | 
 | ||||||
|         im = Image.new("L", (256, 162))  # ratio is 1.5802469136 |     im = Image.new("L", (128, 128)) | ||||||
|         im.thumbnail((33, 33)) |     im.thumbnail((100, 100)) | ||||||
|         self.assertEqual(im.size, (33, 21))  # ratio is 1.5714285714 |     assert im.size == (100, 100) | ||||||
| 
 | 
 | ||||||
|         im = Image.new("L", (162, 256))  # ratio is 0.6328125 |     im = Image.new("L", (256, 162))  # ratio is 1.5802469136 | ||||||
|         im.thumbnail((33, 33)) |     im.thumbnail((33, 33)) | ||||||
|         self.assertEqual(im.size, (21, 33))  # ratio is 0.6363636364 |     assert im.size == (33, 21)  # ratio is 1.5714285714 | ||||||
| 
 | 
 | ||||||
|     def test_float(self): |     im = Image.new("L", (162, 256))  # ratio is 0.6328125 | ||||||
|         im = Image.new("L", (128, 128)) |     im.thumbnail((33, 33)) | ||||||
|         im.thumbnail((99.9, 99.9)) |     assert im.size == (21, 33)  # ratio is 0.6363636364 | ||||||
|         self.assertEqual(im.size, (100, 100)) |  | ||||||
| 
 | 
 | ||||||
|     def test_no_resize(self): |  | ||||||
|         # Check that draft() can resize the image to the destination size |  | ||||||
|         with Image.open("Tests/images/hopper.jpg") as im: |  | ||||||
|             im.draft(None, (64, 64)) |  | ||||||
|             self.assertEqual(im.size, (64, 64)) |  | ||||||
| 
 | 
 | ||||||
|         # Test thumbnail(), where only draft() is necessary to resize the image | def test_float(): | ||||||
|         with Image.open("Tests/images/hopper.jpg") as im: |     im = Image.new("L", (128, 128)) | ||||||
|             im.thumbnail((64, 64)) |     im.thumbnail((99.9, 99.9)) | ||||||
|             self.assertEqual(im.size, (64, 64)) |     assert im.size == (100, 100) | ||||||
| 
 | 
 | ||||||
|     def test_DCT_scaling_edges(self): |  | ||||||
|         # Make an image with red borders and size (N * 8) + 1 to cross DCT grid |  | ||||||
|         im = Image.new("RGB", (257, 257), "red") |  | ||||||
|         im.paste(Image.new("RGB", (235, 235)), (11, 11)) |  | ||||||
| 
 | 
 | ||||||
|         thumb = fromstring(tostring(im, "JPEG", quality=99, subsampling=0)) | def test_no_resize(): | ||||||
|         # small reducing_gap to amplify the effect |     # Check that draft() can resize the image to the destination size | ||||||
|         thumb.thumbnail((32, 32), Image.BICUBIC, reducing_gap=1.0) |     with Image.open("Tests/images/hopper.jpg") as im: | ||||||
|  |         im.draft(None, (64, 64)) | ||||||
|  |         assert im.size == (64, 64) | ||||||
| 
 | 
 | ||||||
|         ref = im.resize((32, 32), Image.BICUBIC) |     # Test thumbnail(), where only draft() is necessary to resize the image | ||||||
|         # This is still JPEG, some error is present. Without the fix it is 11.5 |     with Image.open("Tests/images/hopper.jpg") as im: | ||||||
|         assert_image_similar(thumb, ref, 1.5) |         im.thumbnail((64, 64)) | ||||||
|  |         assert im.size == (64, 64) | ||||||
| 
 | 
 | ||||||
|     def test_reducing_gap_values(self): |  | ||||||
|         im = hopper() |  | ||||||
|         im.thumbnail((18, 18), Image.BICUBIC) |  | ||||||
| 
 | 
 | ||||||
|         ref = hopper() | def test_DCT_scaling_edges(): | ||||||
|         ref.thumbnail((18, 18), Image.BICUBIC, reducing_gap=2.0) |     # Make an image with red borders and size (N * 8) + 1 to cross DCT grid | ||||||
|         # reducing_gap=2.0 should be the default |     im = Image.new("RGB", (257, 257), "red") | ||||||
|  |     im.paste(Image.new("RGB", (235, 235)), (11, 11)) | ||||||
|  | 
 | ||||||
|  |     thumb = fromstring(tostring(im, "JPEG", quality=99, subsampling=0)) | ||||||
|  |     # small reducing_gap to amplify the effect | ||||||
|  |     thumb.thumbnail((32, 32), Image.BICUBIC, reducing_gap=1.0) | ||||||
|  | 
 | ||||||
|  |     ref = im.resize((32, 32), Image.BICUBIC) | ||||||
|  |     # This is still JPEG, some error is present. Without the fix it is 11.5 | ||||||
|  |     assert_image_similar(thumb, ref, 1.5) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_reducing_gap_values(): | ||||||
|  |     im = hopper() | ||||||
|  |     im.thumbnail((18, 18), Image.BICUBIC) | ||||||
|  | 
 | ||||||
|  |     ref = hopper() | ||||||
|  |     ref.thumbnail((18, 18), Image.BICUBIC, reducing_gap=2.0) | ||||||
|  |     # reducing_gap=2.0 should be the default | ||||||
|  |     assert_image_equal(ref, im) | ||||||
|  | 
 | ||||||
|  |     ref = hopper() | ||||||
|  |     ref.thumbnail((18, 18), Image.BICUBIC, reducing_gap=None) | ||||||
|  |     with pytest.raises(AssertionError): | ||||||
|         assert_image_equal(ref, im) |         assert_image_equal(ref, im) | ||||||
| 
 | 
 | ||||||
|         ref = hopper() |     assert_image_similar(ref, im, 3.5) | ||||||
|         ref.thumbnail((18, 18), Image.BICUBIC, reducing_gap=None) | 
 | ||||||
|         with self.assertRaises(AssertionError): | 
 | ||||||
|  | def test_reducing_gap_for_DCT_scaling(): | ||||||
|  |     with Image.open("Tests/images/hopper.jpg") as ref: | ||||||
|  |         # thumbnail should call draft with reducing_gap scale | ||||||
|  |         ref.draft(None, (18 * 3, 18 * 3)) | ||||||
|  |         ref = ref.resize((18, 18), Image.BICUBIC) | ||||||
|  | 
 | ||||||
|  |         with Image.open("Tests/images/hopper.jpg") as im: | ||||||
|  |             im.thumbnail((18, 18), Image.BICUBIC, reducing_gap=3.0) | ||||||
|  | 
 | ||||||
|             assert_image_equal(ref, im) |             assert_image_equal(ref, im) | ||||||
| 
 |  | ||||||
|         assert_image_similar(ref, im, 3.5) |  | ||||||
| 
 |  | ||||||
|     def test_reducing_gap_for_DCT_scaling(self): |  | ||||||
|         with Image.open("Tests/images/hopper.jpg") as ref: |  | ||||||
|             # thumbnail should call draft with reducing_gap scale |  | ||||||
|             ref.draft(None, (18 * 3, 18 * 3)) |  | ||||||
|             ref = ref.resize((18, 18), Image.BICUBIC) |  | ||||||
| 
 |  | ||||||
|             with Image.open("Tests/images/hopper.jpg") as im: |  | ||||||
|                 im.thumbnail((18, 18), Image.BICUBIC, reducing_gap=3.0) |  | ||||||
| 
 |  | ||||||
|                 assert_image_equal(ref, im) |  | ||||||
|  |  | ||||||
|  | @ -1,14 +1,16 @@ | ||||||
| from .helper import PillowTestCase, assert_image_equal, fromstring, hopper | import pytest | ||||||
|  | 
 | ||||||
|  | from .helper import assert_image_equal, fromstring, hopper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageToBitmap(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |  | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(ValueError, lambda: hopper().tobitmap()) |     with pytest.raises(ValueError): | ||||||
|  |         hopper().tobitmap() | ||||||
| 
 | 
 | ||||||
|         im1 = hopper().convert("1") |     im1 = hopper().convert("1") | ||||||
| 
 | 
 | ||||||
|         bitmap = im1.tobitmap() |     bitmap = im1.tobitmap() | ||||||
| 
 | 
 | ||||||
|         self.assertIsInstance(bitmap, bytes) |     assert isinstance(bitmap, bytes) | ||||||
|         assert_image_equal(im1, fromstring(bitmap)) |     assert_image_equal(im1, fromstring(bitmap)) | ||||||
|  |  | ||||||
|  | @ -9,151 +9,154 @@ from PIL.Image import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| from . import helper | from . import helper | ||||||
| from .helper import PillowTestCase, assert_image_equal | from .helper import assert_image_equal | ||||||
|  | 
 | ||||||
|  | HOPPER = { | ||||||
|  |     mode: helper.hopper(mode).crop((0, 0, 121, 127)).copy() | ||||||
|  |     for mode in ["L", "RGB", "I;16", "I;16L", "I;16B"] | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageTranspose(PillowTestCase): | def test_flip_left_right(): | ||||||
|  |     def transpose(mode): | ||||||
|  |         im = HOPPER[mode] | ||||||
|  |         out = im.transpose(FLIP_LEFT_RIGHT) | ||||||
|  |         assert out.mode == mode | ||||||
|  |         assert out.size == im.size | ||||||
| 
 | 
 | ||||||
|     hopper = { |         x, y = im.size | ||||||
|         mode: helper.hopper(mode).crop((0, 0, 121, 127)).copy() |         assert im.getpixel((1, 1)) == out.getpixel((x - 2, 1)) | ||||||
|         for mode in ["L", "RGB", "I;16", "I;16L", "I;16B"] |         assert im.getpixel((x - 2, 1)) == out.getpixel((1, 1)) | ||||||
|     } |         assert im.getpixel((1, y - 2)) == out.getpixel((x - 2, y - 2)) | ||||||
|  |         assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, y - 2)) | ||||||
| 
 | 
 | ||||||
|     def test_flip_left_right(self): |     for mode in HOPPER: | ||||||
|         def transpose(mode): |         transpose(mode) | ||||||
|             im = self.hopper[mode] |  | ||||||
|             out = im.transpose(FLIP_LEFT_RIGHT) |  | ||||||
|             self.assertEqual(out.mode, mode) |  | ||||||
|             self.assertEqual(out.size, im.size) |  | ||||||
| 
 | 
 | ||||||
|             x, y = im.size |  | ||||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((x - 2, 1))) |  | ||||||
|             self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((1, 1))) |  | ||||||
|             self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((x - 2, y - 2))) |  | ||||||
|             self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((1, y - 2))) |  | ||||||
| 
 | 
 | ||||||
|         for mode in self.hopper: | def test_flip_top_bottom(): | ||||||
|             transpose(mode) |     def transpose(mode): | ||||||
|  |         im = HOPPER[mode] | ||||||
|  |         out = im.transpose(FLIP_TOP_BOTTOM) | ||||||
|  |         assert out.mode == mode | ||||||
|  |         assert out.size == im.size | ||||||
| 
 | 
 | ||||||
|     def test_flip_top_bottom(self): |         x, y = im.size | ||||||
|         def transpose(mode): |         assert im.getpixel((1, 1)) == out.getpixel((1, y - 2)) | ||||||
|             im = self.hopper[mode] |         assert im.getpixel((x - 2, 1)) == out.getpixel((x - 2, y - 2)) | ||||||
|             out = im.transpose(FLIP_TOP_BOTTOM) |         assert im.getpixel((1, y - 2)) == out.getpixel((1, 1)) | ||||||
|             self.assertEqual(out.mode, mode) |         assert im.getpixel((x - 2, y - 2)) == out.getpixel((x - 2, 1)) | ||||||
|             self.assertEqual(out.size, im.size) |  | ||||||
| 
 | 
 | ||||||
|             x, y = im.size |     for mode in HOPPER: | ||||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((1, y - 2))) |         transpose(mode) | ||||||
|             self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((x - 2, y - 2))) |  | ||||||
|             self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((1, 1))) |  | ||||||
|             self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((x - 2, 1))) |  | ||||||
| 
 | 
 | ||||||
|         for mode in self.hopper: |  | ||||||
|             transpose(mode) |  | ||||||
| 
 | 
 | ||||||
|     def test_rotate_90(self): | def test_rotate_90(): | ||||||
|         def transpose(mode): |     def transpose(mode): | ||||||
|             im = self.hopper[mode] |         im = HOPPER[mode] | ||||||
|             out = im.transpose(ROTATE_90) |         out = im.transpose(ROTATE_90) | ||||||
|             self.assertEqual(out.mode, mode) |         assert out.mode == mode | ||||||
|             self.assertEqual(out.size, im.size[::-1]) |         assert out.size == im.size[::-1] | ||||||
| 
 | 
 | ||||||
|             x, y = im.size |         x, y = im.size | ||||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((1, x - 2))) |         assert im.getpixel((1, 1)) == out.getpixel((1, x - 2)) | ||||||
|             self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((1, 1))) |         assert im.getpixel((x - 2, 1)) == out.getpixel((1, 1)) | ||||||
|             self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((y - 2, x - 2))) |         assert im.getpixel((1, y - 2)) == out.getpixel((y - 2, x - 2)) | ||||||
|             self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((y - 2, 1))) |         assert im.getpixel((x - 2, y - 2)) == out.getpixel((y - 2, 1)) | ||||||
| 
 | 
 | ||||||
|         for mode in self.hopper: |     for mode in HOPPER: | ||||||
|             transpose(mode) |         transpose(mode) | ||||||
| 
 | 
 | ||||||
|     def test_rotate_180(self): |  | ||||||
|         def transpose(mode): |  | ||||||
|             im = self.hopper[mode] |  | ||||||
|             out = im.transpose(ROTATE_180) |  | ||||||
|             self.assertEqual(out.mode, mode) |  | ||||||
|             self.assertEqual(out.size, im.size) |  | ||||||
| 
 | 
 | ||||||
|             x, y = im.size | def test_rotate_180(): | ||||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((x - 2, y - 2))) |     def transpose(mode): | ||||||
|             self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((1, y - 2))) |         im = HOPPER[mode] | ||||||
|             self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((x - 2, 1))) |         out = im.transpose(ROTATE_180) | ||||||
|             self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((1, 1))) |         assert out.mode == mode | ||||||
|  |         assert out.size == im.size | ||||||
| 
 | 
 | ||||||
|         for mode in self.hopper: |         x, y = im.size | ||||||
|             transpose(mode) |         assert im.getpixel((1, 1)) == out.getpixel((x - 2, y - 2)) | ||||||
|  |         assert im.getpixel((x - 2, 1)) == out.getpixel((1, y - 2)) | ||||||
|  |         assert im.getpixel((1, y - 2)) == out.getpixel((x - 2, 1)) | ||||||
|  |         assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, 1)) | ||||||
| 
 | 
 | ||||||
|     def test_rotate_270(self): |     for mode in HOPPER: | ||||||
|         def transpose(mode): |         transpose(mode) | ||||||
|             im = self.hopper[mode] |  | ||||||
|             out = im.transpose(ROTATE_270) |  | ||||||
|             self.assertEqual(out.mode, mode) |  | ||||||
|             self.assertEqual(out.size, im.size[::-1]) |  | ||||||
| 
 | 
 | ||||||
|             x, y = im.size |  | ||||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((y - 2, 1))) |  | ||||||
|             self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((y - 2, x - 2))) |  | ||||||
|             self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((1, 1))) |  | ||||||
|             self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((1, x - 2))) |  | ||||||
| 
 | 
 | ||||||
|         for mode in self.hopper: | def test_rotate_270(): | ||||||
|             transpose(mode) |     def transpose(mode): | ||||||
|  |         im = HOPPER[mode] | ||||||
|  |         out = im.transpose(ROTATE_270) | ||||||
|  |         assert out.mode == mode | ||||||
|  |         assert out.size == im.size[::-1] | ||||||
| 
 | 
 | ||||||
|     def test_transpose(self): |         x, y = im.size | ||||||
|         def transpose(mode): |         assert im.getpixel((1, 1)) == out.getpixel((y - 2, 1)) | ||||||
|             im = self.hopper[mode] |         assert im.getpixel((x - 2, 1)) == out.getpixel((y - 2, x - 2)) | ||||||
|             out = im.transpose(TRANSPOSE) |         assert im.getpixel((1, y - 2)) == out.getpixel((1, 1)) | ||||||
|             self.assertEqual(out.mode, mode) |         assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, x - 2)) | ||||||
|             self.assertEqual(out.size, im.size[::-1]) |  | ||||||
| 
 | 
 | ||||||
|             x, y = im.size |     for mode in HOPPER: | ||||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((1, 1))) |         transpose(mode) | ||||||
|             self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((1, x - 2))) |  | ||||||
|             self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((y - 2, 1))) |  | ||||||
|             self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((y - 2, x - 2))) |  | ||||||
| 
 | 
 | ||||||
|         for mode in self.hopper: |  | ||||||
|             transpose(mode) |  | ||||||
| 
 | 
 | ||||||
|     def test_tranverse(self): | def test_transpose(): | ||||||
|         def transpose(mode): |     def transpose(mode): | ||||||
|             im = self.hopper[mode] |         im = HOPPER[mode] | ||||||
|             out = im.transpose(TRANSVERSE) |         out = im.transpose(TRANSPOSE) | ||||||
|             self.assertEqual(out.mode, mode) |         assert out.mode == mode | ||||||
|             self.assertEqual(out.size, im.size[::-1]) |         assert out.size == im.size[::-1] | ||||||
| 
 | 
 | ||||||
|             x, y = im.size |         x, y = im.size | ||||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((y - 2, x - 2))) |         assert im.getpixel((1, 1)) == out.getpixel((1, 1)) | ||||||
|             self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((y - 2, 1))) |         assert im.getpixel((x - 2, 1)) == out.getpixel((1, x - 2)) | ||||||
|             self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((1, x - 2))) |         assert im.getpixel((1, y - 2)) == out.getpixel((y - 2, 1)) | ||||||
|             self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((1, 1))) |         assert im.getpixel((x - 2, y - 2)) == out.getpixel((y - 2, x - 2)) | ||||||
| 
 | 
 | ||||||
|         for mode in self.hopper: |     for mode in HOPPER: | ||||||
|             transpose(mode) |         transpose(mode) | ||||||
| 
 | 
 | ||||||
|     def test_roundtrip(self): |  | ||||||
|         for mode in self.hopper: |  | ||||||
|             im = self.hopper[mode] |  | ||||||
| 
 | 
 | ||||||
|             def transpose(first, second): | def test_tranverse(): | ||||||
|                 return im.transpose(first).transpose(second) |     def transpose(mode): | ||||||
|  |         im = HOPPER[mode] | ||||||
|  |         out = im.transpose(TRANSVERSE) | ||||||
|  |         assert out.mode == mode | ||||||
|  |         assert out.size == im.size[::-1] | ||||||
| 
 | 
 | ||||||
|             assert_image_equal(im, transpose(FLIP_LEFT_RIGHT, FLIP_LEFT_RIGHT)) |         x, y = im.size | ||||||
|             assert_image_equal(im, transpose(FLIP_TOP_BOTTOM, FLIP_TOP_BOTTOM)) |         assert im.getpixel((1, 1)) == out.getpixel((y - 2, x - 2)) | ||||||
|             assert_image_equal(im, transpose(ROTATE_90, ROTATE_270)) |         assert im.getpixel((x - 2, 1)) == out.getpixel((y - 2, 1)) | ||||||
|             assert_image_equal(im, transpose(ROTATE_180, ROTATE_180)) |         assert im.getpixel((1, y - 2)) == out.getpixel((1, x - 2)) | ||||||
|             assert_image_equal( |         assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, 1)) | ||||||
|                 im.transpose(TRANSPOSE), transpose(ROTATE_90, FLIP_TOP_BOTTOM) | 
 | ||||||
|             ) |     for mode in HOPPER: | ||||||
|             assert_image_equal( |         transpose(mode) | ||||||
|                 im.transpose(TRANSPOSE), transpose(ROTATE_270, FLIP_LEFT_RIGHT) | 
 | ||||||
|             ) | 
 | ||||||
|             assert_image_equal( | def test_roundtrip(): | ||||||
|                 im.transpose(TRANSVERSE), transpose(ROTATE_90, FLIP_LEFT_RIGHT) |     for mode in HOPPER: | ||||||
|             ) |         im = HOPPER[mode] | ||||||
|             assert_image_equal( | 
 | ||||||
|                 im.transpose(TRANSVERSE), transpose(ROTATE_270, FLIP_TOP_BOTTOM) |         def transpose(first, second): | ||||||
|             ) |             return im.transpose(first).transpose(second) | ||||||
|             assert_image_equal( | 
 | ||||||
|                 im.transpose(TRANSVERSE), transpose(ROTATE_180, TRANSPOSE) |         assert_image_equal(im, transpose(FLIP_LEFT_RIGHT, FLIP_LEFT_RIGHT)) | ||||||
|             ) |         assert_image_equal(im, transpose(FLIP_TOP_BOTTOM, FLIP_TOP_BOTTOM)) | ||||||
|  |         assert_image_equal(im, transpose(ROTATE_90, ROTATE_270)) | ||||||
|  |         assert_image_equal(im, transpose(ROTATE_180, ROTATE_180)) | ||||||
|  |         assert_image_equal( | ||||||
|  |             im.transpose(TRANSPOSE), transpose(ROTATE_90, FLIP_TOP_BOTTOM) | ||||||
|  |         ) | ||||||
|  |         assert_image_equal( | ||||||
|  |             im.transpose(TRANSPOSE), transpose(ROTATE_270, FLIP_LEFT_RIGHT) | ||||||
|  |         ) | ||||||
|  |         assert_image_equal( | ||||||
|  |             im.transpose(TRANSVERSE), transpose(ROTATE_90, FLIP_LEFT_RIGHT) | ||||||
|  |         ) | ||||||
|  |         assert_image_equal( | ||||||
|  |             im.transpose(TRANSVERSE), transpose(ROTATE_270, FLIP_TOP_BOTTOM) | ||||||
|  |         ) | ||||||
|  |         assert_image_equal(im.transpose(TRANSVERSE), transpose(ROTATE_180, TRANSPOSE)) | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| from PIL import Image, ImageChops | from PIL import Image, ImageChops | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, hopper | from .helper import assert_image_equal, hopper | ||||||
| 
 | 
 | ||||||
| BLACK = (0, 0, 0) | BLACK = (0, 0, 0) | ||||||
| BROWN = (127, 64, 0) | BROWN = (127, 64, 0) | ||||||
|  | @ -13,352 +13,373 @@ WHITE = (255, 255, 255) | ||||||
| GREY = 128 | GREY = 128 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageChops(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     im = hopper("L") | ||||||
| 
 | 
 | ||||||
|         im = hopper("L") |     ImageChops.constant(im, 128) | ||||||
|  |     ImageChops.duplicate(im) | ||||||
|  |     ImageChops.invert(im) | ||||||
|  |     ImageChops.lighter(im, im) | ||||||
|  |     ImageChops.darker(im, im) | ||||||
|  |     ImageChops.difference(im, im) | ||||||
|  |     ImageChops.multiply(im, im) | ||||||
|  |     ImageChops.screen(im, im) | ||||||
| 
 | 
 | ||||||
|         ImageChops.constant(im, 128) |     ImageChops.add(im, im) | ||||||
|         ImageChops.duplicate(im) |     ImageChops.add(im, im, 2.0) | ||||||
|         ImageChops.invert(im) |     ImageChops.add(im, im, 2.0, 128) | ||||||
|         ImageChops.lighter(im, im) |     ImageChops.subtract(im, im) | ||||||
|         ImageChops.darker(im, im) |     ImageChops.subtract(im, im, 2.0) | ||||||
|         ImageChops.difference(im, im) |     ImageChops.subtract(im, im, 2.0, 128) | ||||||
|         ImageChops.multiply(im, im) |  | ||||||
|         ImageChops.screen(im, im) |  | ||||||
| 
 | 
 | ||||||
|         ImageChops.add(im, im) |     ImageChops.add_modulo(im, im) | ||||||
|         ImageChops.add(im, im, 2.0) |     ImageChops.subtract_modulo(im, im) | ||||||
|         ImageChops.add(im, im, 2.0, 128) |  | ||||||
|         ImageChops.subtract(im, im) |  | ||||||
|         ImageChops.subtract(im, im, 2.0) |  | ||||||
|         ImageChops.subtract(im, im, 2.0, 128) |  | ||||||
| 
 | 
 | ||||||
|         ImageChops.add_modulo(im, im) |     ImageChops.blend(im, im, 0.5) | ||||||
|         ImageChops.subtract_modulo(im, im) |     ImageChops.composite(im, im, im) | ||||||
| 
 | 
 | ||||||
|         ImageChops.blend(im, im, 0.5) |     ImageChops.offset(im, 10) | ||||||
|         ImageChops.composite(im, im, im) |     ImageChops.offset(im, 10, 20) | ||||||
| 
 | 
 | ||||||
|         ImageChops.offset(im, 10) |  | ||||||
|         ImageChops.offset(im, 10, 20) |  | ||||||
| 
 | 
 | ||||||
|     def test_add(self): | def test_add(): | ||||||
|         # Arrange |     # Arrange | ||||||
|         with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: |     with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: | ||||||
|             with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: |         with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|                 # Act |             # Act | ||||||
|                 new = ImageChops.add(im1, im2) |             new = ImageChops.add(im1, im2) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         self.assertEqual(new.getbbox(), (25, 25, 76, 76)) |     assert new.getbbox() == (25, 25, 76, 76) | ||||||
|         self.assertEqual(new.getpixel((50, 50)), ORANGE) |     assert new.getpixel((50, 50)) == ORANGE | ||||||
| 
 | 
 | ||||||
|     def test_add_scale_offset(self): |  | ||||||
|         # Arrange |  | ||||||
|         with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: |  | ||||||
|             with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: |  | ||||||
| 
 | 
 | ||||||
|                 # Act | def test_add_scale_offset(): | ||||||
|                 new = ImageChops.add(im1, im2, scale=2.5, offset=100) |     # Arrange | ||||||
|  |     with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: | ||||||
|  |         with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|         # Assert |             # Act | ||||||
|         self.assertEqual(new.getbbox(), (0, 0, 100, 100)) |             new = ImageChops.add(im1, im2, scale=2.5, offset=100) | ||||||
|         self.assertEqual(new.getpixel((50, 50)), (202, 151, 100)) |  | ||||||
| 
 | 
 | ||||||
|     def test_add_clip(self): |     # Assert | ||||||
|         # Arrange |     assert new.getbbox() == (0, 0, 100, 100) | ||||||
|         im = hopper() |     assert new.getpixel((50, 50)) == (202, 151, 100) | ||||||
| 
 | 
 | ||||||
|         # Act |  | ||||||
|         new = ImageChops.add(im, im) |  | ||||||
| 
 | 
 | ||||||
|         # Assert | def test_add_clip(): | ||||||
|         self.assertEqual(new.getpixel((50, 50)), (255, 255, 254)) |     # Arrange | ||||||
|  |     im = hopper() | ||||||
| 
 | 
 | ||||||
|     def test_add_modulo(self): |     # Act | ||||||
|         # Arrange |     new = ImageChops.add(im, im) | ||||||
|         with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: |  | ||||||
|             with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: |  | ||||||
| 
 | 
 | ||||||
|                 # Act |     # Assert | ||||||
|                 new = ImageChops.add_modulo(im1, im2) |     assert new.getpixel((50, 50)) == (255, 255, 254) | ||||||
| 
 | 
 | ||||||
|         # Assert |  | ||||||
|         self.assertEqual(new.getbbox(), (25, 25, 76, 76)) |  | ||||||
|         self.assertEqual(new.getpixel((50, 50)), ORANGE) |  | ||||||
| 
 | 
 | ||||||
|     def test_add_modulo_no_clip(self): | def test_add_modulo(): | ||||||
|         # Arrange |     # Arrange | ||||||
|         im = hopper() |     with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: | ||||||
|  |         with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|         # Act |             # Act | ||||||
|         new = ImageChops.add_modulo(im, im) |             new = ImageChops.add_modulo(im1, im2) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         self.assertEqual(new.getpixel((50, 50)), (224, 76, 254)) |     assert new.getbbox() == (25, 25, 76, 76) | ||||||
|  |     assert new.getpixel((50, 50)) == ORANGE | ||||||
| 
 | 
 | ||||||
|     def test_blend(self): |  | ||||||
|         # Arrange |  | ||||||
|         with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: |  | ||||||
|             with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: |  | ||||||
| 
 | 
 | ||||||
|                 # Act | def test_add_modulo_no_clip(): | ||||||
|                 new = ImageChops.blend(im1, im2, 0.5) |     # Arrange | ||||||
|  |     im = hopper() | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Act | ||||||
|         self.assertEqual(new.getbbox(), (25, 25, 76, 76)) |     new = ImageChops.add_modulo(im, im) | ||||||
|         self.assertEqual(new.getpixel((50, 50)), BROWN) |  | ||||||
| 
 | 
 | ||||||
|     def test_constant(self): |     # Assert | ||||||
|         # Arrange |     assert new.getpixel((50, 50)) == (224, 76, 254) | ||||||
|         im = Image.new("RGB", (20, 10)) |  | ||||||
| 
 | 
 | ||||||
|         # Act |  | ||||||
|         new = ImageChops.constant(im, GREY) |  | ||||||
| 
 | 
 | ||||||
|         # Assert | def test_blend(): | ||||||
|         self.assertEqual(new.size, im.size) |     # Arrange | ||||||
|         self.assertEqual(new.getpixel((0, 0)), GREY) |     with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: | ||||||
|         self.assertEqual(new.getpixel((19, 9)), GREY) |         with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|     def test_darker_image(self): |             # Act | ||||||
|         # Arrange |             new = ImageChops.blend(im1, im2, 0.5) | ||||||
|         with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: |  | ||||||
|             with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: |  | ||||||
| 
 | 
 | ||||||
|                 # Act |     # Assert | ||||||
|                 new = ImageChops.darker(im1, im2) |     assert new.getbbox() == (25, 25, 76, 76) | ||||||
|  |     assert new.getpixel((50, 50)) == BROWN | ||||||
| 
 | 
 | ||||||
|                 # Assert |  | ||||||
|                 assert_image_equal(new, im2) |  | ||||||
| 
 | 
 | ||||||
|     def test_darker_pixel(self): | def test_constant(): | ||||||
|         # Arrange |     # Arrange | ||||||
|         im1 = hopper() |     im = Image.new("RGB", (20, 10)) | ||||||
|         with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: | 
 | ||||||
|  |     # Act | ||||||
|  |     new = ImageChops.constant(im, GREY) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert new.size == im.size | ||||||
|  |     assert new.getpixel((0, 0)) == GREY | ||||||
|  |     assert new.getpixel((19, 9)) == GREY | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_darker_image(): | ||||||
|  |     # Arrange | ||||||
|  |     with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: | ||||||
|  |         with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|             # Act |             # Act | ||||||
|             new = ImageChops.darker(im1, im2) |             new = ImageChops.darker(im1, im2) | ||||||
| 
 | 
 | ||||||
|         # Assert |             # Assert | ||||||
|         self.assertEqual(new.getpixel((50, 50)), (240, 166, 0)) |             assert_image_equal(new, im2) | ||||||
| 
 | 
 | ||||||
|     def test_difference(self): |  | ||||||
|         # Arrange |  | ||||||
|         with Image.open("Tests/images/imagedraw_arc_end_le_start.png") as im1: |  | ||||||
|             with Image.open("Tests/images/imagedraw_arc_no_loops.png") as im2: |  | ||||||
| 
 | 
 | ||||||
|                 # Act | def test_darker_pixel(): | ||||||
|                 new = ImageChops.difference(im1, im2) |     # Arrange | ||||||
|  |     im1 = hopper() | ||||||
|  |     with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|         # Assert |         # Act | ||||||
|         self.assertEqual(new.getbbox(), (25, 25, 76, 76)) |         new = ImageChops.darker(im1, im2) | ||||||
| 
 | 
 | ||||||
|     def test_difference_pixel(self): |     # Assert | ||||||
|         # Arrange |     assert new.getpixel((50, 50)) == (240, 166, 0) | ||||||
|         im1 = hopper() | 
 | ||||||
|         with Image.open("Tests/images/imagedraw_polygon_kite_RGB.png") as im2: | 
 | ||||||
|  | def test_difference(): | ||||||
|  |     # Arrange | ||||||
|  |     with Image.open("Tests/images/imagedraw_arc_end_le_start.png") as im1: | ||||||
|  |         with Image.open("Tests/images/imagedraw_arc_no_loops.png") as im2: | ||||||
| 
 | 
 | ||||||
|             # Act |             # Act | ||||||
|             new = ImageChops.difference(im1, im2) |             new = ImageChops.difference(im1, im2) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         self.assertEqual(new.getpixel((50, 50)), (240, 166, 128)) |     assert new.getbbox() == (25, 25, 76, 76) | ||||||
| 
 | 
 | ||||||
|     def test_duplicate(self): | 
 | ||||||
|         # Arrange | def test_difference_pixel(): | ||||||
|         im = hopper() |     # Arrange | ||||||
|  |     im1 = hopper() | ||||||
|  |     with Image.open("Tests/images/imagedraw_polygon_kite_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|         # Act |         # Act | ||||||
|         new = ImageChops.duplicate(im) |         new = ImageChops.difference(im1, im2) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         assert_image_equal(new, im) |     assert new.getpixel((50, 50)) == (240, 166, 128) | ||||||
| 
 | 
 | ||||||
|     def test_invert(self): |  | ||||||
|         # Arrange |  | ||||||
|         with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im: |  | ||||||
| 
 | 
 | ||||||
|             # Act | def test_duplicate(): | ||||||
|             new = ImageChops.invert(im) |     # Arrange | ||||||
|  |     im = hopper() | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Act | ||||||
|         self.assertEqual(new.getbbox(), (0, 0, 100, 100)) |     new = ImageChops.duplicate(im) | ||||||
|         self.assertEqual(new.getpixel((0, 0)), WHITE) |  | ||||||
|         self.assertEqual(new.getpixel((50, 50)), CYAN) |  | ||||||
| 
 | 
 | ||||||
|     def test_lighter_image(self): |     # Assert | ||||||
|         # Arrange |     assert_image_equal(new, im) | ||||||
|         with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: |  | ||||||
|             with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: |  | ||||||
| 
 | 
 | ||||||
|                 # Act |  | ||||||
|                 new = ImageChops.lighter(im1, im2) |  | ||||||
| 
 | 
 | ||||||
|         # Assert | def test_invert(): | ||||||
|         assert_image_equal(new, im1) |     # Arrange | ||||||
|  |     with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im: | ||||||
| 
 | 
 | ||||||
|     def test_lighter_pixel(self): |         # Act | ||||||
|         # Arrange |         new = ImageChops.invert(im) | ||||||
|         im1 = hopper() | 
 | ||||||
|         with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: |     # Assert | ||||||
|  |     assert new.getbbox() == (0, 0, 100, 100) | ||||||
|  |     assert new.getpixel((0, 0)) == WHITE | ||||||
|  |     assert new.getpixel((50, 50)) == CYAN | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_lighter_image(): | ||||||
|  |     # Arrange | ||||||
|  |     with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: | ||||||
|  |         with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|             # Act |             # Act | ||||||
|             new = ImageChops.lighter(im1, im2) |             new = ImageChops.lighter(im1, im2) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         self.assertEqual(new.getpixel((50, 50)), (255, 255, 127)) |     assert_image_equal(new, im1) | ||||||
| 
 | 
 | ||||||
|     def test_multiply_black(self): | 
 | ||||||
|         """If you multiply an image with a solid black image, | def test_lighter_pixel(): | ||||||
|         the result is black.""" |     # Arrange | ||||||
|         # Arrange |     im1 = hopper() | ||||||
|         im1 = hopper() |     with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: | ||||||
|         black = Image.new("RGB", im1.size, "black") |  | ||||||
| 
 | 
 | ||||||
|         # Act |         # Act | ||||||
|         new = ImageChops.multiply(im1, black) |         new = ImageChops.lighter(im1, im2) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         assert_image_equal(new, black) |     assert new.getpixel((50, 50)) == (255, 255, 127) | ||||||
| 
 | 
 | ||||||
|     def test_multiply_green(self): |  | ||||||
|         # Arrange |  | ||||||
|         with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im: |  | ||||||
|             green = Image.new("RGB", im.size, "green") |  | ||||||
| 
 | 
 | ||||||
|             # Act | def test_multiply_black(): | ||||||
|             new = ImageChops.multiply(im, green) |     """If you multiply an image with a solid black image, | ||||||
|  |     the result is black.""" | ||||||
|  |     # Arrange | ||||||
|  |     im1 = hopper() | ||||||
|  |     black = Image.new("RGB", im1.size, "black") | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Act | ||||||
|         self.assertEqual(new.getbbox(), (25, 25, 76, 76)) |     new = ImageChops.multiply(im1, black) | ||||||
|         self.assertEqual(new.getpixel((25, 25)), DARK_GREEN) |  | ||||||
|         self.assertEqual(new.getpixel((50, 50)), BLACK) |  | ||||||
| 
 | 
 | ||||||
|     def test_multiply_white(self): |     # Assert | ||||||
|         """If you multiply with a solid white image, |     assert_image_equal(new, black) | ||||||
|         the image is unaffected.""" | 
 | ||||||
|         # Arrange | 
 | ||||||
|         im1 = hopper() | def test_multiply_green(): | ||||||
|         white = Image.new("RGB", im1.size, "white") |     # Arrange | ||||||
|  |     with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im: | ||||||
|  |         green = Image.new("RGB", im.size, "green") | ||||||
| 
 | 
 | ||||||
|         # Act |         # Act | ||||||
|         new = ImageChops.multiply(im1, white) |         new = ImageChops.multiply(im, green) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         assert_image_equal(new, im1) |     assert new.getbbox() == (25, 25, 76, 76) | ||||||
|  |     assert new.getpixel((25, 25)) == DARK_GREEN | ||||||
|  |     assert new.getpixel((50, 50)) == BLACK | ||||||
| 
 | 
 | ||||||
|     def test_offset(self): | 
 | ||||||
|         # Arrange | def test_multiply_white(): | ||||||
|         xoffset = 45 |     """If you multiply with a solid white image, the image is unaffected.""" | ||||||
|         yoffset = 20 |     # Arrange | ||||||
|         with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im: |     im1 = hopper() | ||||||
|  |     white = Image.new("RGB", im1.size, "white") | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     new = ImageChops.multiply(im1, white) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert_image_equal(new, im1) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_offset(): | ||||||
|  |     # Arrange | ||||||
|  |     xoffset = 45 | ||||||
|  |     yoffset = 20 | ||||||
|  |     with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im: | ||||||
|  | 
 | ||||||
|  |         # Act | ||||||
|  |         new = ImageChops.offset(im, xoffset, yoffset) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert new.getbbox() == (0, 45, 100, 96) | ||||||
|  |     assert new.getpixel((50, 50)) == BLACK | ||||||
|  |     assert new.getpixel((50 + xoffset, 50 + yoffset)) == DARK_GREEN | ||||||
|  | 
 | ||||||
|  |     # Test no yoffset | ||||||
|  |     assert ImageChops.offset(im, xoffset) == ImageChops.offset(im, xoffset, xoffset) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_screen(): | ||||||
|  |     # Arrange | ||||||
|  |     with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: | ||||||
|  |         with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|             # Act |             # Act | ||||||
|             new = ImageChops.offset(im, xoffset, yoffset) |             new = ImageChops.screen(im1, im2) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         self.assertEqual(new.getbbox(), (0, 45, 100, 96)) |     assert new.getbbox() == (25, 25, 76, 76) | ||||||
|         self.assertEqual(new.getpixel((50, 50)), BLACK) |     assert new.getpixel((50, 50)) == ORANGE | ||||||
|         self.assertEqual(new.getpixel((50 + xoffset, 50 + yoffset)), DARK_GREEN) |  | ||||||
| 
 | 
 | ||||||
|         # Test no yoffset |  | ||||||
|         self.assertEqual( |  | ||||||
|             ImageChops.offset(im, xoffset), ImageChops.offset(im, xoffset, xoffset) |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def test_screen(self): | def test_subtract(): | ||||||
|         # Arrange |     # Arrange | ||||||
|         with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: |     with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: | ||||||
|             with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: |         with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: | ||||||
| 
 |  | ||||||
|                 # Act |  | ||||||
|                 new = ImageChops.screen(im1, im2) |  | ||||||
| 
 |  | ||||||
|         # Assert |  | ||||||
|         self.assertEqual(new.getbbox(), (25, 25, 76, 76)) |  | ||||||
|         self.assertEqual(new.getpixel((50, 50)), ORANGE) |  | ||||||
| 
 |  | ||||||
|     def test_subtract(self): |  | ||||||
|         # Arrange |  | ||||||
|         with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: |  | ||||||
|             with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: |  | ||||||
| 
 |  | ||||||
|                 # Act |  | ||||||
|                 new = ImageChops.subtract(im1, im2) |  | ||||||
| 
 |  | ||||||
|         # Assert |  | ||||||
|         self.assertEqual(new.getbbox(), (25, 50, 76, 76)) |  | ||||||
|         self.assertEqual(new.getpixel((50, 50)), GREEN) |  | ||||||
|         self.assertEqual(new.getpixel((50, 51)), BLACK) |  | ||||||
| 
 |  | ||||||
|     def test_subtract_scale_offset(self): |  | ||||||
|         # Arrange |  | ||||||
|         with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: |  | ||||||
|             with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: |  | ||||||
| 
 |  | ||||||
|                 # Act |  | ||||||
|                 new = ImageChops.subtract(im1, im2, scale=2.5, offset=100) |  | ||||||
| 
 |  | ||||||
|         # Assert |  | ||||||
|         self.assertEqual(new.getbbox(), (0, 0, 100, 100)) |  | ||||||
|         self.assertEqual(new.getpixel((50, 50)), (100, 202, 100)) |  | ||||||
| 
 |  | ||||||
|     def test_subtract_clip(self): |  | ||||||
|         # Arrange |  | ||||||
|         im1 = hopper() |  | ||||||
|         with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: |  | ||||||
| 
 | 
 | ||||||
|             # Act |             # Act | ||||||
|             new = ImageChops.subtract(im1, im2) |             new = ImageChops.subtract(im1, im2) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         self.assertEqual(new.getpixel((50, 50)), (0, 0, 127)) |     assert new.getbbox() == (25, 50, 76, 76) | ||||||
|  |     assert new.getpixel((50, 50)) == GREEN | ||||||
|  |     assert new.getpixel((50, 51)) == BLACK | ||||||
| 
 | 
 | ||||||
|     def test_subtract_modulo(self): |  | ||||||
|         # Arrange |  | ||||||
|         with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: |  | ||||||
|             with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: |  | ||||||
| 
 | 
 | ||||||
|                 # Act | def test_subtract_scale_offset(): | ||||||
|                 new = ImageChops.subtract_modulo(im1, im2) |     # Arrange | ||||||
|  |     with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: | ||||||
|  |         with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|         # Assert |             # Act | ||||||
|         self.assertEqual(new.getbbox(), (25, 50, 76, 76)) |             new = ImageChops.subtract(im1, im2, scale=2.5, offset=100) | ||||||
|         self.assertEqual(new.getpixel((50, 50)), GREEN) |  | ||||||
|         self.assertEqual(new.getpixel((50, 51)), BLACK) |  | ||||||
| 
 | 
 | ||||||
|     def test_subtract_modulo_no_clip(self): |     # Assert | ||||||
|         # Arrange |     assert new.getbbox() == (0, 0, 100, 100) | ||||||
|         im1 = hopper() |     assert new.getpixel((50, 50)) == (100, 202, 100) | ||||||
|         with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: | 
 | ||||||
|  | 
 | ||||||
|  | def test_subtract_clip(): | ||||||
|  |     # Arrange | ||||||
|  |     im1 = hopper() | ||||||
|  |     with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: | ||||||
|  | 
 | ||||||
|  |         # Act | ||||||
|  |         new = ImageChops.subtract(im1, im2) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert new.getpixel((50, 50)) == (0, 0, 127) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_subtract_modulo(): | ||||||
|  |     # Arrange | ||||||
|  |     with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: | ||||||
|  |         with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|             # Act |             # Act | ||||||
|             new = ImageChops.subtract_modulo(im1, im2) |             new = ImageChops.subtract_modulo(im1, im2) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         self.assertEqual(new.getpixel((50, 50)), (241, 167, 127)) |     assert new.getbbox() == (25, 50, 76, 76) | ||||||
|  |     assert new.getpixel((50, 50)) == GREEN | ||||||
|  |     assert new.getpixel((50, 51)) == BLACK | ||||||
| 
 | 
 | ||||||
|     def test_logical(self): |  | ||||||
|         def table(op, a, b): |  | ||||||
|             out = [] |  | ||||||
|             for x in (a, b): |  | ||||||
|                 imx = Image.new("1", (1, 1), x) |  | ||||||
|                 for y in (a, b): |  | ||||||
|                     imy = Image.new("1", (1, 1), y) |  | ||||||
|                     out.append(op(imx, imy).getpixel((0, 0))) |  | ||||||
|             return tuple(out) |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(table(ImageChops.logical_and, 0, 1), (0, 0, 0, 255)) | def test_subtract_modulo_no_clip(): | ||||||
|         self.assertEqual(table(ImageChops.logical_or, 0, 1), (0, 255, 255, 255)) |     # Arrange | ||||||
|         self.assertEqual(table(ImageChops.logical_xor, 0, 1), (0, 255, 255, 0)) |     im1 = hopper() | ||||||
|  |     with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(table(ImageChops.logical_and, 0, 128), (0, 0, 0, 255)) |         # Act | ||||||
|         self.assertEqual(table(ImageChops.logical_or, 0, 128), (0, 255, 255, 255)) |         new = ImageChops.subtract_modulo(im1, im2) | ||||||
|         self.assertEqual(table(ImageChops.logical_xor, 0, 128), (0, 255, 255, 0)) |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(table(ImageChops.logical_and, 0, 255), (0, 0, 0, 255)) |     # Assert | ||||||
|         self.assertEqual(table(ImageChops.logical_or, 0, 255), (0, 255, 255, 255)) |     assert new.getpixel((50, 50)) == (241, 167, 127) | ||||||
|         self.assertEqual(table(ImageChops.logical_xor, 0, 255), (0, 255, 255, 0)) | 
 | ||||||
|  | 
 | ||||||
|  | def test_logical(): | ||||||
|  |     def table(op, a, b): | ||||||
|  |         out = [] | ||||||
|  |         for x in (a, b): | ||||||
|  |             imx = Image.new("1", (1, 1), x) | ||||||
|  |             for y in (a, b): | ||||||
|  |                 imy = Image.new("1", (1, 1), y) | ||||||
|  |                 out.append(op(imx, imy).getpixel((0, 0))) | ||||||
|  |         return tuple(out) | ||||||
|  | 
 | ||||||
|  |     assert table(ImageChops.logical_and, 0, 1) == (0, 0, 0, 255) | ||||||
|  |     assert table(ImageChops.logical_or, 0, 1) == (0, 255, 255, 255) | ||||||
|  |     assert table(ImageChops.logical_xor, 0, 1) == (0, 255, 255, 0) | ||||||
|  | 
 | ||||||
|  |     assert table(ImageChops.logical_and, 0, 128) == (0, 0, 0, 255) | ||||||
|  |     assert table(ImageChops.logical_or, 0, 128) == (0, 255, 255, 255) | ||||||
|  |     assert table(ImageChops.logical_xor, 0, 128) == (0, 255, 255, 0) | ||||||
|  | 
 | ||||||
|  |     assert table(ImageChops.logical_and, 0, 255) == (0, 0, 0, 255) | ||||||
|  |     assert table(ImageChops.logical_or, 0, 255) == (0, 255, 255, 255) | ||||||
|  |     assert table(ImageChops.logical_xor, 0, 255) == (0, 255, 255, 0) | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -1,9 +1,9 @@ | ||||||
| import os.path | import os.path | ||||||
| import unittest |  | ||||||
| 
 | 
 | ||||||
|  | import pytest | ||||||
| from PIL import Image, ImageDraw2, features | from PIL import Image, ImageDraw2, features | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper | from .helper import assert_image_equal, assert_image_similar, hopper | ||||||
| 
 | 
 | ||||||
| BLACK = (0, 0, 0) | BLACK = (0, 0, 0) | ||||||
| WHITE = (255, 255, 255) | WHITE = (255, 255, 255) | ||||||
|  | @ -34,190 +34,206 @@ HAS_FREETYPE = features.check("freetype2") | ||||||
| FONT_PATH = "Tests/fonts/FreeMono.ttf" | FONT_PATH = "Tests/fonts/FreeMono.ttf" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageDraw(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     im = hopper("RGB").copy() | ||||||
|         im = hopper("RGB").copy() |  | ||||||
| 
 | 
 | ||||||
|         draw = ImageDraw2.Draw(im) |     draw = ImageDraw2.Draw(im) | ||||||
|         pen = ImageDraw2.Pen("blue", width=7) |     pen = ImageDraw2.Pen("blue", width=7) | ||||||
|         draw.line(list(range(10)), pen) |     draw.line(list(range(10)), pen) | ||||||
| 
 | 
 | ||||||
|         from PIL import ImageDraw |     from PIL import ImageDraw | ||||||
| 
 | 
 | ||||||
|         draw, handler = ImageDraw.getdraw(im) |     draw, handler = ImageDraw.getdraw(im) | ||||||
|         pen = ImageDraw2.Pen("blue", width=7) |     pen = ImageDraw2.Pen("blue", width=7) | ||||||
|         draw.line(list(range(10)), pen) |     draw.line(list(range(10)), pen) | ||||||
| 
 | 
 | ||||||
|     def helper_ellipse(self, mode, bbox): |  | ||||||
|         # Arrange |  | ||||||
|         im = Image.new("RGB", (W, H)) |  | ||||||
|         draw = ImageDraw2.Draw(im) |  | ||||||
|         pen = ImageDraw2.Pen("blue", width=2) |  | ||||||
|         brush = ImageDraw2.Brush("green") |  | ||||||
|         expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode) |  | ||||||
| 
 | 
 | ||||||
|         # Act | def helper_ellipse(mode, bbox): | ||||||
|         draw.ellipse(bbox, pen, brush) |     # Arrange | ||||||
|  |     im = Image.new("RGB", (W, H)) | ||||||
|  |     draw = ImageDraw2.Draw(im) | ||||||
|  |     pen = ImageDraw2.Pen("blue", width=2) | ||||||
|  |     brush = ImageDraw2.Brush("green") | ||||||
|  |     expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Act | ||||||
|         assert_image_similar(im, Image.open(expected), 1) |     draw.ellipse(bbox, pen, brush) | ||||||
| 
 | 
 | ||||||
|     def test_ellipse1(self): |     # Assert | ||||||
|         self.helper_ellipse("RGB", BBOX1) |     assert_image_similar(im, Image.open(expected), 1) | ||||||
| 
 | 
 | ||||||
|     def test_ellipse2(self): |  | ||||||
|         self.helper_ellipse("RGB", BBOX2) |  | ||||||
| 
 | 
 | ||||||
|     def test_ellipse_edge(self): | def test_ellipse1(): | ||||||
|         # Arrange |     helper_ellipse("RGB", BBOX1) | ||||||
|         im = Image.new("RGB", (W, H)) |  | ||||||
|         draw = ImageDraw2.Draw(im) |  | ||||||
|         brush = ImageDraw2.Brush("white") |  | ||||||
| 
 | 
 | ||||||
|         # Act |  | ||||||
|         draw.ellipse(((0, 0), (W - 1, H)), brush) |  | ||||||
| 
 | 
 | ||||||
|         # Assert | def test_ellipse2(): | ||||||
|         assert_image_similar( |     helper_ellipse("RGB", BBOX2) | ||||||
|             im, Image.open("Tests/images/imagedraw_ellipse_edge.png"), 1 |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def helper_line(self, points): |  | ||||||
|         # Arrange |  | ||||||
|         im = Image.new("RGB", (W, H)) |  | ||||||
|         draw = ImageDraw2.Draw(im) |  | ||||||
|         pen = ImageDraw2.Pen("yellow", width=2) |  | ||||||
| 
 | 
 | ||||||
|         # Act | def test_ellipse_edge(): | ||||||
|         draw.line(points, pen) |     # Arrange | ||||||
|  |     im = Image.new("RGB", (W, H)) | ||||||
|  |     draw = ImageDraw2.Draw(im) | ||||||
|  |     brush = ImageDraw2.Brush("white") | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Act | ||||||
|         assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png")) |     draw.ellipse(((0, 0), (W - 1, H)), brush) | ||||||
| 
 | 
 | ||||||
|     def test_line1_pen(self): |     # Assert | ||||||
|         self.helper_line(POINTS1) |     assert_image_similar(im, Image.open("Tests/images/imagedraw_ellipse_edge.png"), 1) | ||||||
| 
 | 
 | ||||||
|     def test_line2_pen(self): |  | ||||||
|         self.helper_line(POINTS2) |  | ||||||
| 
 | 
 | ||||||
|     def test_line_pen_as_brush(self): | def helper_line(points): | ||||||
|         # Arrange |     # Arrange | ||||||
|         im = Image.new("RGB", (W, H)) |     im = Image.new("RGB", (W, H)) | ||||||
|         draw = ImageDraw2.Draw(im) |     draw = ImageDraw2.Draw(im) | ||||||
|         pen = None |     pen = ImageDraw2.Pen("yellow", width=2) | ||||||
|         brush = ImageDraw2.Pen("yellow", width=2) |  | ||||||
| 
 | 
 | ||||||
|         # Act |     # Act | ||||||
|         # Pass in the pen as the brush parameter |     draw.line(points, pen) | ||||||
|         draw.line(POINTS1, pen, brush) |  | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png")) |     assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png")) | ||||||
| 
 | 
 | ||||||
|     def helper_polygon(self, points): |  | ||||||
|         # Arrange |  | ||||||
|         im = Image.new("RGB", (W, H)) |  | ||||||
|         draw = ImageDraw2.Draw(im) |  | ||||||
|         pen = ImageDraw2.Pen("blue", width=2) |  | ||||||
|         brush = ImageDraw2.Brush("red") |  | ||||||
| 
 | 
 | ||||||
|         # Act | def test_line1_pen(): | ||||||
|         draw.polygon(points, pen, brush) |     helper_line(POINTS1) | ||||||
| 
 | 
 | ||||||
|         # Assert |  | ||||||
|         assert_image_equal(im, Image.open("Tests/images/imagedraw_polygon.png")) |  | ||||||
| 
 | 
 | ||||||
|     def test_polygon1(self): | def test_line2_pen(): | ||||||
|         self.helper_polygon(POINTS1) |     helper_line(POINTS2) | ||||||
| 
 | 
 | ||||||
|     def test_polygon2(self): |  | ||||||
|         self.helper_polygon(POINTS2) |  | ||||||
| 
 | 
 | ||||||
|     def helper_rectangle(self, bbox): | def test_line_pen_as_brush(): | ||||||
|         # Arrange |     # Arrange | ||||||
|         im = Image.new("RGB", (W, H)) |     im = Image.new("RGB", (W, H)) | ||||||
|         draw = ImageDraw2.Draw(im) |     draw = ImageDraw2.Draw(im) | ||||||
|         pen = ImageDraw2.Pen("green", width=2) |     pen = None | ||||||
|         brush = ImageDraw2.Brush("black") |     brush = ImageDraw2.Pen("yellow", width=2) | ||||||
| 
 | 
 | ||||||
|         # Act |     # Act | ||||||
|         draw.rectangle(bbox, pen, brush) |     # Pass in the pen as the brush parameter | ||||||
|  |     draw.line(POINTS1, pen, brush) | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Assert | ||||||
|         assert_image_equal(im, Image.open("Tests/images/imagedraw_rectangle.png")) |     assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png")) | ||||||
| 
 | 
 | ||||||
|     def test_rectangle1(self): |  | ||||||
|         self.helper_rectangle(BBOX1) |  | ||||||
| 
 | 
 | ||||||
|     def test_rectangle2(self): | def helper_polygon(points): | ||||||
|         self.helper_rectangle(BBOX2) |     # Arrange | ||||||
|  |     im = Image.new("RGB", (W, H)) | ||||||
|  |     draw = ImageDraw2.Draw(im) | ||||||
|  |     pen = ImageDraw2.Pen("blue", width=2) | ||||||
|  |     brush = ImageDraw2.Brush("red") | ||||||
| 
 | 
 | ||||||
|     def test_big_rectangle(self): |     # Act | ||||||
|         # Test drawing a rectangle bigger than the image |     draw.polygon(points, pen, brush) | ||||||
|         # Arrange |  | ||||||
|         im = Image.new("RGB", (W, H)) |  | ||||||
|         bbox = [(-1, -1), (W + 1, H + 1)] |  | ||||||
|         brush = ImageDraw2.Brush("orange") |  | ||||||
|         draw = ImageDraw2.Draw(im) |  | ||||||
|         expected = "Tests/images/imagedraw_big_rectangle.png" |  | ||||||
| 
 | 
 | ||||||
|         # Act |     # Assert | ||||||
|         draw.rectangle(bbox, brush) |     assert_image_equal(im, Image.open("Tests/images/imagedraw_polygon.png")) | ||||||
| 
 | 
 | ||||||
|         # Assert |  | ||||||
|         assert_image_similar(im, Image.open(expected), 1) |  | ||||||
| 
 | 
 | ||||||
|     @unittest.skipUnless(HAS_FREETYPE, "ImageFont not available") | def test_polygon1(): | ||||||
|     def test_text(self): |     helper_polygon(POINTS1) | ||||||
|         # Arrange |  | ||||||
|         im = Image.new("RGB", (W, H)) |  | ||||||
|         draw = ImageDraw2.Draw(im) |  | ||||||
|         font = ImageDraw2.Font("white", FONT_PATH) |  | ||||||
|         expected = "Tests/images/imagedraw2_text.png" |  | ||||||
| 
 | 
 | ||||||
|         # Act |  | ||||||
|         draw.text((5, 5), "ImageDraw2", font) |  | ||||||
| 
 | 
 | ||||||
|         # Assert | def test_polygon2(): | ||||||
|         assert_image_similar(im, Image.open(expected), 13) |     helper_polygon(POINTS2) | ||||||
| 
 | 
 | ||||||
|     @unittest.skipUnless(HAS_FREETYPE, "ImageFont not available") |  | ||||||
|     def test_textsize(self): |  | ||||||
|         # Arrange |  | ||||||
|         im = Image.new("RGB", (W, H)) |  | ||||||
|         draw = ImageDraw2.Draw(im) |  | ||||||
|         font = ImageDraw2.Font("white", FONT_PATH) |  | ||||||
| 
 | 
 | ||||||
|         # Act | def helper_rectangle(bbox): | ||||||
|         size = draw.textsize("ImageDraw2", font) |     # Arrange | ||||||
|  |     im = Image.new("RGB", (W, H)) | ||||||
|  |     draw = ImageDraw2.Draw(im) | ||||||
|  |     pen = ImageDraw2.Pen("green", width=2) | ||||||
|  |     brush = ImageDraw2.Brush("black") | ||||||
| 
 | 
 | ||||||
|         # Assert |     # Act | ||||||
|         self.assertEqual(size[1], 12) |     draw.rectangle(bbox, pen, brush) | ||||||
| 
 | 
 | ||||||
|     @unittest.skipUnless(HAS_FREETYPE, "ImageFont not available") |     # Assert | ||||||
|     def test_textsize_empty_string(self): |     assert_image_equal(im, Image.open("Tests/images/imagedraw_rectangle.png")) | ||||||
|         # Arrange |  | ||||||
|         im = Image.new("RGB", (W, H)) |  | ||||||
|         draw = ImageDraw2.Draw(im) |  | ||||||
|         font = ImageDraw2.Font("white", FONT_PATH) |  | ||||||
| 
 | 
 | ||||||
|         # Act |  | ||||||
|         # Should not cause 'SystemError: <built-in method getsize of |  | ||||||
|         # ImagingFont object at 0x...> returned NULL without setting an error' |  | ||||||
|         draw.textsize("", font) |  | ||||||
|         draw.textsize("\n", font) |  | ||||||
|         draw.textsize("test\n", font) |  | ||||||
| 
 | 
 | ||||||
|     @unittest.skipUnless(HAS_FREETYPE, "ImageFont not available") | def test_rectangle1(): | ||||||
|     def test_flush(self): |     helper_rectangle(BBOX1) | ||||||
|         # Arrange |  | ||||||
|         im = Image.new("RGB", (W, H)) |  | ||||||
|         draw = ImageDraw2.Draw(im) |  | ||||||
|         font = ImageDraw2.Font("white", FONT_PATH) |  | ||||||
| 
 | 
 | ||||||
|         # Act |  | ||||||
|         draw.text((5, 5), "ImageDraw2", font) |  | ||||||
|         im2 = draw.flush() |  | ||||||
| 
 | 
 | ||||||
|         # Assert | def test_rectangle2(): | ||||||
|         assert_image_equal(im, im2) |     helper_rectangle(BBOX2) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_big_rectangle(): | ||||||
|  |     # Test drawing a rectangle bigger than the image | ||||||
|  |     # Arrange | ||||||
|  |     im = Image.new("RGB", (W, H)) | ||||||
|  |     bbox = [(-1, -1), (W + 1, H + 1)] | ||||||
|  |     brush = ImageDraw2.Brush("orange") | ||||||
|  |     draw = ImageDraw2.Draw(im) | ||||||
|  |     expected = "Tests/images/imagedraw_big_rectangle.png" | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     draw.rectangle(bbox, brush) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert_image_similar(im, Image.open(expected), 1) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") | ||||||
|  | def test_text(): | ||||||
|  |     # Arrange | ||||||
|  |     im = Image.new("RGB", (W, H)) | ||||||
|  |     draw = ImageDraw2.Draw(im) | ||||||
|  |     font = ImageDraw2.Font("white", FONT_PATH) | ||||||
|  |     expected = "Tests/images/imagedraw2_text.png" | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     draw.text((5, 5), "ImageDraw2", font) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert_image_similar(im, Image.open(expected), 13) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") | ||||||
|  | def test_textsize(): | ||||||
|  |     # Arrange | ||||||
|  |     im = Image.new("RGB", (W, H)) | ||||||
|  |     draw = ImageDraw2.Draw(im) | ||||||
|  |     font = ImageDraw2.Font("white", FONT_PATH) | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     size = draw.textsize("ImageDraw2", font) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert size[1] == 12 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") | ||||||
|  | def test_textsize_empty_string(): | ||||||
|  |     # Arrange | ||||||
|  |     im = Image.new("RGB", (W, H)) | ||||||
|  |     draw = ImageDraw2.Draw(im) | ||||||
|  |     font = ImageDraw2.Font("white", FONT_PATH) | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     # Should not cause 'SystemError: <built-in method getsize of | ||||||
|  |     # ImagingFont object at 0x...> returned NULL without setting an error' | ||||||
|  |     draw.textsize("", font) | ||||||
|  |     draw.textsize("\n", font) | ||||||
|  |     draw.textsize("test\n", font) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") | ||||||
|  | def test_flush(): | ||||||
|  |     # Arrange | ||||||
|  |     im = Image.new("RGB", (W, H)) | ||||||
|  |     draw = ImageDraw2.Draw(im) | ||||||
|  |     font = ImageDraw2.Font("white", FONT_PATH) | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     draw.text((5, 5), "ImageDraw2", font) | ||||||
|  |     im2 = draw.flush() | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert_image_equal(im, im2) | ||||||
|  |  | ||||||
|  | @ -1,54 +1,55 @@ | ||||||
| from PIL import Image, ImageEnhance | from PIL import Image, ImageEnhance | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, hopper | from .helper import assert_image_equal, hopper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageEnhance(PillowTestCase): | def test_sanity(): | ||||||
|     def test_sanity(self): |     # FIXME: assert_image | ||||||
|  |     # Implicit asserts no exception: | ||||||
|  |     ImageEnhance.Color(hopper()).enhance(0.5) | ||||||
|  |     ImageEnhance.Contrast(hopper()).enhance(0.5) | ||||||
|  |     ImageEnhance.Brightness(hopper()).enhance(0.5) | ||||||
|  |     ImageEnhance.Sharpness(hopper()).enhance(0.5) | ||||||
| 
 | 
 | ||||||
|         # FIXME: assert_image |  | ||||||
|         # Implicit asserts no exception: |  | ||||||
|         ImageEnhance.Color(hopper()).enhance(0.5) |  | ||||||
|         ImageEnhance.Contrast(hopper()).enhance(0.5) |  | ||||||
|         ImageEnhance.Brightness(hopper()).enhance(0.5) |  | ||||||
|         ImageEnhance.Sharpness(hopper()).enhance(0.5) |  | ||||||
| 
 | 
 | ||||||
|     def test_crash(self): | def test_crash(): | ||||||
|  |     # crashes on small images | ||||||
|  |     im = Image.new("RGB", (1, 1)) | ||||||
|  |     ImageEnhance.Sharpness(im).enhance(0.5) | ||||||
| 
 | 
 | ||||||
|         # crashes on small images |  | ||||||
|         im = Image.new("RGB", (1, 1)) |  | ||||||
|         ImageEnhance.Sharpness(im).enhance(0.5) |  | ||||||
| 
 | 
 | ||||||
|     def _half_transparent_image(self): | def _half_transparent_image(): | ||||||
|         # returns an image, half transparent, half solid |     # returns an image, half transparent, half solid | ||||||
|         im = hopper("RGB") |     im = hopper("RGB") | ||||||
| 
 | 
 | ||||||
|         transparent = Image.new("L", im.size, 0) |     transparent = Image.new("L", im.size, 0) | ||||||
|         solid = Image.new("L", (im.size[0] // 2, im.size[1]), 255) |     solid = Image.new("L", (im.size[0] // 2, im.size[1]), 255) | ||||||
|         transparent.paste(solid, (0, 0)) |     transparent.paste(solid, (0, 0)) | ||||||
|         im.putalpha(transparent) |     im.putalpha(transparent) | ||||||
| 
 | 
 | ||||||
|         return im |     return im | ||||||
| 
 | 
 | ||||||
|     def _check_alpha(self, im, original, op, amount): |  | ||||||
|         self.assertEqual(im.getbands(), original.getbands()) |  | ||||||
|         assert_image_equal( |  | ||||||
|             im.getchannel("A"), |  | ||||||
|             original.getchannel("A"), |  | ||||||
|             "Diff on {}: {}".format(op, amount), |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def test_alpha(self): | def _check_alpha(im, original, op, amount): | ||||||
|         # Issue https://github.com/python-pillow/Pillow/issues/899 |     assert im.getbands() == original.getbands() | ||||||
|         # Is alpha preserved through image enhancement? |     assert_image_equal( | ||||||
|  |         im.getchannel("A"), | ||||||
|  |         original.getchannel("A"), | ||||||
|  |         "Diff on {}: {}".format(op, amount), | ||||||
|  |     ) | ||||||
| 
 | 
 | ||||||
|         original = self._half_transparent_image() |  | ||||||
| 
 | 
 | ||||||
|         for op in ["Color", "Brightness", "Contrast", "Sharpness"]: | def test_alpha(): | ||||||
|             for amount in [0, 0.5, 1.0]: |     # Issue https://github.com/python-pillow/Pillow/issues/899 | ||||||
|                 self._check_alpha( |     # Is alpha preserved through image enhancement? | ||||||
|                     getattr(ImageEnhance, op)(original).enhance(amount), | 
 | ||||||
|                     original, |     original = _half_transparent_image() | ||||||
|                     op, | 
 | ||||||
|                     amount, |     for op in ["Color", "Brightness", "Contrast", "Sharpness"]: | ||||||
|                 ) |         for amount in [0, 0.5, 1.0]: | ||||||
|  |             _check_alpha( | ||||||
|  |                 getattr(ImageEnhance, op)(original).enhance(amount), | ||||||
|  |                 original, | ||||||
|  |                 op, | ||||||
|  |                 amount, | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
|  | import pytest | ||||||
| from PIL import Image, ImageOps | from PIL import Image, ImageOps | ||||||
| 
 | 
 | ||||||
| from .helper import ( | from .helper import ( | ||||||
|     PillowTestCase, |  | ||||||
|     assert_image_equal, |     assert_image_equal, | ||||||
|     assert_image_similar, |     assert_image_similar, | ||||||
|     assert_tuple_approx_equal, |     assert_tuple_approx_equal, | ||||||
|  | @ -16,287 +16,294 @@ except ImportError: | ||||||
|     HAVE_WEBP = False |     HAVE_WEBP = False | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestImageOps(PillowTestCase): | class Deformer: | ||||||
|     class Deformer: |     def getmesh(self, im): | ||||||
|         def getmesh(self, im): |         x, y = im.size | ||||||
|             x, y = im.size |         return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))] | ||||||
|             return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))] |  | ||||||
| 
 | 
 | ||||||
|     deformer = Deformer() |  | ||||||
| 
 | 
 | ||||||
|     def test_sanity(self): | deformer = Deformer() | ||||||
| 
 | 
 | ||||||
|         ImageOps.autocontrast(hopper("L")) |  | ||||||
|         ImageOps.autocontrast(hopper("RGB")) |  | ||||||
| 
 | 
 | ||||||
|         ImageOps.autocontrast(hopper("L"), cutoff=10) | def test_sanity(): | ||||||
|         ImageOps.autocontrast(hopper("L"), ignore=[0, 255]) |  | ||||||
| 
 | 
 | ||||||
|         ImageOps.colorize(hopper("L"), (0, 0, 0), (255, 255, 255)) |     ImageOps.autocontrast(hopper("L")) | ||||||
|         ImageOps.colorize(hopper("L"), "black", "white") |     ImageOps.autocontrast(hopper("RGB")) | ||||||
| 
 | 
 | ||||||
|         ImageOps.pad(hopper("L"), (128, 128)) |     ImageOps.autocontrast(hopper("L"), cutoff=10) | ||||||
|         ImageOps.pad(hopper("RGB"), (128, 128)) |     ImageOps.autocontrast(hopper("L"), ignore=[0, 255]) | ||||||
| 
 | 
 | ||||||
|         ImageOps.crop(hopper("L"), 1) |     ImageOps.colorize(hopper("L"), (0, 0, 0), (255, 255, 255)) | ||||||
|         ImageOps.crop(hopper("RGB"), 1) |     ImageOps.colorize(hopper("L"), "black", "white") | ||||||
| 
 | 
 | ||||||
|         ImageOps.deform(hopper("L"), self.deformer) |     ImageOps.pad(hopper("L"), (128, 128)) | ||||||
|         ImageOps.deform(hopper("RGB"), self.deformer) |     ImageOps.pad(hopper("RGB"), (128, 128)) | ||||||
| 
 | 
 | ||||||
|         ImageOps.equalize(hopper("L")) |     ImageOps.crop(hopper("L"), 1) | ||||||
|         ImageOps.equalize(hopper("RGB")) |     ImageOps.crop(hopper("RGB"), 1) | ||||||
| 
 | 
 | ||||||
|         ImageOps.expand(hopper("L"), 1) |     ImageOps.deform(hopper("L"), deformer) | ||||||
|         ImageOps.expand(hopper("RGB"), 1) |     ImageOps.deform(hopper("RGB"), deformer) | ||||||
|         ImageOps.expand(hopper("L"), 2, "blue") |  | ||||||
|         ImageOps.expand(hopper("RGB"), 2, "blue") |  | ||||||
| 
 | 
 | ||||||
|         ImageOps.fit(hopper("L"), (128, 128)) |     ImageOps.equalize(hopper("L")) | ||||||
|         ImageOps.fit(hopper("RGB"), (128, 128)) |     ImageOps.equalize(hopper("RGB")) | ||||||
| 
 | 
 | ||||||
|         ImageOps.flip(hopper("L")) |     ImageOps.expand(hopper("L"), 1) | ||||||
|         ImageOps.flip(hopper("RGB")) |     ImageOps.expand(hopper("RGB"), 1) | ||||||
|  |     ImageOps.expand(hopper("L"), 2, "blue") | ||||||
|  |     ImageOps.expand(hopper("RGB"), 2, "blue") | ||||||
| 
 | 
 | ||||||
|         ImageOps.grayscale(hopper("L")) |     ImageOps.fit(hopper("L"), (128, 128)) | ||||||
|         ImageOps.grayscale(hopper("RGB")) |     ImageOps.fit(hopper("RGB"), (128, 128)) | ||||||
| 
 | 
 | ||||||
|         ImageOps.invert(hopper("L")) |     ImageOps.flip(hopper("L")) | ||||||
|         ImageOps.invert(hopper("RGB")) |     ImageOps.flip(hopper("RGB")) | ||||||
| 
 | 
 | ||||||
|         ImageOps.mirror(hopper("L")) |     ImageOps.grayscale(hopper("L")) | ||||||
|         ImageOps.mirror(hopper("RGB")) |     ImageOps.grayscale(hopper("RGB")) | ||||||
| 
 | 
 | ||||||
|         ImageOps.posterize(hopper("L"), 4) |     ImageOps.invert(hopper("L")) | ||||||
|         ImageOps.posterize(hopper("RGB"), 4) |     ImageOps.invert(hopper("RGB")) | ||||||
| 
 | 
 | ||||||
|         ImageOps.solarize(hopper("L")) |     ImageOps.mirror(hopper("L")) | ||||||
|         ImageOps.solarize(hopper("RGB")) |     ImageOps.mirror(hopper("RGB")) | ||||||
| 
 | 
 | ||||||
|         ImageOps.exif_transpose(hopper("L")) |     ImageOps.posterize(hopper("L"), 4) | ||||||
|         ImageOps.exif_transpose(hopper("RGB")) |     ImageOps.posterize(hopper("RGB"), 4) | ||||||
| 
 | 
 | ||||||
|     def test_1pxfit(self): |     ImageOps.solarize(hopper("L")) | ||||||
|         # Division by zero in equalize if image is 1 pixel high |     ImageOps.solarize(hopper("RGB")) | ||||||
|         newimg = ImageOps.fit(hopper("RGB").resize((1, 1)), (35, 35)) |  | ||||||
|         self.assertEqual(newimg.size, (35, 35)) |  | ||||||
| 
 | 
 | ||||||
|         newimg = ImageOps.fit(hopper("RGB").resize((1, 100)), (35, 35)) |     ImageOps.exif_transpose(hopper("L")) | ||||||
|         self.assertEqual(newimg.size, (35, 35)) |     ImageOps.exif_transpose(hopper("RGB")) | ||||||
| 
 | 
 | ||||||
|         newimg = ImageOps.fit(hopper("RGB").resize((100, 1)), (35, 35)) |  | ||||||
|         self.assertEqual(newimg.size, (35, 35)) |  | ||||||
| 
 | 
 | ||||||
|     def test_fit_same_ratio(self): | def test_1pxfit(): | ||||||
|         # The ratio for this image is 1000.0 / 755 = 1.3245033112582782 |     # Division by zero in equalize if image is 1 pixel high | ||||||
|         # If the ratios are not acknowledged to be the same, |     newimg = ImageOps.fit(hopper("RGB").resize((1, 1)), (35, 35)) | ||||||
|         # and Pillow attempts to adjust the width to |     assert newimg.size == (35, 35) | ||||||
|         # 1.3245033112582782 * 755 = 1000.0000000000001 |  | ||||||
|         # then centering this greater width causes a negative x offset when cropping |  | ||||||
|         with Image.new("RGB", (1000, 755)) as im: |  | ||||||
|             new_im = ImageOps.fit(im, (1000, 755)) |  | ||||||
|             self.assertEqual(new_im.size, (1000, 755)) |  | ||||||
| 
 | 
 | ||||||
|     def test_pad(self): |     newimg = ImageOps.fit(hopper("RGB").resize((1, 100)), (35, 35)) | ||||||
|         # Same ratio |     assert newimg.size == (35, 35) | ||||||
|         im = hopper() |  | ||||||
|         new_size = (im.width * 2, im.height * 2) |  | ||||||
|         new_im = ImageOps.pad(im, new_size) |  | ||||||
|         self.assertEqual(new_im.size, new_size) |  | ||||||
| 
 | 
 | ||||||
|         for label, color, new_size in [ |     newimg = ImageOps.fit(hopper("RGB").resize((100, 1)), (35, 35)) | ||||||
|             ("h", None, (im.width * 4, im.height * 2)), |     assert newimg.size == (35, 35) | ||||||
|             ("v", "#f00", (im.width * 2, im.height * 4)), |  | ||||||
|         ]: |  | ||||||
|             for i, centering in enumerate([(0, 0), (0.5, 0.5), (1, 1)]): |  | ||||||
|                 new_im = ImageOps.pad(im, new_size, color=color, centering=centering) |  | ||||||
|                 self.assertEqual(new_im.size, new_size) |  | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | def test_fit_same_ratio(): | ||||||
|  |     # The ratio for this image is 1000.0 / 755 = 1.3245033112582782 | ||||||
|  |     # If the ratios are not acknowledged to be the same, | ||||||
|  |     # and Pillow attempts to adjust the width to | ||||||
|  |     # 1.3245033112582782 * 755 = 1000.0000000000001 | ||||||
|  |     # then centering this greater width causes a negative x offset when cropping | ||||||
|  |     with Image.new("RGB", (1000, 755)) as im: | ||||||
|  |         new_im = ImageOps.fit(im, (1000, 755)) | ||||||
|  |         assert new_im.size == (1000, 755) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_pad(): | ||||||
|  |     # Same ratio | ||||||
|  |     im = hopper() | ||||||
|  |     new_size = (im.width * 2, im.height * 2) | ||||||
|  |     new_im = ImageOps.pad(im, new_size) | ||||||
|  |     assert new_im.size == new_size | ||||||
|  | 
 | ||||||
|  |     for label, color, new_size in [ | ||||||
|  |         ("h", None, (im.width * 4, im.height * 2)), | ||||||
|  |         ("v", "#f00", (im.width * 2, im.height * 4)), | ||||||
|  |     ]: | ||||||
|  |         for i, centering in enumerate([(0, 0), (0.5, 0.5), (1, 1)]): | ||||||
|  |             new_im = ImageOps.pad(im, new_size, color=color, centering=centering) | ||||||
|  |             assert new_im.size == new_size | ||||||
|  | 
 | ||||||
|  |             with Image.open( | ||||||
|  |                 "Tests/images/imageops_pad_" + label + "_" + str(i) + ".jpg" | ||||||
|  |             ) as target: | ||||||
|  |                 assert_image_similar(new_im, target, 6) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_pil163(): | ||||||
|  |     # Division by zero in equalize if < 255 pixels in image (@PIL163) | ||||||
|  | 
 | ||||||
|  |     i = hopper("RGB").resize((15, 16)) | ||||||
|  | 
 | ||||||
|  |     ImageOps.equalize(i.convert("L")) | ||||||
|  |     ImageOps.equalize(i.convert("P")) | ||||||
|  |     ImageOps.equalize(i.convert("RGB")) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_scale(): | ||||||
|  |     # Test the scaling function | ||||||
|  |     i = hopper("L").resize((50, 50)) | ||||||
|  | 
 | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         ImageOps.scale(i, -1) | ||||||
|  | 
 | ||||||
|  |     newimg = ImageOps.scale(i, 1) | ||||||
|  |     assert newimg.size == (50, 50) | ||||||
|  | 
 | ||||||
|  |     newimg = ImageOps.scale(i, 2) | ||||||
|  |     assert newimg.size == (100, 100) | ||||||
|  | 
 | ||||||
|  |     newimg = ImageOps.scale(i, 0.5) | ||||||
|  |     assert newimg.size == (25, 25) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_colorize_2color(): | ||||||
|  |     # Test the colorizing function with 2-color functionality | ||||||
|  | 
 | ||||||
|  |     # Open test image (256px by 10px, black to white) | ||||||
|  |     with Image.open("Tests/images/bw_gradient.png") as im: | ||||||
|  |         im = im.convert("L") | ||||||
|  | 
 | ||||||
|  |     # Create image with original 2-color functionality | ||||||
|  |     im_test = ImageOps.colorize(im, "red", "green") | ||||||
|  | 
 | ||||||
|  |     # Test output image (2-color) | ||||||
|  |     left = (0, 1) | ||||||
|  |     middle = (127, 1) | ||||||
|  |     right = (255, 1) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(left), | ||||||
|  |         (255, 0, 0), | ||||||
|  |         threshold=1, | ||||||
|  |         msg="black test pixel incorrect", | ||||||
|  |     ) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(middle), | ||||||
|  |         (127, 63, 0), | ||||||
|  |         threshold=1, | ||||||
|  |         msg="mid test pixel incorrect", | ||||||
|  |     ) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(right), | ||||||
|  |         (0, 127, 0), | ||||||
|  |         threshold=1, | ||||||
|  |         msg="white test pixel incorrect", | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_colorize_2color_offset(): | ||||||
|  |     # Test the colorizing function with 2-color functionality and offset | ||||||
|  | 
 | ||||||
|  |     # Open test image (256px by 10px, black to white) | ||||||
|  |     with Image.open("Tests/images/bw_gradient.png") as im: | ||||||
|  |         im = im.convert("L") | ||||||
|  | 
 | ||||||
|  |     # Create image with original 2-color functionality with offsets | ||||||
|  |     im_test = ImageOps.colorize( | ||||||
|  |         im, black="red", white="green", blackpoint=50, whitepoint=100 | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     # Test output image (2-color) with offsets | ||||||
|  |     left = (25, 1) | ||||||
|  |     middle = (75, 1) | ||||||
|  |     right = (125, 1) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(left), | ||||||
|  |         (255, 0, 0), | ||||||
|  |         threshold=1, | ||||||
|  |         msg="black test pixel incorrect", | ||||||
|  |     ) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(middle), | ||||||
|  |         (127, 63, 0), | ||||||
|  |         threshold=1, | ||||||
|  |         msg="mid test pixel incorrect", | ||||||
|  |     ) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(right), | ||||||
|  |         (0, 127, 0), | ||||||
|  |         threshold=1, | ||||||
|  |         msg="white test pixel incorrect", | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_colorize_3color_offset(): | ||||||
|  |     # Test the colorizing function with 3-color functionality and offset | ||||||
|  | 
 | ||||||
|  |     # Open test image (256px by 10px, black to white) | ||||||
|  |     with Image.open("Tests/images/bw_gradient.png") as im: | ||||||
|  |         im = im.convert("L") | ||||||
|  | 
 | ||||||
|  |     # Create image with new three color functionality with offsets | ||||||
|  |     im_test = ImageOps.colorize( | ||||||
|  |         im, | ||||||
|  |         black="red", | ||||||
|  |         white="green", | ||||||
|  |         mid="blue", | ||||||
|  |         blackpoint=50, | ||||||
|  |         whitepoint=200, | ||||||
|  |         midpoint=100, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     # Test output image (3-color) with offsets | ||||||
|  |     left = (25, 1) | ||||||
|  |     left_middle = (75, 1) | ||||||
|  |     middle = (100, 1) | ||||||
|  |     right_middle = (150, 1) | ||||||
|  |     right = (225, 1) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(left), | ||||||
|  |         (255, 0, 0), | ||||||
|  |         threshold=1, | ||||||
|  |         msg="black test pixel incorrect", | ||||||
|  |     ) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(left_middle), | ||||||
|  |         (127, 0, 127), | ||||||
|  |         threshold=1, | ||||||
|  |         msg="low-mid test pixel incorrect", | ||||||
|  |     ) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(middle), (0, 0, 255), threshold=1, msg="mid incorrect" | ||||||
|  |     ) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(right_middle), | ||||||
|  |         (0, 63, 127), | ||||||
|  |         threshold=1, | ||||||
|  |         msg="high-mid test pixel incorrect", | ||||||
|  |     ) | ||||||
|  |     assert_tuple_approx_equal( | ||||||
|  |         im_test.getpixel(right), | ||||||
|  |         (0, 127, 0), | ||||||
|  |         threshold=1, | ||||||
|  |         msg="white test pixel incorrect", | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_exif_transpose(): | ||||||
|  |     exts = [".jpg"] | ||||||
|  |     if HAVE_WEBP and _webp.HAVE_WEBPANIM: | ||||||
|  |         exts.append(".webp") | ||||||
|  |     for ext in exts: | ||||||
|  |         with Image.open("Tests/images/hopper" + ext) as base_im: | ||||||
|  | 
 | ||||||
|  |             def check(orientation_im): | ||||||
|  |                 for im in [ | ||||||
|  |                     orientation_im, | ||||||
|  |                     orientation_im.copy(), | ||||||
|  |                 ]:  # ImageFile  # Image | ||||||
|  |                     if orientation_im is base_im: | ||||||
|  |                         assert "exif" not in im.info | ||||||
|  |                     else: | ||||||
|  |                         original_exif = im.info["exif"] | ||||||
|  |                     transposed_im = ImageOps.exif_transpose(im) | ||||||
|  |                     assert_image_similar(base_im, transposed_im, 17) | ||||||
|  |                     if orientation_im is base_im: | ||||||
|  |                         assert "exif" not in im.info | ||||||
|  |                     else: | ||||||
|  |                         assert transposed_im.info["exif"] != original_exif | ||||||
|  | 
 | ||||||
|  |                         assert 0x0112 not in transposed_im.getexif() | ||||||
|  | 
 | ||||||
|  |                     # Repeat the operation to test that it does not keep transposing | ||||||
|  |                     transposed_im2 = ImageOps.exif_transpose(transposed_im) | ||||||
|  |                     assert_image_equal(transposed_im2, transposed_im) | ||||||
|  | 
 | ||||||
|  |             check(base_im) | ||||||
|  |             for i in range(2, 9): | ||||||
|                 with Image.open( |                 with Image.open( | ||||||
|                     "Tests/images/imageops_pad_" + label + "_" + str(i) + ".jpg" |                     "Tests/images/hopper_orientation_" + str(i) + ext | ||||||
|                 ) as target: |                 ) as orientation_im: | ||||||
|                     assert_image_similar(new_im, target, 6) |                     check(orientation_im) | ||||||
| 
 |  | ||||||
|     def test_pil163(self): |  | ||||||
|         # Division by zero in equalize if < 255 pixels in image (@PIL163) |  | ||||||
| 
 |  | ||||||
|         i = hopper("RGB").resize((15, 16)) |  | ||||||
| 
 |  | ||||||
|         ImageOps.equalize(i.convert("L")) |  | ||||||
|         ImageOps.equalize(i.convert("P")) |  | ||||||
|         ImageOps.equalize(i.convert("RGB")) |  | ||||||
| 
 |  | ||||||
|     def test_scale(self): |  | ||||||
|         # Test the scaling function |  | ||||||
|         i = hopper("L").resize((50, 50)) |  | ||||||
| 
 |  | ||||||
|         with self.assertRaises(ValueError): |  | ||||||
|             ImageOps.scale(i, -1) |  | ||||||
| 
 |  | ||||||
|         newimg = ImageOps.scale(i, 1) |  | ||||||
|         self.assertEqual(newimg.size, (50, 50)) |  | ||||||
| 
 |  | ||||||
|         newimg = ImageOps.scale(i, 2) |  | ||||||
|         self.assertEqual(newimg.size, (100, 100)) |  | ||||||
| 
 |  | ||||||
|         newimg = ImageOps.scale(i, 0.5) |  | ||||||
|         self.assertEqual(newimg.size, (25, 25)) |  | ||||||
| 
 |  | ||||||
|     def test_colorize_2color(self): |  | ||||||
|         # Test the colorizing function with 2-color functionality |  | ||||||
| 
 |  | ||||||
|         # Open test image (256px by 10px, black to white) |  | ||||||
|         with Image.open("Tests/images/bw_gradient.png") as im: |  | ||||||
|             im = im.convert("L") |  | ||||||
| 
 |  | ||||||
|         # Create image with original 2-color functionality |  | ||||||
|         im_test = ImageOps.colorize(im, "red", "green") |  | ||||||
| 
 |  | ||||||
|         # Test output image (2-color) |  | ||||||
|         left = (0, 1) |  | ||||||
|         middle = (127, 1) |  | ||||||
|         right = (255, 1) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(left), |  | ||||||
|             (255, 0, 0), |  | ||||||
|             threshold=1, |  | ||||||
|             msg="black test pixel incorrect", |  | ||||||
|         ) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(middle), |  | ||||||
|             (127, 63, 0), |  | ||||||
|             threshold=1, |  | ||||||
|             msg="mid test pixel incorrect", |  | ||||||
|         ) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(right), |  | ||||||
|             (0, 127, 0), |  | ||||||
|             threshold=1, |  | ||||||
|             msg="white test pixel incorrect", |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     def test_colorize_2color_offset(self): |  | ||||||
|         # Test the colorizing function with 2-color functionality and offset |  | ||||||
| 
 |  | ||||||
|         # Open test image (256px by 10px, black to white) |  | ||||||
|         with Image.open("Tests/images/bw_gradient.png") as im: |  | ||||||
|             im = im.convert("L") |  | ||||||
| 
 |  | ||||||
|         # Create image with original 2-color functionality with offsets |  | ||||||
|         im_test = ImageOps.colorize( |  | ||||||
|             im, black="red", white="green", blackpoint=50, whitepoint=100 |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|         # Test output image (2-color) with offsets |  | ||||||
|         left = (25, 1) |  | ||||||
|         middle = (75, 1) |  | ||||||
|         right = (125, 1) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(left), |  | ||||||
|             (255, 0, 0), |  | ||||||
|             threshold=1, |  | ||||||
|             msg="black test pixel incorrect", |  | ||||||
|         ) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(middle), |  | ||||||
|             (127, 63, 0), |  | ||||||
|             threshold=1, |  | ||||||
|             msg="mid test pixel incorrect", |  | ||||||
|         ) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(right), |  | ||||||
|             (0, 127, 0), |  | ||||||
|             threshold=1, |  | ||||||
|             msg="white test pixel incorrect", |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     def test_colorize_3color_offset(self): |  | ||||||
|         # Test the colorizing function with 3-color functionality and offset |  | ||||||
| 
 |  | ||||||
|         # Open test image (256px by 10px, black to white) |  | ||||||
|         with Image.open("Tests/images/bw_gradient.png") as im: |  | ||||||
|             im = im.convert("L") |  | ||||||
| 
 |  | ||||||
|         # Create image with new three color functionality with offsets |  | ||||||
|         im_test = ImageOps.colorize( |  | ||||||
|             im, |  | ||||||
|             black="red", |  | ||||||
|             white="green", |  | ||||||
|             mid="blue", |  | ||||||
|             blackpoint=50, |  | ||||||
|             whitepoint=200, |  | ||||||
|             midpoint=100, |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|         # Test output image (3-color) with offsets |  | ||||||
|         left = (25, 1) |  | ||||||
|         left_middle = (75, 1) |  | ||||||
|         middle = (100, 1) |  | ||||||
|         right_middle = (150, 1) |  | ||||||
|         right = (225, 1) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(left), |  | ||||||
|             (255, 0, 0), |  | ||||||
|             threshold=1, |  | ||||||
|             msg="black test pixel incorrect", |  | ||||||
|         ) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(left_middle), |  | ||||||
|             (127, 0, 127), |  | ||||||
|             threshold=1, |  | ||||||
|             msg="low-mid test pixel incorrect", |  | ||||||
|         ) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(middle), (0, 0, 255), threshold=1, msg="mid incorrect" |  | ||||||
|         ) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(right_middle), |  | ||||||
|             (0, 63, 127), |  | ||||||
|             threshold=1, |  | ||||||
|             msg="high-mid test pixel incorrect", |  | ||||||
|         ) |  | ||||||
|         assert_tuple_approx_equal( |  | ||||||
|             im_test.getpixel(right), |  | ||||||
|             (0, 127, 0), |  | ||||||
|             threshold=1, |  | ||||||
|             msg="white test pixel incorrect", |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     def test_exif_transpose(self): |  | ||||||
|         exts = [".jpg"] |  | ||||||
|         if HAVE_WEBP and _webp.HAVE_WEBPANIM: |  | ||||||
|             exts.append(".webp") |  | ||||||
|         for ext in exts: |  | ||||||
|             with Image.open("Tests/images/hopper" + ext) as base_im: |  | ||||||
| 
 |  | ||||||
|                 def check(orientation_im): |  | ||||||
|                     for im in [ |  | ||||||
|                         orientation_im, |  | ||||||
|                         orientation_im.copy(), |  | ||||||
|                     ]:  # ImageFile  # Image |  | ||||||
|                         if orientation_im is base_im: |  | ||||||
|                             self.assertNotIn("exif", im.info) |  | ||||||
|                         else: |  | ||||||
|                             original_exif = im.info["exif"] |  | ||||||
|                         transposed_im = ImageOps.exif_transpose(im) |  | ||||||
|                         assert_image_similar(base_im, transposed_im, 17) |  | ||||||
|                         if orientation_im is base_im: |  | ||||||
|                             self.assertNotIn("exif", im.info) |  | ||||||
|                         else: |  | ||||||
|                             self.assertNotEqual( |  | ||||||
|                                 transposed_im.info["exif"], original_exif |  | ||||||
|                             ) |  | ||||||
| 
 |  | ||||||
|                             self.assertNotIn(0x0112, transposed_im.getexif()) |  | ||||||
| 
 |  | ||||||
|                         # Repeat the operation |  | ||||||
|                         # to test that it does not keep transposing |  | ||||||
|                         transposed_im2 = ImageOps.exif_transpose(transposed_im) |  | ||||||
|                         assert_image_equal(transposed_im2, transposed_im) |  | ||||||
| 
 |  | ||||||
|                 check(base_im) |  | ||||||
|                 for i in range(2, 9): |  | ||||||
|                     with Image.open( |  | ||||||
|                         "Tests/images/hopper_orientation_" + str(i) + ext |  | ||||||
|                     ) as orientation_im: |  | ||||||
|                         check(orientation_im) |  | ||||||
|  |  | ||||||
|  | @ -1,8 +1,7 @@ | ||||||
| import unittest | import pytest | ||||||
| 
 |  | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_image_equal, hopper | from .helper import assert_image_equal, hopper | ||||||
| 
 | 
 | ||||||
| try: | try: | ||||||
|     from PIL import ImageTk |     from PIL import ImageTk | ||||||
|  | @ -12,76 +11,81 @@ try: | ||||||
|     dir(ImageTk) |     dir(ImageTk) | ||||||
|     HAS_TK = True |     HAS_TK = True | ||||||
| except (OSError, ImportError): | except (OSError, ImportError): | ||||||
|     # Skipped via setUp() |     # Skipped via pytestmark | ||||||
|     HAS_TK = False |     HAS_TK = False | ||||||
| 
 | 
 | ||||||
| TK_MODES = ("1", "L", "P", "RGB", "RGBA") | TK_MODES = ("1", "L", "P", "RGB", "RGBA") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @unittest.skipUnless(HAS_TK, "Tk not installed") | pytestmark = pytest.mark.skipif(not HAS_TK, reason="Tk not installed") | ||||||
| class TestImageTk(PillowTestCase): |  | ||||||
|     def setUp(self): |  | ||||||
|         try: |  | ||||||
|             # setup tk |  | ||||||
|             tk.Frame() |  | ||||||
|             # root = tk.Tk() |  | ||||||
|         except tk.TclError as v: |  | ||||||
|             self.skipTest("TCL Error: %s" % v) |  | ||||||
| 
 | 
 | ||||||
|     def test_kw(self): |  | ||||||
|         TEST_JPG = "Tests/images/hopper.jpg" |  | ||||||
|         TEST_PNG = "Tests/images/hopper.png" |  | ||||||
|         with Image.open(TEST_JPG) as im1: |  | ||||||
|             with Image.open(TEST_PNG) as im2: |  | ||||||
|                 with open(TEST_PNG, "rb") as fp: |  | ||||||
|                     data = fp.read() |  | ||||||
|                 kw = {"file": TEST_JPG, "data": data} |  | ||||||
| 
 | 
 | ||||||
|                 # Test "file" | def setup_module(): | ||||||
|                 im = ImageTk._get_image_from_kw(kw) |     try: | ||||||
|                 assert_image_equal(im, im1) |         # setup tk | ||||||
|  |         tk.Frame() | ||||||
|  |         # root = tk.Tk() | ||||||
|  |     except tk.TclError as v: | ||||||
|  |         pytest.skip("TCL Error: %s" % v) | ||||||
| 
 | 
 | ||||||
|                 # Test "data" |  | ||||||
|                 im = ImageTk._get_image_from_kw(kw) |  | ||||||
|                 assert_image_equal(im, im2) |  | ||||||
| 
 | 
 | ||||||
|         # Test no relevant entry | def test_kw(): | ||||||
|         im = ImageTk._get_image_from_kw(kw) |     TEST_JPG = "Tests/images/hopper.jpg" | ||||||
|         self.assertIsNone(im) |     TEST_PNG = "Tests/images/hopper.png" | ||||||
|  |     with Image.open(TEST_JPG) as im1: | ||||||
|  |         with Image.open(TEST_PNG) as im2: | ||||||
|  |             with open(TEST_PNG, "rb") as fp: | ||||||
|  |                 data = fp.read() | ||||||
|  |             kw = {"file": TEST_JPG, "data": data} | ||||||
| 
 | 
 | ||||||
|     def test_photoimage(self): |             # Test "file" | ||||||
|         for mode in TK_MODES: |             im = ImageTk._get_image_from_kw(kw) | ||||||
|             # test as image: |             assert_image_equal(im, im1) | ||||||
|             im = hopper(mode) |  | ||||||
| 
 | 
 | ||||||
|             # this should not crash |             # Test "data" | ||||||
|             im_tk = ImageTk.PhotoImage(im) |             im = ImageTk._get_image_from_kw(kw) | ||||||
|  |             assert_image_equal(im, im2) | ||||||
| 
 | 
 | ||||||
|             self.assertEqual(im_tk.width(), im.width) |     # Test no relevant entry | ||||||
|             self.assertEqual(im_tk.height(), im.height) |     im = ImageTk._get_image_from_kw(kw) | ||||||
|  |     assert im is None | ||||||
| 
 | 
 | ||||||
|             reloaded = ImageTk.getimage(im_tk) |  | ||||||
|             assert_image_equal(reloaded, im.convert("RGBA")) |  | ||||||
| 
 | 
 | ||||||
|     def test_photoimage_blank(self): | def test_photoimage(): | ||||||
|         # test a image using mode/size: |     for mode in TK_MODES: | ||||||
|         for mode in TK_MODES: |         # test as image: | ||||||
|             im_tk = ImageTk.PhotoImage(mode, (100, 100)) |         im = hopper(mode) | ||||||
| 
 |  | ||||||
|             self.assertEqual(im_tk.width(), 100) |  | ||||||
|             self.assertEqual(im_tk.height(), 100) |  | ||||||
| 
 |  | ||||||
|             # reloaded = ImageTk.getimage(im_tk) |  | ||||||
|             # assert_image_equal(reloaded, im) |  | ||||||
| 
 |  | ||||||
|     def test_bitmapimage(self): |  | ||||||
|         im = hopper("1") |  | ||||||
| 
 | 
 | ||||||
|         # this should not crash |         # this should not crash | ||||||
|         im_tk = ImageTk.BitmapImage(im) |         im_tk = ImageTk.PhotoImage(im) | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(im_tk.width(), im.width) |         assert im_tk.width() == im.width | ||||||
|         self.assertEqual(im_tk.height(), im.height) |         assert im_tk.height() == im.height | ||||||
|  | 
 | ||||||
|  |         reloaded = ImageTk.getimage(im_tk) | ||||||
|  |         assert_image_equal(reloaded, im.convert("RGBA")) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_photoimage_blank(): | ||||||
|  |     # test a image using mode/size: | ||||||
|  |     for mode in TK_MODES: | ||||||
|  |         im_tk = ImageTk.PhotoImage(mode, (100, 100)) | ||||||
|  | 
 | ||||||
|  |         assert im_tk.width() == 100 | ||||||
|  |         assert im_tk.height() == 100 | ||||||
| 
 | 
 | ||||||
|         # reloaded = ImageTk.getimage(im_tk) |         # reloaded = ImageTk.getimage(im_tk) | ||||||
|         # assert_image_equal(reloaded, im) |         # assert_image_equal(reloaded, im) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_bitmapimage(): | ||||||
|  |     im = hopper("1") | ||||||
|  | 
 | ||||||
|  |     # this should not crash | ||||||
|  |     im_tk = ImageTk.BitmapImage(im) | ||||||
|  | 
 | ||||||
|  |     assert im_tk.width() == im.width | ||||||
|  |     assert im_tk.height() == im.height | ||||||
|  | 
 | ||||||
|  |     # reloaded = ImageTk.getimage(im_tk) | ||||||
|  |     # assert_image_equal(reloaded, im) | ||||||
|  |  | ||||||
|  | @ -1,38 +1,39 @@ | ||||||
| import sys | import sys | ||||||
| import unittest |  | ||||||
| 
 | 
 | ||||||
|  | import pytest | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, is_win32 | from .helper import is_win32 | ||||||
| 
 | 
 | ||||||
| try: | try: | ||||||
|     import numpy |     import numpy | ||||||
| except ImportError: | except ImportError: | ||||||
|     numpy = None |     numpy = None | ||||||
| 
 | 
 | ||||||
|  | pytestmark = pytest.mark.skipif(is_win32(), reason="Win32 does not call map_buffer") | ||||||
| 
 | 
 | ||||||
| @unittest.skipIf(is_win32(), "Win32 does not call map_buffer") |  | ||||||
| class TestMap(PillowTestCase): |  | ||||||
|     def test_overflow(self): |  | ||||||
|         # There is the potential to overflow comparisons in map.c |  | ||||||
|         # if there are > SIZE_MAX bytes in the image or if |  | ||||||
|         # the file encodes an offset that makes |  | ||||||
|         # (offset + size(bytes)) > SIZE_MAX |  | ||||||
| 
 | 
 | ||||||
|         # Note that this image triggers the decompression bomb warning: | def test_overflow(): | ||||||
|         max_pixels = Image.MAX_IMAGE_PIXELS |     # There is the potential to overflow comparisons in map.c | ||||||
|         Image.MAX_IMAGE_PIXELS = None |     # if there are > SIZE_MAX bytes in the image or if | ||||||
|  |     # the file encodes an offset that makes | ||||||
|  |     # (offset + size(bytes)) > SIZE_MAX | ||||||
| 
 | 
 | ||||||
|         # This image hits the offset test. |     # Note that this image triggers the decompression bomb warning: | ||||||
|         with Image.open("Tests/images/l2rgb_read.bmp") as im: |     max_pixels = Image.MAX_IMAGE_PIXELS | ||||||
|             with self.assertRaises((ValueError, MemoryError, IOError)): |     Image.MAX_IMAGE_PIXELS = None | ||||||
|                 im.load() |  | ||||||
| 
 | 
 | ||||||
|         Image.MAX_IMAGE_PIXELS = max_pixels |     # This image hits the offset test. | ||||||
|  |     with Image.open("Tests/images/l2rgb_read.bmp") as im: | ||||||
|  |         with pytest.raises((ValueError, MemoryError, IOError)): | ||||||
|  |             im.load() | ||||||
| 
 | 
 | ||||||
|     @unittest.skipIf(sys.maxsize <= 2 ** 32, "requires 64-bit system") |     Image.MAX_IMAGE_PIXELS = max_pixels | ||||||
|     @unittest.skipIf(numpy is None, "Numpy is not installed") | 
 | ||||||
|     def test_ysize(self): | 
 | ||||||
|         # Should not raise 'Integer overflow in ysize' | @pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="Requires 64-bit system") | ||||||
|         arr = numpy.zeros((46341, 46341), dtype=numpy.uint8) | @pytest.mark.skipif(numpy is None, reason="NumPy is not installed") | ||||||
|         Image.fromarray(arr) | def test_ysize(): | ||||||
|  |     # Should not raise 'Integer overflow in ysize' | ||||||
|  |     arr = numpy.zeros((46341, 46341), dtype=numpy.uint8) | ||||||
|  |     Image.fromarray(arr) | ||||||
|  |  | ||||||
|  | @ -1,9 +1,7 @@ | ||||||
| import unittest |  | ||||||
| 
 |  | ||||||
| import pytest | import pytest | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase, assert_deep_equal, assert_image, hopper | from .helper import assert_deep_equal, assert_image, hopper | ||||||
| 
 | 
 | ||||||
| try: | try: | ||||||
|     import numpy |     import numpy | ||||||
|  | @ -14,211 +12,227 @@ except ImportError: | ||||||
| TEST_IMAGE_SIZE = (10, 10) | TEST_IMAGE_SIZE = (10, 10) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @unittest.skipIf(numpy is None, "Numpy is not installed") | pytestmark = pytest.mark.skipif(numpy is None, reason="NumPy is not installed") | ||||||
| class TestNumpy(PillowTestCase): | 
 | ||||||
|     def test_numpy_to_image(self): | 
 | ||||||
|         def to_image(dtype, bands=1, boolean=0): | def test_numpy_to_image(): | ||||||
|             if bands == 1: |     def to_image(dtype, bands=1, boolean=0): | ||||||
|                 if boolean: |         if bands == 1: | ||||||
|                     data = [0, 255] * 50 |             if boolean: | ||||||
|                 else: |                 data = [0, 255] * 50 | ||||||
|                     data = list(range(100)) |  | ||||||
|                 a = numpy.array(data, dtype=dtype) |  | ||||||
|                 a.shape = TEST_IMAGE_SIZE |  | ||||||
|                 i = Image.fromarray(a) |  | ||||||
|                 if list(i.getdata()) != data: |  | ||||||
|                     print("data mismatch for", dtype) |  | ||||||
|             else: |             else: | ||||||
|                 data = list(range(100)) |                 data = list(range(100)) | ||||||
|                 a = numpy.array([[x] * bands for x in data], dtype=dtype) |             a = numpy.array(data, dtype=dtype) | ||||||
|                 a.shape = TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], bands |             a.shape = TEST_IMAGE_SIZE | ||||||
|                 i = Image.fromarray(a) |             i = Image.fromarray(a) | ||||||
|                 if list(i.getchannel(0).getdata()) != list(range(100)): |             if list(i.getdata()) != data: | ||||||
|                     print("data mismatch for", dtype) |                 print("data mismatch for", dtype) | ||||||
|             return i |  | ||||||
| 
 |  | ||||||
|         # Check supported 1-bit integer formats |  | ||||||
|         assert_image(to_image(numpy.bool, 1, 1), "1", TEST_IMAGE_SIZE) |  | ||||||
|         assert_image(to_image(numpy.bool8, 1, 1), "1", TEST_IMAGE_SIZE) |  | ||||||
| 
 |  | ||||||
|         # Check supported 8-bit integer formats |  | ||||||
|         assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE) |  | ||||||
|         assert_image(to_image(numpy.uint8, 3), "RGB", TEST_IMAGE_SIZE) |  | ||||||
|         assert_image(to_image(numpy.uint8, 4), "RGBA", TEST_IMAGE_SIZE) |  | ||||||
|         assert_image(to_image(numpy.int8), "I", TEST_IMAGE_SIZE) |  | ||||||
| 
 |  | ||||||
|         # Check non-fixed-size integer types |  | ||||||
|         # These may fail, depending on the platform, since we have no native |  | ||||||
|         # 64 bit int image types. |  | ||||||
|         # assert_image(to_image(numpy.uint), "I", TEST_IMAGE_SIZE) |  | ||||||
|         # assert_image(to_image(numpy.int), "I", TEST_IMAGE_SIZE) |  | ||||||
| 
 |  | ||||||
|         # Check 16-bit integer formats |  | ||||||
|         if Image._ENDIAN == "<": |  | ||||||
|             assert_image(to_image(numpy.uint16), "I;16", TEST_IMAGE_SIZE) |  | ||||||
|         else: |         else: | ||||||
|             assert_image(to_image(numpy.uint16), "I;16B", TEST_IMAGE_SIZE) |             data = list(range(100)) | ||||||
|  |             a = numpy.array([[x] * bands for x in data], dtype=dtype) | ||||||
|  |             a.shape = TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], bands | ||||||
|  |             i = Image.fromarray(a) | ||||||
|  |             if list(i.getchannel(0).getdata()) != list(range(100)): | ||||||
|  |                 print("data mismatch for", dtype) | ||||||
|  |         return i | ||||||
| 
 | 
 | ||||||
|         assert_image(to_image(numpy.int16), "I", TEST_IMAGE_SIZE) |     # Check supported 1-bit integer formats | ||||||
|  |     assert_image(to_image(numpy.bool, 1, 1), "1", TEST_IMAGE_SIZE) | ||||||
|  |     assert_image(to_image(numpy.bool8, 1, 1), "1", TEST_IMAGE_SIZE) | ||||||
| 
 | 
 | ||||||
|         # Check 32-bit integer formats |     # Check supported 8-bit integer formats | ||||||
|         assert_image(to_image(numpy.uint32), "I", TEST_IMAGE_SIZE) |     assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE) | ||||||
|         assert_image(to_image(numpy.int32), "I", TEST_IMAGE_SIZE) |     assert_image(to_image(numpy.uint8, 3), "RGB", TEST_IMAGE_SIZE) | ||||||
|  |     assert_image(to_image(numpy.uint8, 4), "RGBA", TEST_IMAGE_SIZE) | ||||||
|  |     assert_image(to_image(numpy.int8), "I", TEST_IMAGE_SIZE) | ||||||
| 
 | 
 | ||||||
|         # Check 64-bit integer formats |     # Check non-fixed-size integer types | ||||||
|         self.assertRaises(TypeError, to_image, numpy.uint64) |     # These may fail, depending on the platform, since we have no native | ||||||
|         self.assertRaises(TypeError, to_image, numpy.int64) |     # 64-bit int image types. | ||||||
|  |     # assert_image(to_image(numpy.uint), "I", TEST_IMAGE_SIZE) | ||||||
|  |     # assert_image(to_image(numpy.int), "I", TEST_IMAGE_SIZE) | ||||||
| 
 | 
 | ||||||
|         # Check floating-point formats |     # Check 16-bit integer formats | ||||||
|         assert_image(to_image(numpy.float), "F", TEST_IMAGE_SIZE) |     if Image._ENDIAN == "<": | ||||||
|         self.assertRaises(TypeError, to_image, numpy.float16) |         assert_image(to_image(numpy.uint16), "I;16", TEST_IMAGE_SIZE) | ||||||
|         assert_image(to_image(numpy.float32), "F", TEST_IMAGE_SIZE) |     else: | ||||||
|         assert_image(to_image(numpy.float64), "F", TEST_IMAGE_SIZE) |         assert_image(to_image(numpy.uint16), "I;16B", TEST_IMAGE_SIZE) | ||||||
| 
 | 
 | ||||||
|         assert_image(to_image(numpy.uint8, 2), "LA", (10, 10)) |     assert_image(to_image(numpy.int16), "I", TEST_IMAGE_SIZE) | ||||||
|         assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10)) |  | ||||||
|         assert_image(to_image(numpy.uint8, 4), "RGBA", (10, 10)) |  | ||||||
| 
 | 
 | ||||||
|     # based on an erring example at |     # Check 32-bit integer formats | ||||||
|     # https://stackoverflow.com/questions/10854903/what-is-causing-dimension-dependent-attributeerror-in-pil-fromarray-function |     assert_image(to_image(numpy.uint32), "I", TEST_IMAGE_SIZE) | ||||||
|     def test_3d_array(self): |     assert_image(to_image(numpy.int32), "I", TEST_IMAGE_SIZE) | ||||||
|         size = (5, TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1]) |  | ||||||
|         a = numpy.ones(size, dtype=numpy.uint8) |  | ||||||
|         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) |  | ||||||
|         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) |  | ||||||
|         assert_image(Image.fromarray(a[:, :, 1]), "L", TEST_IMAGE_SIZE) |  | ||||||
| 
 | 
 | ||||||
|     def _test_img_equals_nparray(self, img, np): |     # Check 64-bit integer formats | ||||||
|         self.assertGreaterEqual(len(np.shape), 2) |     with pytest.raises(TypeError): | ||||||
|         np_size = np.shape[1], np.shape[0] |         to_image(numpy.uint64) | ||||||
|         self.assertEqual(img.size, np_size) |     with pytest.raises(TypeError): | ||||||
|         px = img.load() |         to_image(numpy.int64) | ||||||
|         for x in range(0, img.size[0], int(img.size[0] / 10)): |  | ||||||
|             for y in range(0, img.size[1], int(img.size[1] / 10)): |  | ||||||
|                 assert_deep_equal(px[x, y], np[y, x]) |  | ||||||
| 
 | 
 | ||||||
|     def test_16bit(self): |     # Check floating-point formats | ||||||
|         with Image.open("Tests/images/16bit.cropped.tif") as img: |     assert_image(to_image(numpy.float), "F", TEST_IMAGE_SIZE) | ||||||
|             np_img = numpy.array(img) |     with pytest.raises(TypeError): | ||||||
|             self._test_img_equals_nparray(img, np_img) |         to_image(numpy.float16) | ||||||
|         self.assertEqual(np_img.dtype, numpy.dtype("<u2")) |     assert_image(to_image(numpy.float32), "F", TEST_IMAGE_SIZE) | ||||||
|  |     assert_image(to_image(numpy.float64), "F", TEST_IMAGE_SIZE) | ||||||
| 
 | 
 | ||||||
|     def test_1bit(self): |     assert_image(to_image(numpy.uint8, 2), "LA", (10, 10)) | ||||||
|         # Test that 1-bit arrays convert to numpy and back |     assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10)) | ||||||
|         # See: https://github.com/python-pillow/Pillow/issues/350 |     assert_image(to_image(numpy.uint8, 4), "RGBA", (10, 10)) | ||||||
|         arr = numpy.array([[1, 0, 0, 1, 0], [0, 1, 0, 0, 0]], "u1") |  | ||||||
|         img = Image.fromarray(arr * 255).convert("1") |  | ||||||
|         self.assertEqual(img.mode, "1") |  | ||||||
|         arr_back = numpy.array(img) |  | ||||||
|         numpy.testing.assert_array_equal(arr, arr_back) |  | ||||||
| 
 | 
 | ||||||
|     def test_save_tiff_uint16(self): |  | ||||||
|         # Tests that we're getting the pixel value in the right byte order. |  | ||||||
|         pixel_value = 0x1234 |  | ||||||
|         a = numpy.array( |  | ||||||
|             [pixel_value] * TEST_IMAGE_SIZE[0] * TEST_IMAGE_SIZE[1], dtype=numpy.uint16 |  | ||||||
|         ) |  | ||||||
|         a.shape = TEST_IMAGE_SIZE |  | ||||||
|         img = Image.fromarray(a) |  | ||||||
| 
 | 
 | ||||||
|         img_px = img.load() | # Based on an erring example at | ||||||
|         self.assertEqual(img_px[0, 0], pixel_value) | # https://stackoverflow.com/questions/10854903/what-is-causing-dimension-dependent-attributeerror-in-pil-fromarray-function | ||||||
|  | def test_3d_array(): | ||||||
|  |     size = (5, TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1]) | ||||||
|  |     a = numpy.ones(size, dtype=numpy.uint8) | ||||||
|  |     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) | ||||||
|  |     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) | ||||||
|  |     assert_image(Image.fromarray(a[:, :, 1]), "L", TEST_IMAGE_SIZE) | ||||||
| 
 | 
 | ||||||
|     def test_to_array(self): |  | ||||||
|         def _to_array(mode, dtype): |  | ||||||
|             img = hopper(mode) |  | ||||||
| 
 | 
 | ||||||
|             # Resize to non-square | def _test_img_equals_nparray(img, np): | ||||||
|             img = img.crop((3, 0, 124, 127)) |     assert len(np.shape) >= 2 | ||||||
|             self.assertEqual(img.size, (121, 127)) |     np_size = np.shape[1], np.shape[0] | ||||||
|  |     assert img.size == np_size | ||||||
|  |     px = img.load() | ||||||
|  |     for x in range(0, img.size[0], int(img.size[0] / 10)): | ||||||
|  |         for y in range(0, img.size[1], int(img.size[1] / 10)): | ||||||
|  |             assert_deep_equal(px[x, y], np[y, x]) | ||||||
| 
 | 
 | ||||||
|             np_img = numpy.array(img) |  | ||||||
|             self._test_img_equals_nparray(img, np_img) |  | ||||||
|             self.assertEqual(np_img.dtype, dtype) |  | ||||||
| 
 | 
 | ||||||
|         modes = [ | def test_16bit(): | ||||||
|             ("L", numpy.uint8), |     with Image.open("Tests/images/16bit.cropped.tif") as img: | ||||||
|             ("I", numpy.int32), |         np_img = numpy.array(img) | ||||||
|             ("F", numpy.float32), |         _test_img_equals_nparray(img, np_img) | ||||||
|             ("LA", numpy.uint8), |     assert np_img.dtype == numpy.dtype("<u2") | ||||||
|             ("RGB", numpy.uint8), |  | ||||||
|             ("RGBA", numpy.uint8), |  | ||||||
|             ("RGBX", numpy.uint8), |  | ||||||
|             ("CMYK", numpy.uint8), |  | ||||||
|             ("YCbCr", numpy.uint8), |  | ||||||
|             ("I;16", "<u2"), |  | ||||||
|             ("I;16B", ">u2"), |  | ||||||
|             ("I;16L", "<u2"), |  | ||||||
|             ("HSV", numpy.uint8), |  | ||||||
|         ] |  | ||||||
| 
 | 
 | ||||||
|         for mode in modes: |  | ||||||
|             _to_array(*mode) |  | ||||||
| 
 | 
 | ||||||
|     def test_point_lut(self): | def test_1bit(): | ||||||
|         # see https://github.com/python-pillow/Pillow/issues/439 |     # Test that 1-bit arrays convert to numpy and back | ||||||
|  |     # See: https://github.com/python-pillow/Pillow/issues/350 | ||||||
|  |     arr = numpy.array([[1, 0, 0, 1, 0], [0, 1, 0, 0, 0]], "u1") | ||||||
|  |     img = Image.fromarray(arr * 255).convert("1") | ||||||
|  |     assert img.mode == "1" | ||||||
|  |     arr_back = numpy.array(img) | ||||||
|  |     numpy.testing.assert_array_equal(arr, arr_back) | ||||||
| 
 | 
 | ||||||
|         data = list(range(256)) * 3 |  | ||||||
|         lut = numpy.array(data, dtype=numpy.uint8) |  | ||||||
| 
 | 
 | ||||||
|         im = hopper() | def test_save_tiff_uint16(): | ||||||
|  |     # Tests that we're getting the pixel value in the right byte order. | ||||||
|  |     pixel_value = 0x1234 | ||||||
|  |     a = numpy.array( | ||||||
|  |         [pixel_value] * TEST_IMAGE_SIZE[0] * TEST_IMAGE_SIZE[1], dtype=numpy.uint16 | ||||||
|  |     ) | ||||||
|  |     a.shape = TEST_IMAGE_SIZE | ||||||
|  |     img = Image.fromarray(a) | ||||||
| 
 | 
 | ||||||
|         im.point(lut) |     img_px = img.load() | ||||||
|  |     assert img_px[0, 0] == pixel_value | ||||||
| 
 | 
 | ||||||
|     def test_putdata(self): |  | ||||||
|         # shouldn't segfault |  | ||||||
|         # see https://github.com/python-pillow/Pillow/issues/1008 |  | ||||||
| 
 | 
 | ||||||
|         im = Image.new("F", (150, 100)) | def test_to_array(): | ||||||
|         arr = numpy.zeros((15000,), numpy.float32) |     def _to_array(mode, dtype): | ||||||
|         im.putdata(arr) |         img = hopper(mode) | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(len(im.getdata()), len(arr)) |         # Resize to non-square | ||||||
|  |         img = img.crop((3, 0, 124, 127)) | ||||||
|  |         assert img.size == (121, 127) | ||||||
| 
 | 
 | ||||||
|     def test_roundtrip_eye(self): |         np_img = numpy.array(img) | ||||||
|         for dtype in ( |         _test_img_equals_nparray(img, np_img) | ||||||
|             numpy.bool, |         assert np_img.dtype == dtype | ||||||
|             numpy.bool8, |  | ||||||
|             numpy.int8, |  | ||||||
|             numpy.int16, |  | ||||||
|             numpy.int32, |  | ||||||
|             numpy.uint8, |  | ||||||
|             numpy.uint16, |  | ||||||
|             numpy.uint32, |  | ||||||
|             numpy.float, |  | ||||||
|             numpy.float32, |  | ||||||
|             numpy.float64, |  | ||||||
|         ): |  | ||||||
|             arr = numpy.eye(10, dtype=dtype) |  | ||||||
|             numpy.testing.assert_array_equal(arr, numpy.array(Image.fromarray(arr))) |  | ||||||
| 
 | 
 | ||||||
|     def test_zero_size(self): |     modes = [ | ||||||
|         # Shouldn't cause floating point exception |         ("L", numpy.uint8), | ||||||
|         # See https://github.com/python-pillow/Pillow/issues/2259 |         ("I", numpy.int32), | ||||||
|  |         ("F", numpy.float32), | ||||||
|  |         ("LA", numpy.uint8), | ||||||
|  |         ("RGB", numpy.uint8), | ||||||
|  |         ("RGBA", numpy.uint8), | ||||||
|  |         ("RGBX", numpy.uint8), | ||||||
|  |         ("CMYK", numpy.uint8), | ||||||
|  |         ("YCbCr", numpy.uint8), | ||||||
|  |         ("I;16", "<u2"), | ||||||
|  |         ("I;16B", ">u2"), | ||||||
|  |         ("I;16L", "<u2"), | ||||||
|  |         ("HSV", numpy.uint8), | ||||||
|  |     ] | ||||||
| 
 | 
 | ||||||
|         im = Image.fromarray(numpy.empty((0, 0), dtype=numpy.uint8)) |     for mode in modes: | ||||||
|  |         _to_array(*mode) | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(im.size, (0, 0)) |  | ||||||
| 
 | 
 | ||||||
|     def test_bool(self): | def test_point_lut(): | ||||||
|         # https://github.com/python-pillow/Pillow/issues/2044 |     # See https://github.com/python-pillow/Pillow/issues/439 | ||||||
|         a = numpy.zeros((10, 2), dtype=numpy.bool) |  | ||||||
|         a[0][0] = True |  | ||||||
| 
 | 
 | ||||||
|         im2 = Image.fromarray(a) |     data = list(range(256)) * 3 | ||||||
|         self.assertEqual(im2.getdata()[0], 255) |     lut = numpy.array(data, dtype=numpy.uint8) | ||||||
| 
 | 
 | ||||||
|     def test_no_resource_warning_for_numpy_array(self): |     im = hopper() | ||||||
|         # https://github.com/python-pillow/Pillow/issues/835 |  | ||||||
|         # Arrange |  | ||||||
|         from numpy import array |  | ||||||
| 
 | 
 | ||||||
|         test_file = "Tests/images/hopper.png" |     im.point(lut) | ||||||
|         with Image.open(test_file) as im: |  | ||||||
| 
 | 
 | ||||||
|             # Act/Assert | 
 | ||||||
|             pytest.warns(None, lambda: array(im)) | def test_putdata(): | ||||||
|  |     # Shouldn't segfault | ||||||
|  |     # See https://github.com/python-pillow/Pillow/issues/1008 | ||||||
|  | 
 | ||||||
|  |     im = Image.new("F", (150, 100)) | ||||||
|  |     arr = numpy.zeros((15000,), numpy.float32) | ||||||
|  |     im.putdata(arr) | ||||||
|  | 
 | ||||||
|  |     assert len(im.getdata()) == len(arr) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_roundtrip_eye(): | ||||||
|  |     for dtype in ( | ||||||
|  |         numpy.bool, | ||||||
|  |         numpy.bool8, | ||||||
|  |         numpy.int8, | ||||||
|  |         numpy.int16, | ||||||
|  |         numpy.int32, | ||||||
|  |         numpy.uint8, | ||||||
|  |         numpy.uint16, | ||||||
|  |         numpy.uint32, | ||||||
|  |         numpy.float, | ||||||
|  |         numpy.float32, | ||||||
|  |         numpy.float64, | ||||||
|  |     ): | ||||||
|  |         arr = numpy.eye(10, dtype=dtype) | ||||||
|  |         numpy.testing.assert_array_equal(arr, numpy.array(Image.fromarray(arr))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_zero_size(): | ||||||
|  |     # Shouldn't cause floating point exception | ||||||
|  |     # See https://github.com/python-pillow/Pillow/issues/2259 | ||||||
|  | 
 | ||||||
|  |     im = Image.fromarray(numpy.empty((0, 0), dtype=numpy.uint8)) | ||||||
|  | 
 | ||||||
|  |     assert im.size == (0, 0) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_bool(): | ||||||
|  |     # https://github.com/python-pillow/Pillow/issues/2044 | ||||||
|  |     a = numpy.zeros((10, 2), dtype=numpy.bool) | ||||||
|  |     a[0][0] = True | ||||||
|  | 
 | ||||||
|  |     im2 = Image.fromarray(a) | ||||||
|  |     assert im2.getdata()[0] == 255 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_no_resource_warning_for_numpy_array(): | ||||||
|  |     # https://github.com/python-pillow/Pillow/issues/835 | ||||||
|  |     # Arrange | ||||||
|  |     from numpy import array | ||||||
|  | 
 | ||||||
|  |     test_file = "Tests/images/hopper.png" | ||||||
|  |     with Image.open(test_file) as im: | ||||||
|  | 
 | ||||||
|  |         # Act/Assert | ||||||
|  |         pytest.warns(None, lambda: array(im)) | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| import time | import time | ||||||
| 
 | 
 | ||||||
|  | import pytest | ||||||
| from PIL.PdfParser import ( | from PIL.PdfParser import ( | ||||||
|     IndirectObjectDef, |     IndirectObjectDef, | ||||||
|     IndirectReference, |     IndirectReference, | ||||||
|  | @ -14,127 +15,105 @@ from PIL.PdfParser import ( | ||||||
|     pdf_repr, |     pdf_repr, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| from .helper import PillowTestCase | 
 | ||||||
|  | def test_text_encode_decode(): | ||||||
|  |     assert encode_text("abc") == b"\xFE\xFF\x00a\x00b\x00c" | ||||||
|  |     assert decode_text(b"\xFE\xFF\x00a\x00b\x00c") == "abc" | ||||||
|  |     assert decode_text(b"abc") == "abc" | ||||||
|  |     assert decode_text(b"\x1B a \x1C") == "\u02D9 a \u02DD" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestPdfParser(PillowTestCase): | def test_indirect_refs(): | ||||||
|     def test_text_encode_decode(self): |     assert IndirectReference(1, 2) == IndirectReference(1, 2) | ||||||
|         self.assertEqual(encode_text("abc"), b"\xFE\xFF\x00a\x00b\x00c") |     assert IndirectReference(1, 2) != IndirectReference(1, 3) | ||||||
|         self.assertEqual(decode_text(b"\xFE\xFF\x00a\x00b\x00c"), "abc") |     assert IndirectReference(1, 2) != IndirectObjectDef(1, 2) | ||||||
|         self.assertEqual(decode_text(b"abc"), "abc") |     assert IndirectReference(1, 2) != (1, 2) | ||||||
|         self.assertEqual(decode_text(b"\x1B a \x1C"), "\u02D9 a \u02DD") |     assert IndirectObjectDef(1, 2) == IndirectObjectDef(1, 2) | ||||||
|  |     assert IndirectObjectDef(1, 2) != IndirectObjectDef(1, 3) | ||||||
|  |     assert IndirectObjectDef(1, 2) != IndirectReference(1, 2) | ||||||
|  |     assert IndirectObjectDef(1, 2) != (1, 2) | ||||||
| 
 | 
 | ||||||
|     def test_indirect_refs(self): |  | ||||||
|         self.assertEqual(IndirectReference(1, 2), IndirectReference(1, 2)) |  | ||||||
|         self.assertNotEqual(IndirectReference(1, 2), IndirectReference(1, 3)) |  | ||||||
|         self.assertNotEqual(IndirectReference(1, 2), IndirectObjectDef(1, 2)) |  | ||||||
|         self.assertNotEqual(IndirectReference(1, 2), (1, 2)) |  | ||||||
|         self.assertEqual(IndirectObjectDef(1, 2), IndirectObjectDef(1, 2)) |  | ||||||
|         self.assertNotEqual(IndirectObjectDef(1, 2), IndirectObjectDef(1, 3)) |  | ||||||
|         self.assertNotEqual(IndirectObjectDef(1, 2), IndirectReference(1, 2)) |  | ||||||
|         self.assertNotEqual(IndirectObjectDef(1, 2), (1, 2)) |  | ||||||
| 
 | 
 | ||||||
|     def test_parsing(self): | def test_parsing(): | ||||||
|         self.assertEqual(PdfParser.interpret_name(b"Name#23Hash"), b"Name#Hash") |     assert PdfParser.interpret_name(b"Name#23Hash") == b"Name#Hash" | ||||||
|         self.assertEqual( |     assert PdfParser.interpret_name(b"Name#23Hash", as_text=True) == "Name#Hash" | ||||||
|             PdfParser.interpret_name(b"Name#23Hash", as_text=True), "Name#Hash" |     assert PdfParser.get_value(b"1 2 R ", 0) == (IndirectReference(1, 2), 5) | ||||||
|         ) |     assert PdfParser.get_value(b"true[", 0) == (True, 4) | ||||||
|         self.assertEqual( |     assert PdfParser.get_value(b"false%", 0) == (False, 5) | ||||||
|             PdfParser.get_value(b"1 2 R ", 0), (IndirectReference(1, 2), 5) |     assert PdfParser.get_value(b"null<", 0) == (None, 4) | ||||||
|         ) |     assert PdfParser.get_value(b"%cmt\n %cmt\n 123\n", 0) == (123, 15) | ||||||
|         self.assertEqual(PdfParser.get_value(b"true[", 0), (True, 4)) |     assert PdfParser.get_value(b"<901FA3>", 0) == (b"\x90\x1F\xA3", 8) | ||||||
|         self.assertEqual(PdfParser.get_value(b"false%", 0), (False, 5)) |     assert PdfParser.get_value(b"asd < 9 0 1 f A > qwe", 3) == (b"\x90\x1F\xA0", 17) | ||||||
|         self.assertEqual(PdfParser.get_value(b"null<", 0), (None, 4)) |     assert PdfParser.get_value(b"(asd)", 0) == (b"asd", 5) | ||||||
|         self.assertEqual(PdfParser.get_value(b"%cmt\n %cmt\n 123\n", 0), (123, 15)) |     assert PdfParser.get_value(b"(asd(qwe)zxc)zzz(aaa)", 0) == (b"asd(qwe)zxc", 13) | ||||||
|         self.assertEqual(PdfParser.get_value(b"<901FA3>", 0), (b"\x90\x1F\xA3", 8)) |     assert PdfParser.get_value(b"(Two \\\nwords.)", 0) == (b"Two words.", 14) | ||||||
|         self.assertEqual( |     assert PdfParser.get_value(b"(Two\nlines.)", 0) == (b"Two\nlines.", 12) | ||||||
|             PdfParser.get_value(b"asd < 9 0 1 f A > qwe", 3), (b"\x90\x1F\xA0", 17) |     assert PdfParser.get_value(b"(Two\r\nlines.)", 0) == (b"Two\nlines.", 13) | ||||||
|         ) |     assert PdfParser.get_value(b"(Two\\nlines.)", 0) == (b"Two\nlines.", 13) | ||||||
|         self.assertEqual(PdfParser.get_value(b"(asd)", 0), (b"asd", 5)) |     assert PdfParser.get_value(b"(One\\(paren).", 0) == (b"One(paren", 12) | ||||||
|         self.assertEqual( |     assert PdfParser.get_value(b"(One\\)paren).", 0) == (b"One)paren", 12) | ||||||
|             PdfParser.get_value(b"(asd(qwe)zxc)zzz(aaa)", 0), (b"asd(qwe)zxc", 13) |     assert PdfParser.get_value(b"(\\0053)", 0) == (b"\x053", 7) | ||||||
|         ) |     assert PdfParser.get_value(b"(\\053)", 0) == (b"\x2B", 6) | ||||||
|         self.assertEqual( |     assert PdfParser.get_value(b"(\\53)", 0) == (b"\x2B", 5) | ||||||
|             PdfParser.get_value(b"(Two \\\nwords.)", 0), (b"Two words.", 14) |     assert PdfParser.get_value(b"(\\53a)", 0) == (b"\x2Ba", 6) | ||||||
|         ) |     assert PdfParser.get_value(b"(\\1111)", 0) == (b"\x491", 7) | ||||||
|         self.assertEqual(PdfParser.get_value(b"(Two\nlines.)", 0), (b"Two\nlines.", 12)) |     assert PdfParser.get_value(b" 123 (", 0) == (123, 4) | ||||||
|         self.assertEqual( |     assert round(abs(PdfParser.get_value(b" 123.4 %", 0)[0] - 123.4), 7) == 0 | ||||||
|             PdfParser.get_value(b"(Two\r\nlines.)", 0), (b"Two\nlines.", 13) |     assert PdfParser.get_value(b" 123.4 %", 0)[1] == 6 | ||||||
|         ) |     with pytest.raises(PdfFormatError): | ||||||
|         self.assertEqual( |         PdfParser.get_value(b"]", 0) | ||||||
|             PdfParser.get_value(b"(Two\\nlines.)", 0), (b"Two\nlines.", 13) |     d = PdfParser.get_value(b"<</Name (value) /N /V>>", 0)[0] | ||||||
|         ) |     assert isinstance(d, PdfDict) | ||||||
|         self.assertEqual(PdfParser.get_value(b"(One\\(paren).", 0), (b"One(paren", 12)) |     assert len(d) == 2 | ||||||
|         self.assertEqual(PdfParser.get_value(b"(One\\)paren).", 0), (b"One)paren", 12)) |     assert d.Name == "value" | ||||||
|         self.assertEqual(PdfParser.get_value(b"(\\0053)", 0), (b"\x053", 7)) |     assert d[b"Name"] == b"value" | ||||||
|         self.assertEqual(PdfParser.get_value(b"(\\053)", 0), (b"\x2B", 6)) |     assert d.N == PdfName("V") | ||||||
|         self.assertEqual(PdfParser.get_value(b"(\\53)", 0), (b"\x2B", 5)) |     a = PdfParser.get_value(b"[/Name (value) /N /V]", 0)[0] | ||||||
|         self.assertEqual(PdfParser.get_value(b"(\\53a)", 0), (b"\x2Ba", 6)) |     assert isinstance(a, list) | ||||||
|         self.assertEqual(PdfParser.get_value(b"(\\1111)", 0), (b"\x491", 7)) |     assert len(a) == 4 | ||||||
|         self.assertEqual(PdfParser.get_value(b" 123 (", 0), (123, 4)) |     assert a[0] == PdfName("Name") | ||||||
|         self.assertAlmostEqual(PdfParser.get_value(b" 123.4 %", 0)[0], 123.4) |     s = PdfParser.get_value( | ||||||
|         self.assertEqual(PdfParser.get_value(b" 123.4 %", 0)[1], 6) |         b"<</Name (value) /Length 5>>\nstream\nabcde\nendstream<<...", 0 | ||||||
|         self.assertRaises(PdfFormatError, PdfParser.get_value, b"]", 0) |     )[0] | ||||||
|         d = PdfParser.get_value(b"<</Name (value) /N /V>>", 0)[0] |     assert isinstance(s, PdfStream) | ||||||
|         self.assertIsInstance(d, PdfDict) |     assert s.dictionary.Name == "value" | ||||||
|         self.assertEqual(len(d), 2) |     assert s.decode() == b"abcde" | ||||||
|         self.assertEqual(d.Name, "value") |     for name in ["CreationDate", "ModDate"]: | ||||||
|         self.assertEqual(d[b"Name"], b"value") |         for date, value in { | ||||||
|         self.assertEqual(d.N, PdfName("V")) |             b"20180729214124": "20180729214124", | ||||||
|         a = PdfParser.get_value(b"[/Name (value) /N /V]", 0)[0] |             b"D:20180729214124": "20180729214124", | ||||||
|         self.assertIsInstance(a, list) |             b"D:2018072921": "20180729210000", | ||||||
|         self.assertEqual(len(a), 4) |             b"D:20180729214124Z": "20180729214124", | ||||||
|         self.assertEqual(a[0], PdfName("Name")) |             b"D:20180729214124+08'00'": "20180729134124", | ||||||
|         s = PdfParser.get_value( |             b"D:20180729214124-05'00'": "20180730024124", | ||||||
|             b"<</Name (value) /Length 5>>\nstream\nabcde\nendstream<<...", 0 |         }.items(): | ||||||
|         )[0] |             d = PdfParser.get_value(b"<</" + name.encode() + b" (" + date + b")>>", 0)[ | ||||||
|         self.assertIsInstance(s, PdfStream) |                 0 | ||||||
|         self.assertEqual(s.dictionary.Name, "value") |             ] | ||||||
|         self.assertEqual(s.decode(), b"abcde") |             assert time.strftime("%Y%m%d%H%M%S", getattr(d, name)) == value | ||||||
|         for name in ["CreationDate", "ModDate"]: |  | ||||||
|             for date, value in { |  | ||||||
|                 b"20180729214124": "20180729214124", |  | ||||||
|                 b"D:20180729214124": "20180729214124", |  | ||||||
|                 b"D:2018072921": "20180729210000", |  | ||||||
|                 b"D:20180729214124Z": "20180729214124", |  | ||||||
|                 b"D:20180729214124+08'00'": "20180729134124", |  | ||||||
|                 b"D:20180729214124-05'00'": "20180730024124", |  | ||||||
|             }.items(): |  | ||||||
|                 d = PdfParser.get_value( |  | ||||||
|                     b"<</" + name.encode() + b" (" + date + b")>>", 0 |  | ||||||
|                 )[0] |  | ||||||
|                 self.assertEqual(time.strftime("%Y%m%d%H%M%S", getattr(d, name)), value) |  | ||||||
| 
 | 
 | ||||||
|     def test_pdf_repr(self): | 
 | ||||||
|         self.assertEqual(bytes(IndirectReference(1, 2)), b"1 2 R") | def test_pdf_repr(): | ||||||
|         self.assertEqual(bytes(IndirectObjectDef(*IndirectReference(1, 2))), b"1 2 obj") |     assert bytes(IndirectReference(1, 2)) == b"1 2 R" | ||||||
|         self.assertEqual(bytes(PdfName(b"Name#Hash")), b"/Name#23Hash") |     assert bytes(IndirectObjectDef(*IndirectReference(1, 2))) == b"1 2 obj" | ||||||
|         self.assertEqual(bytes(PdfName("Name#Hash")), b"/Name#23Hash") |     assert bytes(PdfName(b"Name#Hash")) == b"/Name#23Hash" | ||||||
|         self.assertEqual( |     assert bytes(PdfName("Name#Hash")) == b"/Name#23Hash" | ||||||
|             bytes(PdfDict({b"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>" |     assert bytes(PdfDict({b"Name": IndirectReference(1, 2)})) == b"<<\n/Name 1 2 R\n>>" | ||||||
|         ) |     assert bytes(PdfDict({"Name": IndirectReference(1, 2)})) == b"<<\n/Name 1 2 R\n>>" | ||||||
|         self.assertEqual( |     assert pdf_repr(IndirectReference(1, 2)) == b"1 2 R" | ||||||
|             bytes(PdfDict({"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>" |     assert pdf_repr(IndirectObjectDef(*IndirectReference(1, 2))) == b"1 2 obj" | ||||||
|         ) |     assert pdf_repr(PdfName(b"Name#Hash")) == b"/Name#23Hash" | ||||||
|         self.assertEqual(pdf_repr(IndirectReference(1, 2)), b"1 2 R") |     assert pdf_repr(PdfName("Name#Hash")) == b"/Name#23Hash" | ||||||
|         self.assertEqual( |     assert ( | ||||||
|             pdf_repr(IndirectObjectDef(*IndirectReference(1, 2))), b"1 2 obj" |         pdf_repr(PdfDict({b"Name": IndirectReference(1, 2)})) == b"<<\n/Name 1 2 R\n>>" | ||||||
|         ) |     ) | ||||||
|         self.assertEqual(pdf_repr(PdfName(b"Name#Hash")), b"/Name#23Hash") |     assert ( | ||||||
|         self.assertEqual(pdf_repr(PdfName("Name#Hash")), b"/Name#23Hash") |         pdf_repr(PdfDict({"Name": IndirectReference(1, 2)})) == b"<<\n/Name 1 2 R\n>>" | ||||||
|         self.assertEqual( |     ) | ||||||
|             pdf_repr(PdfDict({b"Name": IndirectReference(1, 2)})), |     assert pdf_repr(123) == b"123" | ||||||
|             b"<<\n/Name 1 2 R\n>>", |     assert pdf_repr(True) == b"true" | ||||||
|         ) |     assert pdf_repr(False) == b"false" | ||||||
|         self.assertEqual( |     assert pdf_repr(None) == b"null" | ||||||
|             pdf_repr(PdfDict({"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>" |     assert pdf_repr(b"a)/b\\(c") == br"(a\)/b\\\(c)" | ||||||
|         ) |     assert pdf_repr([123, True, {"a": PdfName(b"b")}]) == b"[ 123 true <<\n/a /b\n>> ]" | ||||||
|         self.assertEqual(pdf_repr(123), b"123") |     assert pdf_repr(PdfBinary(b"\x90\x1F\xA0")) == b"<901FA0>" | ||||||
|         self.assertEqual(pdf_repr(True), b"true") |  | ||||||
|         self.assertEqual(pdf_repr(False), b"false") |  | ||||||
|         self.assertEqual(pdf_repr(None), b"null") |  | ||||||
|         self.assertEqual(pdf_repr(b"a)/b\\(c"), br"(a\)/b\\\(c)") |  | ||||||
|         self.assertEqual( |  | ||||||
|             pdf_repr([123, True, {"a": PdfName(b"b")}]), b"[ 123 true <<\n/a /b\n>> ]" |  | ||||||
|         ) |  | ||||||
|         self.assertEqual(pdf_repr(PdfBinary(b"\x90\x1F\xA0")), b"<901FA0>") |  | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user