Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you scale an animated GIF image in PIL and preserve the animation

I'm wondering if it's possible to scale an animated GIF image using PIL. In particular Plone’s archetypes ImageField currently loses the animation from images scaled using its scale method:

def scale(self, data, w, h, default_format = 'PNG'):
    """ scale image (with material from ImageTag_Hotfix)"""
    #make sure we have valid int's
    size = int(w), int(h)

    original_file=StringIO(data)
    image = PIL.Image.open(original_file)
    # consider image mode when scaling
    # source images can be mode '1','L,','P','RGB(A)'
    # convert to greyscale or RGBA before scaling
    # preserve palletted mode (but not pallette)
    # for palletted-only image formats, e.g. GIF
    # PNG compression is OK for RGBA thumbnails
    original_mode = image.mode
    img_format = image.format and image.format or default_format
    if original_mode == '1':
        image = image.convert('L')
    elif original_mode == 'P':
        image = image.convert('RGBA')
    image.thumbnail(size, self.pil_resize_algo)
    # decided to only preserve palletted mode
    # for GIF, could also use image.format in ('GIF','PNG')
    if original_mode == 'P' and img_format == 'GIF':
        image = image.convert('P')
    thumbnail_file = StringIO()
    # quality parameter doesn't affect lossless formats
    image.save(thumbnail_file, img_format, quality=self.pil_quality)
    thumbnail_file.seek(0)
    return thumbnail_file, img_format.lower()

I know how to identify a animated GIF: The following evaluates to True image.format == 'GIF' and image.seek(image.tell()+1). I’ve tried not converting to RGBA mode but that doesn't work.

Background: On our Plone instance we've modified the default image type to set the original_size attribute of its image field to force all images to scaled with an appropriate quality setting. This works great for jpegs but means we currently can't upload animated GIFs

like image 571
scarba05 Avatar asked Feb 03 '12 12:02

scarba05


2 Answers

You can use images2gif.py to read gifs and than scale each frame independently. images2gif will allow you to write an animated gif with a sequence of Images.

The images2gif.py I found on the internet didn't handle transparency, so i fixed that. You can find that here: https://bitbucket.org/bench/images2gif.py

like image 148
ben Avatar answered Oct 16 '22 23:10

ben


PIL has got some limited support for animated GIF's but it is, as said, limited, and you have to work in very low level to deal with it.

I'd advise trying some other method for scaling images than PIL if you want to deal with animated gif's. Possibly, the most straightforward way is to use an off-process ImageMagick, with subprocess.Popen - (and even then, at this time, I am only guessing ImageMagick "does the right thing" with animated GIF's) -

An option is to have an "image processing server", with another Python script, apart from your zope install that will receive requests to scale the images - possibly with a xmlrpc call - you could build this as a GIMP plug-in and use GIMP for scaling the GIF's.

Another option is to leave things as they are, and use "stills" for animated GIF's where they need to appear in another dimension than the original, and display the original image where the animation is appropriate. (Or maybe simply require that animated gif's be submitted already on the proper size)

like image 25
jsbueno Avatar answered Oct 17 '22 01:10

jsbueno