mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 01:47:47 +03:00 
			
		
		
		
	Wait until all markers are read to process EXIF
This commit is contained in:
		
							parent
							
								
									53e82e49c5
								
							
						
					
					
						commit
						b84c970fbf
					
				
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 364 B After Width: | Height: | Size: 391 B  | 
| 
						 | 
					@ -870,7 +870,7 @@ class TestFileJpeg:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_multiple_exif(self) -> None:
 | 
					    def test_multiple_exif(self) -> None:
 | 
				
			||||||
        with Image.open("Tests/images/multiple_exif.jpg") as im:
 | 
					        with Image.open("Tests/images/multiple_exif.jpg") as im:
 | 
				
			||||||
            assert im.info["exif"] == b"Exif\x00\x00firstsecond"
 | 
					            assert im.getexif()[270] == "firstsecond"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @mark_if_feature_version(
 | 
					    @mark_if_feature_version(
 | 
				
			||||||
        pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
 | 
					        pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,38 +159,6 @@ def APP(self, marker):
 | 
				
			||||||
        # plus constant header size
 | 
					        # plus constant header size
 | 
				
			||||||
        self.info["mpoffset"] = self.fp.tell() - n + 4
 | 
					        self.info["mpoffset"] = self.fp.tell() - n + 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # If DPI isn't in JPEG header, fetch from EXIF
 | 
					 | 
				
			||||||
    if "dpi" not in self.info and "exif" in self.info:
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            exif = self.getexif()
 | 
					 | 
				
			||||||
            resolution_unit = exif[0x0128]
 | 
					 | 
				
			||||||
            x_resolution = exif[0x011A]
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                dpi = float(x_resolution[0]) / x_resolution[1]
 | 
					 | 
				
			||||||
            except TypeError:
 | 
					 | 
				
			||||||
                dpi = x_resolution
 | 
					 | 
				
			||||||
            if math.isnan(dpi):
 | 
					 | 
				
			||||||
                msg = "DPI is not a number"
 | 
					 | 
				
			||||||
                raise ValueError(msg)
 | 
					 | 
				
			||||||
            if resolution_unit == 3:  # cm
 | 
					 | 
				
			||||||
                # 1 dpcm = 2.54 dpi
 | 
					 | 
				
			||||||
                dpi *= 2.54
 | 
					 | 
				
			||||||
            self.info["dpi"] = dpi, dpi
 | 
					 | 
				
			||||||
        except (
 | 
					 | 
				
			||||||
            struct.error,
 | 
					 | 
				
			||||||
            KeyError,
 | 
					 | 
				
			||||||
            SyntaxError,
 | 
					 | 
				
			||||||
            TypeError,
 | 
					 | 
				
			||||||
            ValueError,
 | 
					 | 
				
			||||||
            ZeroDivisionError,
 | 
					 | 
				
			||||||
        ):
 | 
					 | 
				
			||||||
            # struct.error for truncated EXIF
 | 
					 | 
				
			||||||
            # KeyError for dpi not included
 | 
					 | 
				
			||||||
            # SyntaxError for invalid/unreadable EXIF
 | 
					 | 
				
			||||||
            # ValueError or TypeError for dpi being an invalid float
 | 
					 | 
				
			||||||
            # ZeroDivisionError for invalid dpi rational value
 | 
					 | 
				
			||||||
            self.info["dpi"] = 72, 72
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def COM(self: JpegImageFile, marker: int) -> None:
 | 
					def COM(self: JpegImageFile, marker: int) -> None:
 | 
				
			||||||
    #
 | 
					    #
 | 
				
			||||||
| 
						 | 
					@ -409,6 +377,8 @@ class JpegImageFile(ImageFile.ImageFile):
 | 
				
			||||||
                msg = "no marker found"
 | 
					                msg = "no marker found"
 | 
				
			||||||
                raise SyntaxError(msg)
 | 
					                raise SyntaxError(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._read_dpi_from_exif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def load_read(self, read_bytes: int) -> bytes:
 | 
					    def load_read(self, read_bytes: int) -> bytes:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        internal: read more image data
 | 
					        internal: read more image data
 | 
				
			||||||
| 
						 | 
					@ -497,6 +467,40 @@ class JpegImageFile(ImageFile.ImageFile):
 | 
				
			||||||
    def _getexif(self) -> dict[str, Any] | None:
 | 
					    def _getexif(self) -> dict[str, Any] | None:
 | 
				
			||||||
        return _getexif(self)
 | 
					        return _getexif(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _read_dpi_from_exif(self) -> None:
 | 
				
			||||||
 | 
					        # If DPI isn't in JPEG header, fetch from EXIF
 | 
				
			||||||
 | 
					        if "dpi" in self.info or "exif" not in self.info:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            exif = self.getexif()
 | 
				
			||||||
 | 
					            resolution_unit = exif[0x0128]
 | 
				
			||||||
 | 
					            x_resolution = exif[0x011A]
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                dpi = float(x_resolution[0]) / x_resolution[1]
 | 
				
			||||||
 | 
					            except TypeError:
 | 
				
			||||||
 | 
					                dpi = x_resolution
 | 
				
			||||||
 | 
					            if math.isnan(dpi):
 | 
				
			||||||
 | 
					                msg = "DPI is not a number"
 | 
				
			||||||
 | 
					                raise ValueError(msg)
 | 
				
			||||||
 | 
					            if resolution_unit == 3:  # cm
 | 
				
			||||||
 | 
					                # 1 dpcm = 2.54 dpi
 | 
				
			||||||
 | 
					                dpi *= 2.54
 | 
				
			||||||
 | 
					            self.info["dpi"] = dpi, dpi
 | 
				
			||||||
 | 
					        except (
 | 
				
			||||||
 | 
					            struct.error,
 | 
				
			||||||
 | 
					            KeyError,
 | 
				
			||||||
 | 
					            SyntaxError,
 | 
				
			||||||
 | 
					            TypeError,
 | 
				
			||||||
 | 
					            ValueError,
 | 
				
			||||||
 | 
					            ZeroDivisionError,
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
 | 
					            # struct.error for truncated EXIF
 | 
				
			||||||
 | 
					            # KeyError for dpi not included
 | 
				
			||||||
 | 
					            # SyntaxError for invalid/unreadable EXIF
 | 
				
			||||||
 | 
					            # ValueError or TypeError for dpi being an invalid float
 | 
				
			||||||
 | 
					            # ZeroDivisionError for invalid dpi rational value
 | 
				
			||||||
 | 
					            self.info["dpi"] = 72, 72
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _getmp(self):
 | 
					    def _getmp(self):
 | 
				
			||||||
        return _getmp(self)
 | 
					        return _getmp(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user