diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index a34cb2cb923..c261cfb97bb 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -639,7 +639,8 @@ def test_dispose2_background(tmp_path): assert im.getpixel((0, 0)) == (255, 0, 0) -def test_transparency_in_second_frame(): +def test_transparency_in_second_frame(tmp_path): + out = str(tmp_path / "temp.gif") with Image.open("Tests/images/different_transparency.gif") as im: assert im.info["transparency"] == 0 @@ -649,6 +650,14 @@ def test_transparency_in_second_frame(): assert_image_equal_tofile(im, "Tests/images/different_transparency_merged.png") + im.save(out, save_all=True) + + with Image.open(out) as reread: + reread.seek(reread.tell() + 1) + assert_image_equal_tofile( + reread, "Tests/images/different_transparency_merged.png" + ) + def test_no_transparency_in_second_frame(): with Image.open("Tests/images/iss634.gif") as img: @@ -660,6 +669,22 @@ def test_no_transparency_in_second_frame(): assert img.histogram()[255] == 0 +def test_remapped_transparency(tmp_path): + out = str(tmp_path / "temp.gif") + + im = Image.new("P", (1, 2)) + im2 = im.copy() + + # Add transparency at a higher index + # so that it will be optimized to a lower index + im.putpixel((0, 1), 5) + im.info["transparency"] = 5 + im.save(out, save_all=True, append_images=[im2]) + + with Image.open(out) as reloaded: + assert reloaded.info["transparency"] == reloaded.getpixel((0, 1)) + + def test_duration(tmp_path): duration = 1000 diff --git a/Tests/test_image.py b/Tests/test_image.py index 5544ae43c8a..7922505185b 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -609,6 +609,20 @@ def test_remap_palette(self): with pytest.raises(ValueError): im.remap_palette(None) + def test_remap_palette_transparency(self): + im = Image.new("P", (1, 2)) + im.putpixel((0, 1), 1) + im.info["transparency"] = 0 + + im_remapped = im.remap_palette([1, 0]) + assert im_remapped.info["transparency"] == 1 + + # Test unused transparency + im.info["transparency"] = 2 + + im_remapped = im.remap_palette([1, 0]) + assert "transparency" not in im_remapped.info + def test__new(self): im = hopper("RGB") im_p = hopper("P") diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 778245ed21d..3469199cad3 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -574,10 +574,14 @@ def _write_multiple_frames(im, fp, palette): im_frame = _normalize_mode(im_frame.copy()) if frame_count == 0: for k, v in im_frame.info.items(): + if k == "transparency": + continue im.encoderinfo.setdefault(k, v) - im_frame = _normalize_palette(im_frame, palette, im.encoderinfo) encoderinfo = im.encoderinfo.copy() + im_frame = _normalize_palette(im_frame, palette, encoderinfo) + if "transparency" in im_frame.info: + encoderinfo.setdefault("transparency", im_frame.info["transparency"]) if isinstance(duration, (list, tuple)): encoderinfo["duration"] = duration[frame_count] elif duration is None and "duration" in im_frame.info: diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 5b7a50e1806..4f53564af63 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1909,6 +1909,13 @@ def remap_palette(self, dest_map, source_palette=None): m_im.putpalette(new_palette_bytes) m_im.palette = ImagePalette.ImagePalette("RGB", palette=palette_bytes) + if "transparency" in self.info: + try: + m_im.info["transparency"] = dest_map.index(self.info["transparency"]) + except ValueError: + if "transparency" in m_im.info: + del m_im.info["transparency"] + return m_im def _get_safe_box(self, size, resample, box):