-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Broken background on transparent GIFs built from individual frames #6115
Comments
I suspect that setting transparency and background to 255 is the issue. These values are indexes into the color palette but your palette only has 13 entries, not 255. I fed the test input and output .gifs provided by @balt-is-you-and-shift into a small script I wrote, and here is the output:
When I copied the background and transparency from the source to the save() call, I think I got the results you desire:
|
Take a look at this. If I set the transparency using the key from the info dictionary, it works. from PIL import Image
with Image.open('test.gif') as im:
images = []
durations = []
transparency = im.info["transparency"]
for i in range(im.n_frames):
im.seek(i)
im.convert('RGBA')
im_temp = Image.new('RGBA',im.size,(0,0,0,0))
im_temp.paste(im,(0,0))
images.append(im_temp)
durations.append(im.info['duration'])
images[0].save(
'test-out.gif',
interlace=True,
save_all=True,
append_images=images[1:],
loop=0,
duration=durations,
disposal=2,
transparency = transparency,
background = 255,
optimize=False
) |
This wouldn't solve the issue well, bad example. I'll make a better example of the issue when I can. |
test-v2.zip Sorry for the multiple edits, I'm trying to get an example that best shows the issue. from PIL import Image
import json
with open('durations.json','rb') as f:
durations = json.load(f)
images = []
for n in range(8):
with Image.open(f'test{n}.png') as im:
im = im.convert('RGBA').resize([n*8 for n in im.size],Image.NEAREST)
images.append(im)
images[0].save( #GIFs have this issue
'test.gif',
interlace=True,
save_all=True,
append_images=images[1:],
loop=0,
duration=durations,
disposal=2,
transparency = 255,
background = 255,
optimize=False
)
images[0].save( #APNGs don't have this issue, showing it's an issue with GIF saving
'test.png',
format='PNG',
save_all=True,
append_images=images,
default_image=True,
loop=0,
durations=durations
)
|
Not sure why you are setting transparency=255 (or why PIL is not complaining about it!). According to the docs (https://pillow.readthedocs.io/en/latest/handbook/image-file-formats.html#saving), transparency is an "index", i.e. offset into the color palette indicating which "color" should denote transparent pixels. Your image palette does not contain 256 colors (only 13 are used), so you are not getting the proper results. For the test provided, using transparency=0 works. The same applies to the background setting: it is an index into the color palette. Again, setting to 0 will get what you want for this. (@radarhere : your solution is missing this part as well.) FYI: here is the color palette for your generated GIF:
If there is anything amiss with PIL, I think it is that the On a side note: I went through the same thing as you: generating an animated image from a list of images. In my solution, I chose a file naming convention over a .json durations file. I named my inputs "nn-dDDD-blah.png" where "nn" is the image order index (for easily sorting the output of a glob.glob('*.png') call), "DDD" is the duration in msecs., and "blah" is anything but was used for the default output filename "blah.{gif|png}". Just another way of doing things... |
See, the problem with that is that setting transparency and background to 255 worked fine in previous versions, and setting them both to 0 won't work if the majority of the image isn't transparent. |
I've created PR #6128 to resolve this. With it, your code works when you remove the from PIL import Image
with Image.open('test.gif') as im:
images = []
durations = []
for i in range(im.n_frames):
im.seek(i)
im.convert('RGBA')
im_temp = Image.new('RGBA',im.size,(0,0,0,0))
im_temp.paste(im,(0,0))
images.append(im_temp)
durations.append(im.info['duration'])
images[0].save(
'test-out.gif',
interlace=True,
save_all=True,
append_images=images[1:],
loop=0,
duration=durations,
disposal=2,
background = 255,
optimize=False
) |
Seems great, thanks! |
The background of transparent GIFs constructed from Images seems to not quite see the transparent color correctly.
This should copy the image perfectly, but there are artifacts.
Here's the venv I used to test this, in a zip.
The text was updated successfully, but these errors were encountered: