Skip to content

Commit

Permalink
Merge pull request #6176 from radarhere/gif_transparency
Browse files Browse the repository at this point in the history
Improve transparency handling when saving GIF
  • Loading branch information
hugovk committed May 27, 2022
2 parents 0476914 + 99f4623 commit 27f5c4d
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 2 deletions.
27 changes: 26 additions & 1 deletion Tests/test_file_gif.py
Expand Up @@ -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

Expand All @@ -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:
Expand All @@ -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

Expand Down
14 changes: 14 additions & 0 deletions Tests/test_image.py
Expand Up @@ -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")
Expand Down
6 changes: 5 additions & 1 deletion src/PIL/GifImagePlugin.py
Expand Up @@ -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:
Expand Down
7 changes: 7 additions & 0 deletions src/PIL/Image.py
Expand Up @@ -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):
Expand Down

0 comments on commit 27f5c4d

Please sign in to comment.