Skip to content
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

Alpha channel is discarded when saving an animated PNG #7122

Closed
gsingh93 opened this issue Apr 29, 2023 · 2 comments · Fixed by #7123
Closed

Alpha channel is discarded when saving an animated PNG #7122

gsingh93 opened this issue Apr 29, 2023 · 2 comments · Fixed by #7123

Comments

@gsingh93
Copy link

gsingh93 commented Apr 29, 2023

What did you do?

Created an animated PNG from RGBA images with transparent colors (non-zero alpha).

What did you expect to happen?

The animated PNG should preserve the alpha channel of the individual images.

What actually happened?

The alpha channel of all but the first image in the sequence is discarded. If the frames are of a static object fading in or out, then PIL then thinks that all of the frames are the same, and then discards them.

This bug also seems to occur with animated GIFs, but I'm not 100% sure the root cause is the same.

What are your OS, Python and Pillow versions?

  • OS: macOS 13.3.1
  • Python: 3.11.3
  • Pillow: 9.5.0

This script will create an APNG from 10 frames, with the alpha of the red square in the center increasing each frame:

#!/usr/bin/env python3

from PIL import Image, ImageDraw

images = []
for i in range(10):
    img = Image.new('RGBA', (300, 300), (255, 255, 255, 255))

    draw = ImageDraw.Draw(img)
    draw.rectangle((100, 100, 200, 200), fill=(255, 0, 0, i * 20))

    img.save(f'frame-{i}.png')
    images.append(img)

images[0].save(
    'test.png', save_all=True, append_images=images[1:], duration=100, loop=0
)
images[0].show()

Here is the PNG file with the transparency issue:
test-incorrect

What happened here is that when the alpha channel was thrown away, all of the images in append_images are exactly the same and they get thrown away.

This is how I would expect the correct image to look:
test-correct

@gsingh93
Copy link
Author

I was able to fix this issue and generate the correct APNG file shown above by changing this line from:

delta = ImageChops.subtract_modulo(
    im_frame.convert("RGB"), base_im.convert("RGB")
)

to:

delta = ImageChops.subtract_modulo(
    im_frame.convert("RGBA"), base_im.convert("RGBA")
)

But I don't know if this is the correct fix, or whether it will break in some cases.

@radarhere
Copy link
Member

Thanks for the head start. Your suggestion does break some of our existing tests, but I was able to add some further changes to fix them. I've created PR #7123 to resolve this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants