PIL - Convert GIF Frames to JPG

Schinken picture Schinken · Apr 22, 2012 · Viewed 22.9k times · Source

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

Answer

fraxel picture fraxel · Apr 26, 2012

First of all, JPEG doesn't support transparency! But that's not the only problem.. As you move to the next frame of the GIF the palette information is lost (problem witn PIL?) - so PIL is unable to correctly convert to the RGBA framework (Hence the first frame is okish, but all the others are screwy). So the work-around is to add the palette back in for every frame, (which is what you were doing in your last code example, but your trouble was that you were saving as RGB not RGBA so you had no alpha/ transparency channel. Also you were doing a few unnecessary things..). Anyhow, here are the .png's with transparency and the corrected code, hope its of some use :)

enter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description here

import Image
import sys

def processImage(infile):
    try:
        im = Image.open(infile)
    except IOError:
        print "Cant load", infile
        sys.exit(1)
    i = 0
    mypalette = im.getpalette()

    try:
        while 1:
            im.putpalette(mypalette)
            new_im = Image.new("RGBA", im.size)
            new_im.paste(im)
            new_im.save('foo'+str(i)+'.png')

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

    except EOFError:
        pass # end of sequence

processImage('gif_example.gif')