'PIL - Convert GIF Frames to JPG

I tried to convert an gif to single images with Python Image Library, but it results in weird frames

The Input gif is:

Source Image http://longcat.de/gif_example.gif

In my first try, i tried to convert the image with Image.new to an RGB image, with 255,255,255 as white background - like in any other example i've found on the internet:

def processImage( infile ):

    try:
        im = Image.open( infile )
    except IOError:
        print "Cant load", infile
        sys.exit(1)

    i = 0

    try:
        while 1:

            background = Image.new("RGB", im.size, (255, 255, 255))
            background.paste(im)
            background.save('foo'+str(i)+'.jpg', 'JPEG', quality=80)

            i += 1
            im.seek( im.tell() + 1 )

    except EOFError:
        pass # end of sequence

but it results in weird output files:

Example #1 http://longcat.de/gif_example1.jpg

My second try was, to convert the gif in an RGBA first, and then use its transparency mask, to make the transparent pieces white:

def processImage( infile ):

    try:
        im = Image.open( infile )
    except IOError:
        print "Cant load", infile
        sys.exit(1)

    i = 0

    try:
        while 1:

            im2 = im.convert('RGBA')
            im2.load()

            background = Image.new("RGB", im2.size, (255, 255, 255))
            background.paste(im2, mask = im2.split()[3] )
            background.save('foo'+str(i)+'.jpg', 'JPEG', quality=80)

            i += 1
            im.seek( im.tell() + 1 )

    except EOFError:
        pass # end of sequence

which results in an output like this:

Example #2 http://longcat.de/gif_example2.jpg

The advantage over the first try was, that the first frame looks pretty good But as you can see, the rest is broken

What should i try next?

Edit:

I think i came a lot closer to the solution

Example #3 http://longcat.de/gif_example3.png

I had to use the palette of the first image for the other images, and merge it with the previous frame (for gif animations which use diff-images)

def processImage( infile ):

    try:
        im = Image.open( infile )
    except IOError:
        print "Cant load", infile
        sys.exit(1)

    i = 0

    size        = im.size
    lastframe   = im.convert('RGBA')
    mypalette   = im.getpalette()

    try:
        while 1:

            im2 = im.copy()
            im2.putpalette( mypalette )

            background = Image.new("RGB", size, (255,255,255))

            background.paste( lastframe )
            background.paste( im2 )
            background.save('foo'+str(i)+'.png', 'PNG', quality=80)

            lastframe = background

            i += 1
            im.seek( im.tell() + 1 )

    except EOFError:
        pass # end of sequence

But i actually dont know, why my transparency is black, instead of white Even if i modify the palette (change the transparency channel to white) or use the transparency mask, the background is still black



Solution 1:[1]

When viewing an image on an image viewer, even when transparency is set to zero, it tends to display the image as black. One way to be sure that your image is truly transparent is to merge it over another. The 'emoticon' should be seen whilst not obstructing the other image.Try:

background = Image.open('someimage.jpg') #an existing image
foreground = Image.open('foo.jpg') #one of the above images
background.paste(foreground, (0,0), foreground)
background.save('trial.jpg') #the composite image

Theoretically, if you open 'trial.jpg' in the image viewer and the content of the initial image is preserved and on top of it lies the foo image then you'll know for sure if it's just the image viewer and your images are fine...

Solution 2:[2]

source here

Image.open('image.gif').convert('RGB').save('image.jpg')

Solution 3:[3]

enter image description here

This works for me. The following example shows converting image.gif to 8 jpg format images with white background.

from PIL import Image
from PIL import GifImagePlugin


def gif2jpg(file_name: str, num_key_frames: int, trans_color: tuple):
    """
    convert gif to `num_key_frames` images with jpg format
    :param file_name: gif file name
    :param num_key_frames: result images number
    :param trans_color: set converted transparent color in jpg image
    :return:
    """
    with Image.open(file_name) as im:
        for i in range(num_key_frames):
            im.seek(im.n_frames // num_key_frames * i)
            image = im.convert("RGBA")
            datas = image.getdata()
            newData = []
            for item in datas:
                if item[3] == 0:  # if transparent
                    newData.append(trans_color)  # set transparent color in jpg
                else:
                    newData.append(tuple(item[:3]))
            image = Image.new("RGB", im.size)
            image.getdata()
            image.putdata(newData)
            image.save('{}.jpg'.format(i))


gif2jpg("image.gif", 8, (255, 255, 255))  # convert image.gif to 8 jpg images with white background

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Matthias
Solution 2 Community
Solution 3 apoptosis