Search code examples
pythonpython-imaging-library

How to remove white background of gif when using pillow?


I'm trying to display a gif on top of an image. The gif originally has a transparent background. The code below does that, except it created a black background around the original gif that flickers white when the gif resets. If I don't resize the gif then there would still be a white background around the original gif after its merged with the image.

Is there a way to keep the original gif's background transparent when merging?

from PIL import Image


background = Image.open('GrassyField.png').convert("RGBA")
gif = Image.open("1.gif")

foreground_w, foreground_w = gif.size
background_w, background_h = background.size
frames = []

for num in range(gif.n_frames):
    gif.seek(num)
    layer = Image.new('RGBA', (foreground_w, foreground_w), (0, 0, 0, 0)).resize((background_w, 
        background_h))
    layer.paste(background, (0, 0), mask=background)

    layer.paste(gif.resize((100, 100)).convert('RGBA'), (220, 25))

    frames.append(layer)
    frames[0].save('output.gif',
            save_all=True,
            append_images=frames[1:],
            duration=100,loop=0)

Solution

  • Let's say that 1.gif is:

    1.gif

    and GrassyField.png is:

    enter image description here

    using this code:

    import PIL.Image
    import PIL.ImageSequence
    
    with PIL.Image.open('1.gif') as foreground_animation, PIL.Image.open('GrassyField.png') as background_image:
        image_roles = {
            'foreground': foreground_animation, 
            'background': background_image.convert(mode='RGBA')
        }
    
        def create_frames(images_roles):
            for current_frame in PIL.ImageSequence.Iterator(image_roles['foreground']):
                current_background = image_roles['background'].copy()
                current_foreground = current_frame.convert(mode='RGBA').resize((100, 100))
                current_background.alpha_composite(current_foreground, dest=(220,25))
                yield current_background
    
        frames = tuple(create_frames(image_roles))
        frames[0].save(
            'output.gif',
            save_all=True,
            append_images=frames[1:],
            duration=100,loop=0
        )
    

    You get output.gif:

    enter image description here

    Is that what you wanted?