Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """ MODULE images2gif
- Provides a function (writeGif) to write animated gif from a series
- of PIL images
- This code is provided as is, and is free to use for all.
- Almar Klein (June 2009)
- Will Pierce (March 2013) - removed numpy support and refactored internals
- - based on gifmaker (in the scripts folder of the source distribution of PIL)
- - based on gif file structure as provided by wikipedia
- """
- import struct
- import PIL
- from PIL import Image
- from PIL.GifImagePlugin import getheader, getdata
- # getheader gives a 87a header and a color palette (two elements in a list).
- # getdata()[0] gives the Image Descriptor up to (including) "LZW min code size".
- # getdatas()[1:] is the image data itself in chuncks of 256 bytes (well
- # technically the first byte says how many bytes follow, after which that
- # amount (max 255) follows).
- intToBin = struct.Struct('<H').pack
- def getheaderAnim(im):
- """ Animation header. To replace the getheader()[0] """
- return ''.join(["GIF89a",
- intToBin(im.size[0]),
- intToBin(im.size[1]),
- "\x87\x00\x00"])
- def getAppExt(loops):
- """ Application extention. Part that secifies amount of loops.
- if loops is 0, it goes on infinitely.
- """
- return ''.join(["\x21\xFF\x0B", # application extension
- "NETSCAPE2.0",
- "\x03\x01",
- intToBin(loops),
- '\x00']) # end
- def getGraphicsControlExt(duration=0.1):
- """ Graphics Control Extension. A header at the start of
- each image. Specifies transparancy and duration. """
- return ''.join(['\x21\xF9\x04',
- '\x08', # no transparency
- intToBin(int(duration * 100)), # in 100th of seconds
- '\x00', # no transparent color
- '\x00']) # end
- def _writeGifToFile(fp, images, durations, loops):
- """ Given a set of images writes the bytes to the specified stream."""
- # first image, gather data for global header
- img = images[0]
- header = getheaderAnim(img)
- palette = getheader(img)[1]
- appext = getAppExt(loops)
- # output the initial header
- fp.write(header)
- fp.write(palette)
- fp.write(appext)
- # write sequence of images
- for img, duration in zip(images, durations):
- graphext = getGraphicsControlExt(duration)
- fp.write(graphext)
- for dat in getdata(img):
- fp.write(dat)
- fp.write(';') # end gif marker
- def writeGif(filename, images, duration=0.1, loops=0, dither=1):
- """Write an animated gif from the specified images.
- @param str filename - output filename
- @param list images - a list of PIL Images
- @param int/list duration - either a float for per-frame delay, or list of floats
- @param int loops - number of times the animation should loop, None means infinite
- @param int dither - dithering mode for Image.convert(), set to 0 to disable dithering
- """
- # build duration list
- try:
- assert len(duration) == len(images)
- durations = duration
- except TypeError:
- durations = [duration] * len(images)
- # convert to PIL gifs (palette mode)
- gifs = [img.convert('P', dither=dither) for img in images]
- with open(filename, 'wb') as fp:
- _writeGifToFile(fp, gifs, durations, loops)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement