Added ImageOps exif_transpose method
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_2.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_2.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_3.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_3.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_4.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_4.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_5.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_5.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_6.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_6.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_7.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_7.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_8.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/hopper_orientation_8.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
|  | @ -3,6 +3,12 @@ from .helper import PillowTestCase, hopper | |||
| from PIL import ImageOps | ||||
| from PIL import Image | ||||
| 
 | ||||
| try: | ||||
|     from PIL import _webp | ||||
|     HAVE_WEBP = True | ||||
| except ImportError: | ||||
|     HAVE_WEBP = False | ||||
| 
 | ||||
| 
 | ||||
| class TestImageOps(PillowTestCase): | ||||
| 
 | ||||
|  | @ -62,6 +68,9 @@ class TestImageOps(PillowTestCase): | |||
|         ImageOps.solarize(hopper("L")) | ||||
|         ImageOps.solarize(hopper("RGB")) | ||||
| 
 | ||||
|         ImageOps.exif_transpose(hopper("L")) | ||||
|         ImageOps.exif_transpose(hopper("RGB")) | ||||
| 
 | ||||
|     def test_1pxfit(self): | ||||
|         # Division by zero in equalize if image is 1 pixel high | ||||
|         newimg = ImageOps.fit(hopper("RGB").resize((1, 1)), (35, 35)) | ||||
|  | @ -218,3 +227,22 @@ class TestImageOps(PillowTestCase): | |||
|                                        (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: | ||||
|             base_im = Image.open("Tests/images/hopper"+ext) | ||||
| 
 | ||||
|             orientations = [base_im] | ||||
|             for i in range(2, 9): | ||||
|                 im = Image.open("Tests/images/hopper_orientation_"+str(i)+ext) | ||||
|                 orientations.append(im) | ||||
|             for im in orientations: | ||||
|                 transposed_im = ImageOps.exif_transpose(im) | ||||
|                 self.assert_image_similar(base_im, transposed_im, 17) | ||||
| 
 | ||||
|                 # Repeat the operation, to test that it does not keep transposing | ||||
|                 transposed_im2 = ImageOps.exif_transpose(transposed_im) | ||||
|                 self.assert_image_equal(transposed_im2, transposed_im) | ||||
|  |  | |||
|  | @ -522,3 +522,31 @@ def solarize(image, threshold=128): | |||
|         else: | ||||
|             lut.append(255-i) | ||||
|     return _lut(image, lut) | ||||
| 
 | ||||
| 
 | ||||
| def exif_transpose(image): | ||||
|     """ | ||||
|     If an image has an EXIF Orientation tag, return a new image that is | ||||
|     transposed accordingly. Otherwise, return a copy of the image. | ||||
| 
 | ||||
|     :param image: The image to transpose. | ||||
|     :return: An image. | ||||
|     """ | ||||
|     if not hasattr(image, '_exif_transposed') and hasattr(image, '_getexif'): | ||||
|         exif = image._getexif() | ||||
|         if exif: | ||||
|             orientation = exif.get(0x0112) | ||||
|             method = { | ||||
|                 2: Image.FLIP_LEFT_RIGHT, | ||||
|                 3: Image.ROTATE_180, | ||||
|                 4: Image.FLIP_TOP_BOTTOM, | ||||
|                 5: Image.TRANSPOSE, | ||||
|                 6: Image.ROTATE_270, | ||||
|                 7: Image.TRANSVERSE, | ||||
|                 8: Image.ROTATE_90 | ||||
|             }.get(orientation) | ||||
|             if method is not None: | ||||
|                 transposed_image = image.transpose(method) | ||||
|                 transposed_image._exif_transposed = True | ||||
|                 return transposed_image | ||||
|     return image.copy() | ||||
|  |  | |||