mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-31 07:57:27 +03:00 
			
		
		
		
	Merge pull request #1 from wiredfool/p_rgba_transparency
Tweak for #664
This commit is contained in:
		
						commit
						f8c5812154
					
				
							
								
								
									
										39
									
								
								PIL/Image.py
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								PIL/Image.py
									
									
									
									
									
								
							|  | @ -101,7 +101,7 @@ import collections | ||||||
| import numbers | import numbers | ||||||
| 
 | 
 | ||||||
| # works everywhere, win for pypy, not cpython | # works everywhere, win for pypy, not cpython | ||||||
| USE_CFFI_ACCESS = hasattr(sys, 'pypy_version_info')   | USE_CFFI_ACCESS = hasattr(sys, 'pypy_version_info') | ||||||
| try: | try: | ||||||
|     import cffi |     import cffi | ||||||
|     HAS_CFFI=True |     HAS_CFFI=True | ||||||
|  | @ -233,7 +233,7 @@ _MODE_CONV = { | ||||||
|     "CMYK": ('|u1', 4), |     "CMYK": ('|u1', 4), | ||||||
|     "YCbCr": ('|u1', 3), |     "YCbCr": ('|u1', 3), | ||||||
|     "LAB": ('|u1', 3), # UNDONE - unsigned |u1i1i1 |     "LAB": ('|u1', 3), # UNDONE - unsigned |u1i1i1 | ||||||
| 	# I;16 == I;16L, and I;32 == I;32L   | 	# I;16 == I;16L, and I;32 == I;32L | ||||||
|     "I;16": ('<u2', None), |     "I;16": ('<u2', None), | ||||||
|     "I;16B": ('>u2', None), |     "I;16B": ('>u2', None), | ||||||
|     "I;16L": ('<u2', None), |     "I;16L": ('<u2', None), | ||||||
|  | @ -502,7 +502,7 @@ class Image: | ||||||
|         return self |         return self | ||||||
|     def __exit__(self, *args): |     def __exit__(self, *args): | ||||||
|         self.close() |         self.close() | ||||||
|          | 
 | ||||||
|     def close(self): |     def close(self): | ||||||
|         """ |         """ | ||||||
|         Closes the file pointer, if possible. |         Closes the file pointer, if possible. | ||||||
|  | @ -524,7 +524,7 @@ class Image: | ||||||
|         # deferred error that will better explain that the core image |         # deferred error that will better explain that the core image | ||||||
|         # object is gone. |         # object is gone. | ||||||
|         self.im = deferred_error(ValueError("Operation on closed image")) |         self.im = deferred_error(ValueError("Operation on closed image")) | ||||||
|          | 
 | ||||||
| 
 | 
 | ||||||
|     def _copy(self): |     def _copy(self): | ||||||
|         self.load() |         self.load() | ||||||
|  | @ -540,7 +540,7 @@ class Image: | ||||||
|         if not file: |         if not file: | ||||||
|             f, file = tempfile.mkstemp(suffix) |             f, file = tempfile.mkstemp(suffix) | ||||||
|             os.close(f) |             os.close(f) | ||||||
|              | 
 | ||||||
|         self.load() |         self.load() | ||||||
|         if not format or format == "PPM": |         if not format or format == "PPM": | ||||||
|             self.im.save_ppm(file) |             self.im.save_ppm(file) | ||||||
|  | @ -672,7 +672,7 @@ class Image: | ||||||
|         normal cases, you don't need to call this method, since the |         normal cases, you don't need to call this method, since the | ||||||
|         Image class automatically loads an opened image when it is |         Image class automatically loads an opened image when it is | ||||||
|         accessed for the first time. This method will close the file |         accessed for the first time. This method will close the file | ||||||
|         associated with the image.  |         associated with the image. | ||||||
| 
 | 
 | ||||||
|         :returns: An image access object. |         :returns: An image access object. | ||||||
|         """ |         """ | ||||||
|  | @ -777,7 +777,7 @@ class Image: | ||||||
|         if "transparency" in self.info and self.info['transparency'] is not None: |         if "transparency" in self.info and self.info['transparency'] is not None: | ||||||
|             if self.mode in ('L', 'RGB') and mode == 'RGBA': |             if self.mode in ('L', 'RGB') and mode == 'RGBA': | ||||||
|                 # Use transparent conversion to promote from transparent |                 # Use transparent conversion to promote from transparent | ||||||
|                 # color to an alpha channel.          |                 # color to an alpha channel. | ||||||
|                 return self._new(self.im.convert_transparent( |                 return self._new(self.im.convert_transparent( | ||||||
|                                            mode, self.info['transparency'])) |                                            mode, self.info['transparency'])) | ||||||
|             elif self.mode in ('L', 'RGB', 'P') and mode in ('L', 'RGB', 'P'): |             elif self.mode in ('L', 'RGB', 'P') and mode in ('L', 'RGB', 'P'): | ||||||
|  | @ -799,11 +799,12 @@ class Image: | ||||||
|                         trns_im = trns_im.convert(mode) |                         trns_im = trns_im.convert(mode) | ||||||
|                     else: |                     else: | ||||||
|                         # can't just retrieve the palette number, got to do it |                         # can't just retrieve the palette number, got to do it | ||||||
|                         # after quantization.  |                         # after quantization. | ||||||
|                         trns_im = trns_im.convert('RGB') |                         trns_im = trns_im.convert('RGB') | ||||||
|                     trns = trns_im.getpixel((0,0)) |                     trns = trns_im.getpixel((0,0)) | ||||||
|                          |             elif self.mode == 'P' and mode == 'RGBA': | ||||||
|                      |                 delete_trns = True | ||||||
|  | 
 | ||||||
|         if mode == "P" and palette == ADAPTIVE: |         if mode == "P" and palette == ADAPTIVE: | ||||||
|             im = self.im.quantize(colors) |             im = self.im.quantize(colors) | ||||||
|             new = self._new(im) |             new = self._new(im) | ||||||
|  | @ -811,7 +812,7 @@ class Image: | ||||||
|             new.palette = ImagePalette.raw("RGB", new.im.getpalette("RGB")) |             new.palette = ImagePalette.raw("RGB", new.im.getpalette("RGB")) | ||||||
|             if delete_trns: |             if delete_trns: | ||||||
|                 # This could possibly happen if we requantize to fewer colors. |                 # This could possibly happen if we requantize to fewer colors. | ||||||
|                 # The transparency would be totally off in that case.  |                 # The transparency would be totally off in that case. | ||||||
|                 del(new.info['transparency']) |                 del(new.info['transparency']) | ||||||
|             if trns is not None: |             if trns is not None: | ||||||
|                 try: |                 try: | ||||||
|  | @ -826,7 +827,7 @@ class Image: | ||||||
|         # colorspace conversion |         # colorspace conversion | ||||||
|         if dither is None: |         if dither is None: | ||||||
|             dither = FLOYDSTEINBERG |             dither = FLOYDSTEINBERG | ||||||
|                  | 
 | ||||||
|         try: |         try: | ||||||
|             im = self.im.convert(mode, dither) |             im = self.im.convert(mode, dither) | ||||||
|         except ValueError: |         except ValueError: | ||||||
|  | @ -863,7 +864,7 @@ class Image: | ||||||
|         # quantizer interface in a later version of PIL. |         # quantizer interface in a later version of PIL. | ||||||
| 
 | 
 | ||||||
|         self.load() |         self.load() | ||||||
|          | 
 | ||||||
|         if method is None: |         if method is None: | ||||||
|             # defaults: |             # defaults: | ||||||
|             method = 0 |             method = 0 | ||||||
|  | @ -871,10 +872,10 @@ class Image: | ||||||
|                 method = 2 |                 method = 2 | ||||||
| 
 | 
 | ||||||
|         if self.mode == 'RGBA' and method != 2: |         if self.mode == 'RGBA' and method != 2: | ||||||
|             # Caller specified an invalid mode.  |             # Caller specified an invalid mode. | ||||||
|             raise ValueError('Fast Octree (method == 2) is the ' + |             raise ValueError('Fast Octree (method == 2) is the ' + | ||||||
|                              ' only valid method for quantizing RGBA images') |                              ' only valid method for quantizing RGBA images') | ||||||
|          | 
 | ||||||
|         if palette: |         if palette: | ||||||
|             # use palette from reference image |             # use palette from reference image | ||||||
|             palette.load() |             palette.load() | ||||||
|  | @ -928,7 +929,7 @@ class Image: | ||||||
|     def draft(self, mode, size): |     def draft(self, mode, size): | ||||||
|         """ |         """ | ||||||
|         NYI |         NYI | ||||||
|          | 
 | ||||||
|         Configures the image file loader so it returns a version of the |         Configures the image file loader so it returns a version of the | ||||||
|         image that as closely as possible matches the given mode and |         image that as closely as possible matches the given mode and | ||||||
|         size.  For example, you can use this method to convert a color |         size.  For example, you can use this method to convert a color | ||||||
|  | @ -1277,7 +1278,7 @@ class Image: | ||||||
|             if self.mode in ("I", "I;16", "F"): |             if self.mode in ("I", "I;16", "F"): | ||||||
|                 # check if the function can be used with point_transform |                 # check if the function can be used with point_transform | ||||||
|                 # UNDONE wiredfool -- I think this prevents us from ever doing |                 # UNDONE wiredfool -- I think this prevents us from ever doing | ||||||
|                 # a gamma function point transform on > 8bit images.  |                 # a gamma function point transform on > 8bit images. | ||||||
|                 scale, offset = _getscaleoffset(lut) |                 scale, offset = _getscaleoffset(lut) | ||||||
|                 return self._new(self.im.point_transform(scale, offset)) |                 return self._new(self.im.point_transform(scale, offset)) | ||||||
|             # for other modes, convert the function to a table |             # for other modes, convert the function to a table | ||||||
|  | @ -1420,8 +1421,8 @@ class Image: | ||||||
|             self._copy() |             self._copy() | ||||||
|             self.pyaccess = None |             self.pyaccess = None | ||||||
|             self.load() |             self.load() | ||||||
|              | 
 | ||||||
|         if self.pyaccess:  |         if self.pyaccess: | ||||||
|             return self.pyaccess.putpixel(xy,value) |             return self.pyaccess.putpixel(xy,value) | ||||||
|         return self.im.putpixel(xy, value) |         return self.im.putpixel(xy, value) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ from tester import * | ||||||
| 
 | 
 | ||||||
| from PIL import Image | from PIL import Image | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def test_sanity(): | def test_sanity(): | ||||||
| 
 | 
 | ||||||
|     def convert(im, mode): |     def convert(im, mode): | ||||||
|  | @ -16,6 +17,7 @@ def test_sanity(): | ||||||
|         for mode in modes: |         for mode in modes: | ||||||
|             yield_test(convert, im, mode) |             yield_test(convert, im, mode) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def test_default(): | def test_default(): | ||||||
| 
 | 
 | ||||||
|     im = lena("P") |     im = lena("P") | ||||||
|  | @ -26,26 +28,29 @@ def test_default(): | ||||||
|     assert_image(im, "RGB", im.size) |     assert_image(im, "RGB", im.size) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # ref https://github.com/python-imaging/Pillow/issues/274 | # ref https://github.com/python-imaging/Pillow/issues/274 | ||||||
| 
 | 
 | ||||||
| def _test_float_conversion(im): | def _test_float_conversion(im): | ||||||
|     orig = im.getpixel((5,5)) |     orig = im.getpixel((5, 5)) | ||||||
|     converted = im.convert('F').getpixel((5,5)) |     converted = im.convert('F').getpixel((5, 5)) | ||||||
|     assert_equal(orig, converted) |     assert_equal(orig, converted) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def test_8bit(): | def test_8bit(): | ||||||
|     im = Image.open('Images/lena.jpg') |     im = Image.open('Images/lena.jpg') | ||||||
|     _test_float_conversion(im.convert('L')) |     _test_float_conversion(im.convert('L')) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def test_16bit(): | def test_16bit(): | ||||||
|     im = Image.open('Tests/images/16bit.cropped.tif') |     im = Image.open('Tests/images/16bit.cropped.tif') | ||||||
|     _test_float_conversion(im) |     _test_float_conversion(im) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def test_16bit_workaround(): | def test_16bit_workaround(): | ||||||
|     im = Image.open('Tests/images/16bit.cropped.tif') |     im = Image.open('Tests/images/16bit.cropped.tif') | ||||||
|     _test_float_conversion(im.convert('I')) |     _test_float_conversion(im.convert('I')) | ||||||
|      | 
 | ||||||
|  | 
 | ||||||
| def test_rgba_p(): | def test_rgba_p(): | ||||||
|     im = lena('RGBA') |     im = lena('RGBA') | ||||||
|     im.putalpha(lena('L')) |     im.putalpha(lena('L')) | ||||||
|  | @ -54,30 +59,45 @@ def test_rgba_p(): | ||||||
|     comparable = converted.convert('RGBA') |     comparable = converted.convert('RGBA') | ||||||
| 
 | 
 | ||||||
|     assert_image_similar(im, comparable, 20) |     assert_image_similar(im, comparable, 20) | ||||||
|                 | 
 | ||||||
| def test_trns_p():     | 
 | ||||||
|  | def test_trns_p(): | ||||||
|     im = lena('P') |     im = lena('P') | ||||||
|     im.info['transparency']=0 |     im.info['transparency'] = 0 | ||||||
| 
 | 
 | ||||||
|     f = tempfile('temp.png') |     f = tempfile('temp.png') | ||||||
| 
 | 
 | ||||||
|     l = im.convert('L') |     l = im.convert('L') | ||||||
|     assert_equal(l.info['transparency'], 0) # undone |     assert_equal(l.info['transparency'], 0)  # undone | ||||||
|     assert_no_exception(lambda: l.save(f)) |     assert_no_exception(lambda: l.save(f)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     rgb = im.convert('RGB') |     rgb = im.convert('RGB') | ||||||
|     assert_equal(rgb.info['transparency'], (0,0,0)) # undone |     assert_equal(rgb.info['transparency'], (0, 0, 0))  # undone | ||||||
|     assert_no_exception(lambda: rgb.save(f)) |     assert_no_exception(lambda: rgb.save(f)) | ||||||
|      | 
 | ||||||
|  | 
 | ||||||
|  | # ref https://github.com/python-imaging/Pillow/issues/664 | ||||||
|  | 
 | ||||||
|  | def test_trns_p_rgba(): | ||||||
|  |     # Arrange | ||||||
|  |     im = lena('P') | ||||||
|  |     im.info['transparency'] = 128 | ||||||
|  | 
 | ||||||
|  |     # Act | ||||||
|  |     rgba = im.convert('RGBA') | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert_false('transparency' in rgba.info) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def test_trns_l(): | def test_trns_l(): | ||||||
|     im = lena('L') |     im = lena('L') | ||||||
|     im.info['transparency'] = 128 |     im.info['transparency'] = 128 | ||||||
| 
 | 
 | ||||||
|     f = tempfile('temp.png') |     f = tempfile('temp.png') | ||||||
|      | 
 | ||||||
|     rgb = im.convert('RGB') |     rgb = im.convert('RGB') | ||||||
|     assert_equal(rgb.info['transparency'], (128,128,128)) # undone |     assert_equal(rgb.info['transparency'], (128, 128, 128))  # undone | ||||||
|     assert_no_exception(lambda: rgb.save(f)) |     assert_no_exception(lambda: rgb.save(f)) | ||||||
| 
 | 
 | ||||||
|     p = im.convert('P') |     p = im.convert('P') | ||||||
|  | @ -85,28 +105,26 @@ def test_trns_l(): | ||||||
|     assert_no_exception(lambda: p.save(f)) |     assert_no_exception(lambda: p.save(f)) | ||||||
| 
 | 
 | ||||||
|     p = assert_warning(UserWarning, |     p = assert_warning(UserWarning, | ||||||
|                        lambda: im.convert('P', palette = Image.ADAPTIVE)) |                        lambda: im.convert('P', palette=Image.ADAPTIVE)) | ||||||
|     assert_false('transparency' in p.info) |     assert_false('transparency' in p.info) | ||||||
|     assert_no_exception(lambda: p.save(f)) |     assert_no_exception(lambda: p.save(f)) | ||||||
| 
 | 
 | ||||||
|      | 
 | ||||||
| def test_trns_RGB(): | def test_trns_RGB(): | ||||||
|     im = lena('RGB') |     im = lena('RGB') | ||||||
|     im.info['transparency'] = im.getpixel((0,0)) |     im.info['transparency'] = im.getpixel((0, 0)) | ||||||
| 
 | 
 | ||||||
|     f = tempfile('temp.png') |     f = tempfile('temp.png') | ||||||
|          | 
 | ||||||
|     l = im.convert('L') |     l = im.convert('L') | ||||||
|     assert_equal(l.info['transparency'], l.getpixel((0,0))) # undone |     assert_equal(l.info['transparency'], l.getpixel((0, 0)))  # undone | ||||||
|     assert_no_exception(lambda: l.save(f)) |     assert_no_exception(lambda: l.save(f)) | ||||||
| 
 | 
 | ||||||
|     p = im.convert('P') |     p = im.convert('P') | ||||||
|     assert_true('transparency' in p.info) |     assert_true('transparency' in p.info) | ||||||
|     assert_no_exception(lambda: p.save(f)) |     assert_no_exception(lambda: p.save(f)) | ||||||
|      | 
 | ||||||
|     p = assert_warning(UserWarning, |     p = assert_warning(UserWarning, | ||||||
|                        lambda: im.convert('P', palette = Image.ADAPTIVE)) |                        lambda: im.convert('P', palette=Image.ADAPTIVE)) | ||||||
|     assert_false('transparency' in p.info) |     assert_false('transparency' in p.info) | ||||||
|     assert_no_exception(lambda: p.save(f)) |     assert_no_exception(lambda: p.save(f)) | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user