mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-30 23:47:27 +03:00 
			
		
		
		
	Merge branch 'main' into context_manager
This commit is contained in:
		
						commit
						68e9ee59e7
					
				
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 486 B After Width: | Height: | Size: 533 B | 
|  | @ -84,4 +84,4 @@ def test_handler(tmp_path: Path) -> None: | ||||||
|         im.save(temp_file) |         im.save(temp_file) | ||||||
|         assert handler.saved |         assert handler.saved | ||||||
| 
 | 
 | ||||||
|     BufrStubImagePlugin._handler = None |     BufrStubImagePlugin.register_handler(None) | ||||||
|  |  | ||||||
|  | @ -84,4 +84,4 @@ def test_handler(tmp_path: Path) -> None: | ||||||
|         im.save(temp_file) |         im.save(temp_file) | ||||||
|         assert handler.saved |         assert handler.saved | ||||||
| 
 | 
 | ||||||
|     GribStubImagePlugin._handler = None |     GribStubImagePlugin.register_handler(None) | ||||||
|  |  | ||||||
|  | @ -86,4 +86,4 @@ def test_handler(tmp_path: Path) -> None: | ||||||
|         im.save(temp_file) |         im.save(temp_file) | ||||||
|         assert handler.saved |         assert handler.saved | ||||||
| 
 | 
 | ||||||
|     Hdf5StubImagePlugin._handler = None |     Hdf5StubImagePlugin.register_handler(None) | ||||||
|  |  | ||||||
|  | @ -1030,8 +1030,13 @@ class TestFileJpeg: | ||||||
|         with Image.open(f) as reloaded: |         with Image.open(f) as reloaded: | ||||||
|             assert reloaded.info["xmp"] == b"XMP test" |             assert reloaded.info["xmp"] == b"XMP test" | ||||||
| 
 | 
 | ||||||
|         im.info["xmp"] = b"1" * 65504 |             # Check that XMP is not saved from image info | ||||||
|         im.save(f) |             reloaded.save(f) | ||||||
|  | 
 | ||||||
|  |         with Image.open(f) as reloaded: | ||||||
|  |             assert "xmp" not in reloaded.info | ||||||
|  | 
 | ||||||
|  |         im.save(f, xmp=b"1" * 65504) | ||||||
|         with Image.open(f) as reloaded: |         with Image.open(f) as reloaded: | ||||||
|             assert reloaded.info["xmp"] == b"1" * 65504 |             assert reloaded.info["xmp"] == b"1" * 65504 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -311,3 +311,15 @@ def test_save_all() -> None: | ||||||
|     # Test that a single frame image will not be saved as an MPO |     # Test that a single frame image will not be saved as an MPO | ||||||
|     jpg = roundtrip(im, save_all=True) |     jpg = roundtrip(im, save_all=True) | ||||||
|     assert "mp" not in jpg.info |     assert "mp" not in jpg.info | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_save_xmp() -> None: | ||||||
|  |     im = Image.new("RGB", (1, 1)) | ||||||
|  |     im2 = Image.new("RGB", (1, 1), "#f00") | ||||||
|  |     im2.encoderinfo = {"xmp": b"Second frame"} | ||||||
|  |     im_reloaded = roundtrip(im, xmp=b"First frame", save_all=True, append_images=[im2]) | ||||||
|  | 
 | ||||||
|  |     assert im_reloaded.info["xmp"] == b"First frame" | ||||||
|  | 
 | ||||||
|  |     im_reloaded.seek(1) | ||||||
|  |     assert im_reloaded.info["xmp"] == b"Second frame" | ||||||
|  |  | ||||||
|  | @ -810,20 +810,15 @@ class TestFilePng: | ||||||
|                 im.seek(1) |                 im.seek(1) | ||||||
| 
 | 
 | ||||||
|     @pytest.mark.parametrize("buffer", (True, False)) |     @pytest.mark.parametrize("buffer", (True, False)) | ||||||
|     def test_save_stdout(self, buffer: bool) -> None: |     def test_save_stdout(self, buffer: bool, monkeypatch: pytest.MonkeyPatch) -> None: | ||||||
|         old_stdout = sys.stdout |  | ||||||
| 
 |  | ||||||
|         b = BytesIO() |         b = BytesIO() | ||||||
|         mystdout: TextIOWrapper | BytesIO = TextIOWrapper(b) if buffer else b |         mystdout: TextIOWrapper | BytesIO = TextIOWrapper(b) if buffer else b | ||||||
| 
 | 
 | ||||||
|         sys.stdout = mystdout |         monkeypatch.setattr(sys, "stdout", mystdout) | ||||||
| 
 | 
 | ||||||
|         with Image.open(TEST_PNG_FILE) as im: |         with Image.open(TEST_PNG_FILE) as im: | ||||||
|             im.save(sys.stdout, "PNG") |             im.save(sys.stdout, "PNG") | ||||||
| 
 | 
 | ||||||
|         # Reset stdout |  | ||||||
|         sys.stdout = old_stdout |  | ||||||
| 
 |  | ||||||
|         with Image.open(b) as reloaded: |         with Image.open(b) as reloaded: | ||||||
|             assert_image_equal_tofile(reloaded, TEST_PNG_FILE) |             assert_image_equal_tofile(reloaded, TEST_PNG_FILE) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -368,19 +368,14 @@ def test_mimetypes(tmp_path: Path) -> None: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @pytest.mark.parametrize("buffer", (True, False)) | @pytest.mark.parametrize("buffer", (True, False)) | ||||||
| def test_save_stdout(buffer: bool) -> None: | def test_save_stdout(buffer: bool, monkeypatch: pytest.MonkeyPatch) -> None: | ||||||
|     old_stdout = sys.stdout |  | ||||||
| 
 |  | ||||||
|     b = BytesIO() |     b = BytesIO() | ||||||
|     mystdout: TextIOWrapper | BytesIO = TextIOWrapper(b) if buffer else b |     mystdout: TextIOWrapper | BytesIO = TextIOWrapper(b) if buffer else b | ||||||
| 
 | 
 | ||||||
|     sys.stdout = mystdout |     monkeypatch.setattr(sys, "stdout", mystdout) | ||||||
| 
 | 
 | ||||||
|     with Image.open(TEST_FILE) as im: |     with Image.open(TEST_FILE) as im: | ||||||
|         im.save(sys.stdout, "PPM") |         im.save(sys.stdout, "PPM") | ||||||
| 
 | 
 | ||||||
|     # Reset stdout |  | ||||||
|     sys.stdout = old_stdout |  | ||||||
| 
 |  | ||||||
|     with Image.open(b) as reloaded: |     with Image.open(b) as reloaded: | ||||||
|         assert_image_equal_tofile(reloaded, TEST_FILE) |         assert_image_equal_tofile(reloaded, TEST_FILE) | ||||||
|  |  | ||||||
|  | @ -1675,6 +1675,9 @@ def test_continuous_horizontal_edges_polygon() -> None: | ||||||
| def test_discontiguous_corners_polygon() -> None: | def test_discontiguous_corners_polygon() -> None: | ||||||
|     img, draw = create_base_image_draw((84, 68)) |     img, draw = create_base_image_draw((84, 68)) | ||||||
|     draw.polygon(((1, 21), (34, 4), (71, 1), (38, 18)), BLACK) |     draw.polygon(((1, 21), (34, 4), (71, 1), (38, 18)), BLACK) | ||||||
|  |     draw.polygon( | ||||||
|  |         ((82, 29), (82, 26), (82, 24), (67, 22), (52, 29), (52, 15), (67, 22)), BLACK | ||||||
|  |     ) | ||||||
|     draw.polygon(((71, 44), (38, 27), (1, 24)), BLACK) |     draw.polygon(((71, 44), (38, 27), (1, 24)), BLACK) | ||||||
|     draw.polygon( |     draw.polygon( | ||||||
|         ((38, 66), (5, 49), (77, 49), (47, 66), (82, 63), (82, 47), (1, 47), (1, 63)), |         ((38, 66), (5, 49), (77, 49), (47, 66), (82, 63), (82, 47), (1, 47), (1, 63)), | ||||||
|  |  | ||||||
|  | @ -93,6 +93,19 @@ class TestImageFile: | ||||||
|             assert p.image is not None |             assert p.image is not None | ||||||
|             assert (48, 48) == p.image.size |             assert (48, 48) == p.image.size | ||||||
| 
 | 
 | ||||||
|  |     @pytest.mark.filterwarnings("ignore:Corrupt EXIF data") | ||||||
|  |     def test_incremental_tiff(self) -> None: | ||||||
|  |         with ImageFile.Parser() as p: | ||||||
|  |             with open("Tests/images/hopper.tif", "rb") as f: | ||||||
|  |                 p.feed(f.read(1024)) | ||||||
|  | 
 | ||||||
|  |                 # Check that insufficient data was given in the first feed | ||||||
|  |                 assert not p.image | ||||||
|  | 
 | ||||||
|  |                 p.feed(f.read()) | ||||||
|  |             assert p.image is not None | ||||||
|  |             assert (128, 128) == p.image.size | ||||||
|  | 
 | ||||||
|     @skip_unless_feature("webp") |     @skip_unless_feature("webp") | ||||||
|     def test_incremental_webp(self) -> None: |     def test_incremental_webp(self) -> None: | ||||||
|         with ImageFile.Parser() as p: |         with ImageFile.Parser() as p: | ||||||
|  |  | ||||||
|  | @ -76,6 +76,17 @@ def test_pickle_image( | ||||||
|     helper_pickle_file(tmp_path, protocol, test_file, test_mode) |     helper_pickle_file(tmp_path, protocol, test_file, test_mode) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def test_pickle_jpeg() -> None: | ||||||
|  |     # Arrange | ||||||
|  |     with Image.open("Tests/images/hopper.jpg") as image: | ||||||
|  |         # Act: roundtrip | ||||||
|  |         unpickled_image = pickle.loads(pickle.dumps(image)) | ||||||
|  | 
 | ||||||
|  |     # Assert | ||||||
|  |     assert len(unpickled_image.layer) == 3 | ||||||
|  |     assert unpickled_image.layers == 3 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def test_pickle_la_mode_with_palette(tmp_path: Path) -> None: | def test_pickle_la_mode_with_palette(tmp_path: Path) -> None: | ||||||
|     # Arrange |     # Arrange | ||||||
|     filename = str(tmp_path / "temp.pkl") |     filename = str(tmp_path / "temp.pkl") | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -344,7 +344,7 @@ class pil_build_ext(build_ext): | ||||||
|             for x in ("raqm", "fribidi") |             for x in ("raqm", "fribidi") | ||||||
|         ] |         ] | ||||||
|         + [ |         + [ | ||||||
|             ("disable-platform-guessing", None, "Disable platform guessing on Linux"), |             ("disable-platform-guessing", None, "Disable platform guessing"), | ||||||
|             ("debug", None, "Debug logging"), |             ("debug", None, "Debug logging"), | ||||||
|         ] |         ] | ||||||
|         + [("add-imaging-libs=", None, "Add libs to _imaging build")] |         + [("add-imaging-libs=", None, "Add libs to _imaging build")] | ||||||
|  |  | ||||||
|  | @ -274,7 +274,7 @@ class BlpImageFile(ImageFile.ImageFile): | ||||||
|             raise BLPFormatError(msg) |             raise BLPFormatError(msg) | ||||||
| 
 | 
 | ||||||
|         self._mode = "RGBA" if self._blp_alpha_depth else "RGB" |         self._mode = "RGBA" if self._blp_alpha_depth else "RGB" | ||||||
|         self.tile = [ImageFile._Tile(decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))] |         self.tile = [ImageFile._Tile(decoder, (0, 0) + self.size, 0, self.mode)] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class _BLPBaseDecoder(ImageFile.PyDecoder): | class _BLPBaseDecoder(ImageFile.PyDecoder): | ||||||
|  |  | ||||||
|  | @ -561,9 +561,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | ||||||
|         + struct.pack("<4I", *rgba_mask)  # dwRGBABitMask |         + struct.pack("<4I", *rgba_mask)  # dwRGBABitMask | ||||||
|         + struct.pack("<5I", DDSCAPS.TEXTURE, 0, 0, 0, 0) |         + struct.pack("<5I", DDSCAPS.TEXTURE, 0, 0, 0, 0) | ||||||
|     ) |     ) | ||||||
|     ImageFile._save( |     ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, rawmode)]) | ||||||
|         im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))] |  | ||||||
|     ) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _accept(prefix: bytes) -> bool: | def _accept(prefix: bytes) -> bool: | ||||||
|  |  | ||||||
|  | @ -456,7 +456,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes, eps: int = 1) - | ||||||
|     if hasattr(fp, "flush"): |     if hasattr(fp, "flush"): | ||||||
|         fp.flush() |         fp.flush() | ||||||
| 
 | 
 | ||||||
|     ImageFile._save(im, fp, [ImageFile._Tile("eps", (0, 0) + im.size, 0, None)]) |     ImageFile._save(im, fp, [ImageFile._Tile("eps", (0, 0) + im.size)]) | ||||||
| 
 | 
 | ||||||
|     fp.write(b"\n%%%%EndBinary\n") |     fp.write(b"\n%%%%EndBinary\n") | ||||||
|     fp.write(b"grestore end\n") |     fp.write(b"grestore end\n") | ||||||
|  |  | ||||||
|  | @ -164,7 +164,7 @@ class FliImageFile(ImageFile.ImageFile): | ||||||
|         framesize = i32(s) |         framesize = i32(s) | ||||||
| 
 | 
 | ||||||
|         self.decodermaxblock = framesize |         self.decodermaxblock = framesize | ||||||
|         self.tile = [ImageFile._Tile("fli", (0, 0) + self.size, self.__offset, None)] |         self.tile = [ImageFile._Tile("fli", (0, 0) + self.size, self.__offset)] | ||||||
| 
 | 
 | ||||||
|         self.__offset += framesize |         self.__offset += framesize | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -171,7 +171,7 @@ class FpxImageFile(ImageFile.ImageFile): | ||||||
|                         "raw", |                         "raw", | ||||||
|                         (x, y, x1, y1), |                         (x, y, x1, y1), | ||||||
|                         i32(s, i) + 28, |                         i32(s, i) + 28, | ||||||
|                         (self.rawmode,), |                         self.rawmode, | ||||||
|                     ) |                     ) | ||||||
|                 ) |                 ) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -96,7 +96,7 @@ class FtexImageFile(ImageFile.ImageFile): | ||||||
|             self._mode = "RGBA" |             self._mode = "RGBA" | ||||||
|             self.tile = [ImageFile._Tile("bcn", (0, 0) + self.size, 0, (1,))] |             self.tile = [ImageFile._Tile("bcn", (0, 0) + self.size, 0, (1,))] | ||||||
|         elif format == Format.UNCOMPRESSED: |         elif format == Format.UNCOMPRESSED: | ||||||
|             self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))] |             self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, "RGB")] | ||||||
|         else: |         else: | ||||||
|             msg = f"Invalid texture compression format: {repr(format)}" |             msg = f"Invalid texture compression format: {repr(format)}" | ||||||
|             raise ValueError(msg) |             raise ValueError(msg) | ||||||
|  |  | ||||||
|  | @ -76,7 +76,7 @@ class GdImageFile(ImageFile.ImageFile): | ||||||
|                 "raw", |                 "raw", | ||||||
|                 (0, 0) + self.size, |                 (0, 0) + self.size, | ||||||
|                 7 + true_color_offset + 4 + 256 * 4, |                 7 + true_color_offset + 4 + 256 * 4, | ||||||
|                 ("L", 0, 1), |                 "L", | ||||||
|             ) |             ) | ||||||
|         ] |         ] | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -736,7 +736,7 @@ class Image: | ||||||
| 
 | 
 | ||||||
|     def __setstate__(self, state: list[Any]) -> None: |     def __setstate__(self, state: list[Any]) -> None: | ||||||
|         Image.__init__(self) |         Image.__init__(self) | ||||||
|         info, mode, size, palette, data = state |         info, mode, size, palette, data = state[:5] | ||||||
|         self.info = info |         self.info = info | ||||||
|         self._mode = mode |         self._mode = mode | ||||||
|         self._size = size |         self._size = size | ||||||
|  | @ -2499,7 +2499,7 @@ class Image: | ||||||
|         self._ensure_mutable() |         self._ensure_mutable() | ||||||
| 
 | 
 | ||||||
|         save_all = params.pop("save_all", False) |         save_all = params.pop("save_all", False) | ||||||
|         self.encoderinfo = params |         self.encoderinfo = {**getattr(self, "encoderinfo", {}), **params} | ||||||
|         self.encoderconfig: tuple[Any, ...] = () |         self.encoderconfig: tuple[Any, ...] = () | ||||||
| 
 | 
 | ||||||
|         preinit() |         preinit() | ||||||
|  | @ -2546,6 +2546,11 @@ class Image: | ||||||
|                 except PermissionError: |                 except PermissionError: | ||||||
|                     pass |                     pass | ||||||
|             raise |             raise | ||||||
|  |         finally: | ||||||
|  |             try: | ||||||
|  |                 del self.encoderinfo | ||||||
|  |             except AttributeError: | ||||||
|  |                 pass | ||||||
|         if open_fp: |         if open_fp: | ||||||
|             fp.close() |             fp.close() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -101,8 +101,8 @@ def _tilesort(t: _Tile) -> int: | ||||||
| class _Tile(NamedTuple): | class _Tile(NamedTuple): | ||||||
|     codec_name: str |     codec_name: str | ||||||
|     extents: tuple[int, int, int, int] | None |     extents: tuple[int, int, int, int] | None | ||||||
|     offset: int |     offset: int = 0 | ||||||
|     args: tuple[Any, ...] | str | None |     args: tuple[Any, ...] | str | None = None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # | # | ||||||
|  |  | ||||||
|  | @ -104,28 +104,17 @@ def grab( | ||||||
| 
 | 
 | ||||||
| def grabclipboard() -> Image.Image | list[str] | None: | def grabclipboard() -> Image.Image | list[str] | None: | ||||||
|     if sys.platform == "darwin": |     if sys.platform == "darwin": | ||||||
|         fh, filepath = tempfile.mkstemp(".png") |         p = subprocess.run( | ||||||
|         os.close(fh) |             ["osascript", "-e", "get the clipboard as «class PNGf»"], | ||||||
|         commands = [ |             capture_output=True, | ||||||
|             'set theFile to (open for access POSIX file "' |         ) | ||||||
|             + filepath |         if p.returncode != 0: | ||||||
|             + '" with write permission)', |             return None | ||||||
|             "try", |  | ||||||
|             "    write (the clipboard as «class PNGf») to theFile", |  | ||||||
|             "end try", |  | ||||||
|             "close access theFile", |  | ||||||
|         ] |  | ||||||
|         script = ["osascript"] |  | ||||||
|         for command in commands: |  | ||||||
|             script += ["-e", command] |  | ||||||
|         subprocess.call(script) |  | ||||||
| 
 | 
 | ||||||
|         im = None |         import binascii | ||||||
|         if os.stat(filepath).st_size != 0: | 
 | ||||||
|             im = Image.open(filepath) |         data = io.BytesIO(binascii.unhexlify(p.stdout[11:-3])) | ||||||
|             im.load() |         return Image.open(data) | ||||||
|         os.unlink(filepath) |  | ||||||
|         return im |  | ||||||
|     elif sys.platform == "win32": |     elif sys.platform == "win32": | ||||||
|         fmt, data = Image.core.grabclipboard_win32() |         fmt, data = Image.core.grabclipboard_win32() | ||||||
|         if fmt == "file":  # CF_HDROP |         if fmt == "file":  # CF_HDROP | ||||||
|  |  | ||||||
|  | @ -698,10 +698,11 @@ def exif_transpose(image: Image.Image, *, in_place: bool = False) -> Image.Image | ||||||
|         8: Image.Transpose.ROTATE_90, |         8: Image.Transpose.ROTATE_90, | ||||||
|     }.get(orientation) |     }.get(orientation) | ||||||
|     if method is not None: |     if method is not None: | ||||||
|         transposed_image = image.transpose(method) |  | ||||||
|         if in_place: |         if in_place: | ||||||
|             image.im = transposed_image.im |             image.im = image.im.transpose(method) | ||||||
|             image._size = transposed_image._size |             image._size = image.im.size | ||||||
|  |         else: | ||||||
|  |             transposed_image = image.transpose(method) | ||||||
|         exif_image = image if in_place else transposed_image |         exif_image = image if in_place else transposed_image | ||||||
| 
 | 
 | ||||||
|         exif = exif_image.getexif() |         exif = exif_image.getexif() | ||||||
|  |  | ||||||
|  | @ -62,7 +62,7 @@ class ImtImageFile(ImageFile.ImageFile): | ||||||
|                         "raw", |                         "raw", | ||||||
|                         (0, 0) + self.size, |                         (0, 0) + self.size, | ||||||
|                         self.fp.tell() - len(buffer), |                         self.fp.tell() - len(buffer), | ||||||
|                         (self.mode, 0, 1), |                         self.mode, | ||||||
|                     ) |                     ) | ||||||
|                 ] |                 ] | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -401,6 +401,13 @@ class JpegImageFile(ImageFile.ImageFile): | ||||||
|             return getattr(self, "_" + name) |             return getattr(self, "_" + name) | ||||||
|         raise AttributeError(name) |         raise AttributeError(name) | ||||||
| 
 | 
 | ||||||
|  |     def __getstate__(self) -> list[Any]: | ||||||
|  |         return super().__getstate__() + [self.layers, self.layer] | ||||||
|  | 
 | ||||||
|  |     def __setstate__(self, state: list[Any]) -> None: | ||||||
|  |         super().__setstate__(state) | ||||||
|  |         self.layers, self.layer = state[5:] | ||||||
|  | 
 | ||||||
|     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 | ||||||
|  | @ -758,7 +765,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | ||||||
|     extra = info.get("extra", b"") |     extra = info.get("extra", b"") | ||||||
| 
 | 
 | ||||||
|     MAX_BYTES_IN_MARKER = 65533 |     MAX_BYTES_IN_MARKER = 65533 | ||||||
|     xmp = info.get("xmp", im.info.get("xmp")) |     xmp = info.get("xmp") | ||||||
|     if xmp: |     if xmp: | ||||||
|         overhead_len = 29  # b"http://ns.adobe.com/xap/1.0/\x00" |         overhead_len = 29  # b"http://ns.adobe.com/xap/1.0/\x00" | ||||||
|         max_data_bytes_in_marker = MAX_BYTES_IN_MARKER - overhead_len |         max_data_bytes_in_marker = MAX_BYTES_IN_MARKER - overhead_len | ||||||
|  |  | ||||||
|  | @ -70,9 +70,9 @@ class MspImageFile(ImageFile.ImageFile): | ||||||
|         self._size = i16(s, 4), i16(s, 6) |         self._size = i16(s, 4), i16(s, 6) | ||||||
| 
 | 
 | ||||||
|         if s[:4] == b"DanM": |         if s[:4] == b"DanM": | ||||||
|             self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 32, ("1", 0, 1))] |             self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 32, "1")] | ||||||
|         else: |         else: | ||||||
|             self.tile = [ImageFile._Tile("MSP", (0, 0) + self.size, 32, None)] |             self.tile = [ImageFile._Tile("MSP", (0, 0) + self.size, 32)] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class MspDecoder(ImageFile.PyDecoder): | class MspDecoder(ImageFile.PyDecoder): | ||||||
|  | @ -188,7 +188,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | ||||||
|         fp.write(o16(h)) |         fp.write(o16(h)) | ||||||
| 
 | 
 | ||||||
|     # image body |     # image body | ||||||
|     ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 32, ("1", 0, 1))]) |     ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 32, "1")]) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # | # | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ class PcdImageFile(ImageFile.ImageFile): | ||||||
| 
 | 
 | ||||||
|         self._mode = "RGB" |         self._mode = "RGB" | ||||||
|         self._size = 768, 512  # FIXME: not correct for rotated images! |         self._size = 768, 512  # FIXME: not correct for rotated images! | ||||||
|         self.tile = [ImageFile._Tile("pcd", (0, 0) + self.size, 96 * 2048, None)] |         self.tile = [ImageFile._Tile("pcd", (0, 0) + self.size, 96 * 2048)] | ||||||
| 
 | 
 | ||||||
|     def load_end(self) -> None: |     def load_end(self) -> None: | ||||||
|         if self.tile_post_rotate: |         if self.tile_post_rotate: | ||||||
|  |  | ||||||
|  | @ -61,9 +61,7 @@ class PixarImageFile(ImageFile.ImageFile): | ||||||
|         # FIXME: to be continued... |         # FIXME: to be continued... | ||||||
| 
 | 
 | ||||||
|         # create tile descriptor (assuming "dumped") |         # create tile descriptor (assuming "dumped") | ||||||
|         self.tile = [ |         self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 1024, self.mode)] | ||||||
|             ImageFile._Tile("raw", (0, 0) + self.size, 1024, (self.mode, 0, 1)) |  | ||||||
|         ] |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # | # | ||||||
|  |  | ||||||
|  | @ -33,7 +33,7 @@ class QoiImageFile(ImageFile.ImageFile): | ||||||
|         self._mode = "RGB" if channels == 3 else "RGBA" |         self._mode = "RGB" if channels == 3 else "RGBA" | ||||||
| 
 | 
 | ||||||
|         self.fp.seek(1, os.SEEK_CUR)  # colorspace |         self.fp.seek(1, os.SEEK_CUR)  # colorspace | ||||||
|         self.tile = [ImageFile._Tile("qoi", (0, 0) + self._size, self.fp.tell(), None)] |         self.tile = [ImageFile._Tile("qoi", (0, 0) + self._size, self.fp.tell())] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class QoiDecoder(ImageFile.PyDecoder): | class QoiDecoder(ImageFile.PyDecoder): | ||||||
|  |  | ||||||
|  | @ -156,9 +156,7 @@ class SpiderImageFile(ImageFile.ImageFile): | ||||||
|             self.rawmode = "F;32F" |             self.rawmode = "F;32F" | ||||||
|         self._mode = "F" |         self._mode = "F" | ||||||
| 
 | 
 | ||||||
|         self.tile = [ |         self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, offset, self.rawmode)] | ||||||
|             ImageFile._Tile("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1)) |  | ||||||
|         ] |  | ||||||
|         self._fp = self.fp  # FIXME: hack |         self._fp = self.fp  # FIXME: hack | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|  | @ -286,9 +284,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | ||||||
|     fp.writelines(hdr) |     fp.writelines(hdr) | ||||||
| 
 | 
 | ||||||
|     rawmode = "F;32NF"  # 32-bit native floating point |     rawmode = "F;32NF"  # 32-bit native floating point | ||||||
|     ImageFile._save( |     ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, rawmode)]) | ||||||
|         im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))] |  | ||||||
|     ) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _save_spider(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | def _save_spider(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | ||||||
|  |  | ||||||
|  | @ -1436,8 +1436,12 @@ class TiffImageFile(ImageFile.ImageFile): | ||||||
|         logger.debug("- YCbCr subsampling: %s", self.tag_v2.get(YCBCRSUBSAMPLING)) |         logger.debug("- YCbCr subsampling: %s", self.tag_v2.get(YCBCRSUBSAMPLING)) | ||||||
| 
 | 
 | ||||||
|         # size |         # size | ||||||
|         xsize = self.tag_v2.get(IMAGEWIDTH) |         try: | ||||||
|         ysize = self.tag_v2.get(IMAGELENGTH) |             xsize = self.tag_v2[IMAGEWIDTH] | ||||||
|  |             ysize = self.tag_v2[IMAGELENGTH] | ||||||
|  |         except KeyError as e: | ||||||
|  |             msg = "Missing dimensions" | ||||||
|  |             raise TypeError(msg) from e | ||||||
|         if not isinstance(xsize, int) or not isinstance(ysize, int): |         if not isinstance(xsize, int) or not isinstance(ysize, int): | ||||||
|             msg = "Invalid dimensions" |             msg = "Invalid dimensions" | ||||||
|             raise ValueError(msg) |             raise ValueError(msg) | ||||||
|  | @ -1918,7 +1922,9 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | ||||||
|                 if not getattr(Image.core, "libtiff_support_custom_tags", False): |                 if not getattr(Image.core, "libtiff_support_custom_tags", False): | ||||||
|                     continue |                     continue | ||||||
| 
 | 
 | ||||||
|                 if tag in ifd.tagtype: |                 if tag in TiffTags.TAGS_V2_GROUPS: | ||||||
|  |                     types[tag] = TiffTags.LONG8 | ||||||
|  |                 elif tag in ifd.tagtype: | ||||||
|                     types[tag] = ifd.tagtype[tag] |                     types[tag] = ifd.tagtype[tag] | ||||||
|                 elif not (isinstance(value, (int, float, str, bytes))): |                 elif not (isinstance(value, (int, float, str, bytes))): | ||||||
|                     continue |                     continue | ||||||
|  |  | ||||||
|  | @ -74,9 +74,7 @@ class XVThumbImageFile(ImageFile.ImageFile): | ||||||
|         self.palette = ImagePalette.raw("RGB", PALETTE) |         self.palette = ImagePalette.raw("RGB", PALETTE) | ||||||
| 
 | 
 | ||||||
|         self.tile = [ |         self.tile = [ | ||||||
|             ImageFile._Tile( |             ImageFile._Tile("raw", (0, 0) + self.size, self.fp.tell(), self.mode) | ||||||
|                 "raw", (0, 0) + self.size, self.fp.tell(), (self.mode, 0, 1) |  | ||||||
|             ) |  | ||||||
|         ] |         ] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -67,7 +67,7 @@ class XbmImageFile(ImageFile.ImageFile): | ||||||
|         self._mode = "1" |         self._mode = "1" | ||||||
|         self._size = xsize, ysize |         self._size = xsize, ysize | ||||||
| 
 | 
 | ||||||
|         self.tile = [ImageFile._Tile("xbm", (0, 0) + self.size, m.end(), None)] |         self.tile = [ImageFile._Tile("xbm", (0, 0) + self.size, m.end())] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | ||||||
|  | @ -85,7 +85,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | ||||||
| 
 | 
 | ||||||
|     fp.write(b"static char im_bits[] = {\n") |     fp.write(b"static char im_bits[] = {\n") | ||||||
| 
 | 
 | ||||||
|     ImageFile._save(im, fp, [ImageFile._Tile("xbm", (0, 0) + im.size, 0, None)]) |     ImageFile._save(im, fp, [ImageFile._Tile("xbm", (0, 0) + im.size)]) | ||||||
| 
 | 
 | ||||||
|     fp.write(b"};\n") |     fp.write(b"};\n") | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -104,9 +104,7 @@ class XpmImageFile(ImageFile.ImageFile): | ||||||
|         self._mode = "P" |         self._mode = "P" | ||||||
|         self.palette = ImagePalette.raw("RGB", b"".join(palette)) |         self.palette = ImagePalette.raw("RGB", b"".join(palette)) | ||||||
| 
 | 
 | ||||||
|         self.tile = [ |         self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, self.fp.tell(), "P")] | ||||||
|             ImageFile._Tile("raw", (0, 0) + self.size, self.fp.tell(), ("P", 0, 1)) |  | ||||||
|         ] |  | ||||||
| 
 | 
 | ||||||
|     def load_read(self, read_bytes: int) -> bytes: |     def load_read(self, read_bytes: int) -> bytes: | ||||||
|         # |         # | ||||||
|  |  | ||||||
|  | @ -346,10 +346,10 @@ pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) { | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Py_BEGIN_ALLOW_THREADS |     Py_BEGIN_ALLOW_THREADS; | ||||||
| 
 | 
 | ||||||
|         // transform color channels only
 |     // transform color channels only
 | ||||||
|         for (i = 0; i < im->ysize; i++) { |     for (i = 0; i < im->ysize; i++) { | ||||||
|         cmsDoTransform(hTransform, im->image[i], imOut->image[i], im->xsize); |         cmsDoTransform(hTransform, im->image[i], imOut->image[i], im->xsize); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -362,9 +362,9 @@ pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) { | ||||||
|     // enough available on all platforms, so we polyfill it here for now.
 |     // enough available on all platforms, so we polyfill it here for now.
 | ||||||
|     pyCMScopyAux(hTransform, imOut, im); |     pyCMScopyAux(hTransform, imOut, im); | ||||||
| 
 | 
 | ||||||
|     Py_END_ALLOW_THREADS |     Py_END_ALLOW_THREADS; | ||||||
| 
 | 
 | ||||||
|         return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static cmsHTRANSFORM | static cmsHTRANSFORM | ||||||
|  | @ -378,17 +378,17 @@ _buildTransform( | ||||||
| ) { | ) { | ||||||
|     cmsHTRANSFORM hTransform; |     cmsHTRANSFORM hTransform; | ||||||
| 
 | 
 | ||||||
|     Py_BEGIN_ALLOW_THREADS |     Py_BEGIN_ALLOW_THREADS; | ||||||
| 
 | 
 | ||||||
|         /* create the transform */ |     /* create the transform */ | ||||||
|         hTransform = cmsCreateTransform( |     hTransform = cmsCreateTransform( | ||||||
|             hInputProfile, |         hInputProfile, | ||||||
|             findLCMStype(sInMode), |         findLCMStype(sInMode), | ||||||
|             hOutputProfile, |         hOutputProfile, | ||||||
|             findLCMStype(sOutMode), |         findLCMStype(sOutMode), | ||||||
|             iRenderingIntent, |         iRenderingIntent, | ||||||
|             cmsFLAGS |         cmsFLAGS | ||||||
|         ); |     ); | ||||||
| 
 | 
 | ||||||
|     Py_END_ALLOW_THREADS; |     Py_END_ALLOW_THREADS; | ||||||
| 
 | 
 | ||||||
|  | @ -412,19 +412,19 @@ _buildProofTransform( | ||||||
| ) { | ) { | ||||||
|     cmsHTRANSFORM hTransform; |     cmsHTRANSFORM hTransform; | ||||||
| 
 | 
 | ||||||
|     Py_BEGIN_ALLOW_THREADS |     Py_BEGIN_ALLOW_THREADS; | ||||||
| 
 | 
 | ||||||
|         /* create the transform */ |     /* create the transform */ | ||||||
|         hTransform = cmsCreateProofingTransform( |     hTransform = cmsCreateProofingTransform( | ||||||
|             hInputProfile, |         hInputProfile, | ||||||
|             findLCMStype(sInMode), |         findLCMStype(sInMode), | ||||||
|             hOutputProfile, |         hOutputProfile, | ||||||
|             findLCMStype(sOutMode), |         findLCMStype(sOutMode), | ||||||
|             hProofProfile, |         hProofProfile, | ||||||
|             iRenderingIntent, |         iRenderingIntent, | ||||||
|             iProofIntent, |         iProofIntent, | ||||||
|             cmsFLAGS |         cmsFLAGS | ||||||
|         ); |     ); | ||||||
| 
 | 
 | ||||||
|     Py_END_ALLOW_THREADS; |     Py_END_ALLOW_THREADS; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -690,24 +690,26 @@ PyImaging_CreateWindowWin32(PyObject *self, PyObject *args) { | ||||||
|     SetWindowLongPtr(wnd, 0, (LONG_PTR)callback); |     SetWindowLongPtr(wnd, 0, (LONG_PTR)callback); | ||||||
|     SetWindowLongPtr(wnd, sizeof(callback), (LONG_PTR)PyThreadState_Get()); |     SetWindowLongPtr(wnd, sizeof(callback), (LONG_PTR)PyThreadState_Get()); | ||||||
| 
 | 
 | ||||||
|     Py_BEGIN_ALLOW_THREADS ShowWindow(wnd, SW_SHOWNORMAL); |     Py_BEGIN_ALLOW_THREADS; | ||||||
|  |     ShowWindow(wnd, SW_SHOWNORMAL); | ||||||
|     SetForegroundWindow(wnd); /* to make sure it's visible */ |     SetForegroundWindow(wnd); /* to make sure it's visible */ | ||||||
|     Py_END_ALLOW_THREADS |     Py_END_ALLOW_THREADS; | ||||||
| 
 | 
 | ||||||
|         return Py_BuildValue(F_HANDLE, wnd); |     return Py_BuildValue(F_HANDLE, wnd); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| PyObject * | PyObject * | ||||||
| PyImaging_EventLoopWin32(PyObject *self, PyObject *args) { | PyImaging_EventLoopWin32(PyObject *self, PyObject *args) { | ||||||
|     MSG msg; |     MSG msg; | ||||||
| 
 | 
 | ||||||
|     Py_BEGIN_ALLOW_THREADS while (mainloop && GetMessage(&msg, NULL, 0, 0)) { |     Py_BEGIN_ALLOW_THREADS; | ||||||
|  |     while (mainloop && GetMessage(&msg, NULL, 0, 0)) { | ||||||
|         TranslateMessage(&msg); |         TranslateMessage(&msg); | ||||||
|         DispatchMessage(&msg); |         DispatchMessage(&msg); | ||||||
|     } |     } | ||||||
|     Py_END_ALLOW_THREADS |     Py_END_ALLOW_THREADS; | ||||||
| 
 | 
 | ||||||
|         Py_INCREF(Py_None); |     Py_INCREF(Py_None); | ||||||
|     return Py_None; |     return Py_None; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -736,7 +736,7 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) { | ||||||
|             } |             } | ||||||
|             if (tag_type) { |             if (tag_type) { | ||||||
|                 int type_int = PyLong_AsLong(tag_type); |                 int type_int = PyLong_AsLong(tag_type); | ||||||
|                 if (type_int >= TIFF_BYTE && type_int <= TIFF_DOUBLE) { |                 if (type_int >= TIFF_BYTE && type_int <= TIFF_LONG8) { | ||||||
|                     type = (TIFFDataType)type_int; |                     type = (TIFFDataType)type_int; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -929,7 +929,7 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) { | ||||||
|                 ); |                 ); | ||||||
|             } else if (type == TIFF_LONG) { |             } else if (type == TIFF_LONG) { | ||||||
|                 status = ImagingLibTiffSetField( |                 status = ImagingLibTiffSetField( | ||||||
|                     &encoder->state, (ttag_t)key_int, PyLong_AsLongLong(value) |                     &encoder->state, (ttag_t)key_int, (UINT32)PyLong_AsLong(value) | ||||||
|                 ); |                 ); | ||||||
|             } else if (type == TIFF_SSHORT) { |             } else if (type == TIFF_SSHORT) { | ||||||
|                 status = ImagingLibTiffSetField( |                 status = ImagingLibTiffSetField( | ||||||
|  | @ -959,6 +959,10 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) { | ||||||
|                 status = ImagingLibTiffSetField( |                 status = ImagingLibTiffSetField( | ||||||
|                     &encoder->state, (ttag_t)key_int, (FLOAT64)PyFloat_AsDouble(value) |                     &encoder->state, (ttag_t)key_int, (FLOAT64)PyFloat_AsDouble(value) | ||||||
|                 ); |                 ); | ||||||
|  |             } else if (type == TIFF_LONG8) { | ||||||
|  |                 status = ImagingLibTiffSetField( | ||||||
|  |                     &encoder->state, (ttag_t)key_int, (uint64_t)PyLong_AsLongLong(value) | ||||||
|  |                 ); | ||||||
|             } else { |             } else { | ||||||
|                 TRACE( |                 TRACE( | ||||||
|                     ("Unhandled type for key %d : %s \n", |                     ("Unhandled type for key %d : %s \n", | ||||||
|  |  | ||||||
|  | @ -501,7 +501,8 @@ polygon_generic( | ||||||
|                     // Needed to draw consistent polygons
 |                     // Needed to draw consistent polygons
 | ||||||
|                     xx[j] = xx[j - 1]; |                     xx[j] = xx[j - 1]; | ||||||
|                     j++; |                     j++; | ||||||
|                 } else if (current->dx != 0 && roundf(xx[j - 1]) == xx[j - 1]) { |                 } else if (current->dx != 0 && j % 2 == 1 && | ||||||
|  |                            roundf(xx[j - 1]) == xx[j - 1]) { | ||||||
|                     // Connect discontiguous corners
 |                     // Connect discontiguous corners
 | ||||||
|                     for (k = 0; k < i; k++) { |                     for (k = 0; k < i; k++) { | ||||||
|                         Edge *other_edge = edge_table[k]; |                         Edge *other_edge = edge_table[k]; | ||||||
|  | @ -510,10 +511,8 @@ polygon_generic( | ||||||
|                             continue; |                             continue; | ||||||
|                         } |                         } | ||||||
|                         // Check if the two edges join to make a corner
 |                         // Check if the two edges join to make a corner
 | ||||||
|                         if (((ymin == current->ymin && ymin == other_edge->ymin) || |                         if (xx[j - 1] == | ||||||
|                              (ymin == current->ymax && ymin == other_edge->ymax)) && |                             (ymin - other_edge->y0) * other_edge->dx + other_edge->x0) { | ||||||
|                             xx[j - 1] == (ymin - other_edge->y0) * other_edge->dx + |  | ||||||
|                                              other_edge->x0) { |  | ||||||
|                             // Determine points from the edges on the next row
 |                             // Determine points from the edges on the next row
 | ||||||
|                             // Or if this is the last row, check the previous row
 |                             // Or if this is the last row, check the previous row
 | ||||||
|                             int offset = ymin == ymax ? -1 : 1; |                             int offset = ymin == ymax ? -1 : 1; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user