2013-04-21 10:38:36 +04:00
|
|
|
#!/usr/bin/env python
|
2010-07-31 06:52:47 +04:00
|
|
|
#
|
|
|
|
# The Python Imaging Library
|
|
|
|
# $Id$
|
|
|
|
#
|
|
|
|
# convert sequence format to GIF animation
|
|
|
|
#
|
|
|
|
# history:
|
|
|
|
# 97-01-03 fl created
|
|
|
|
#
|
|
|
|
# Copyright (c) Secret Labs AB 1997. All rights reserved.
|
|
|
|
# Copyright (c) Fredrik Lundh 1997.
|
|
|
|
#
|
|
|
|
# See the README file for information on usage and redistribution.
|
|
|
|
#
|
|
|
|
|
|
|
|
#
|
|
|
|
# For special purposes, you can import this module and call
|
|
|
|
# the makedelta or compress functions yourself. For example,
|
|
|
|
# if you have an application that generates a sequence of
|
|
|
|
# images, you can convert it to a GIF animation using some-
|
|
|
|
# thing like the following code:
|
|
|
|
#
|
|
|
|
# import Image
|
|
|
|
# import gifmaker
|
|
|
|
#
|
|
|
|
# sequence = []
|
|
|
|
#
|
|
|
|
# # generate sequence
|
|
|
|
# for i in range(100):
|
|
|
|
# im = <generate image i>
|
|
|
|
# sequence.append(im)
|
|
|
|
#
|
|
|
|
# # write GIF animation
|
|
|
|
# fp = open("out.gif", "wb")
|
|
|
|
# gifmaker.makedelta(fp, sequence)
|
|
|
|
# fp.close()
|
|
|
|
#
|
|
|
|
# Alternatively, use an iterator to generate the sequence, and
|
|
|
|
# write data directly to a socket. Or something...
|
|
|
|
#
|
|
|
|
|
2012-10-16 06:27:35 +04:00
|
|
|
from __future__ import print_function
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
from PIL import Image, ImageChops
|
|
|
|
|
|
|
|
from PIL.GifImagePlugin import getheader, getdata
|
|
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
|
|
# sequence iterator
|
|
|
|
|
2015-04-24 02:41:33 +03:00
|
|
|
|
2015-05-26 17:07:21 +03:00
|
|
|
class image_sequence(object):
|
2010-07-31 06:52:47 +04:00
|
|
|
def __init__(self, im):
|
|
|
|
self.im = im
|
2015-04-24 02:41:33 +03:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
def __getitem__(self, ix):
|
|
|
|
try:
|
|
|
|
if ix:
|
|
|
|
self.im.seek(ix)
|
|
|
|
return self.im
|
|
|
|
except EOFError:
|
2015-04-24 02:41:33 +03:00
|
|
|
raise IndexError # end of sequence
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
|
|
# straightforward delta encoding
|
|
|
|
|
2015-04-24 02:41:33 +03:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
def makedelta(fp, sequence):
|
|
|
|
"""Convert list of image frames to a GIF animation file"""
|
|
|
|
|
|
|
|
frames = 0
|
|
|
|
|
|
|
|
previous = None
|
|
|
|
|
|
|
|
for im in sequence:
|
|
|
|
|
2015-04-03 15:22:13 +03:00
|
|
|
# To specify duration, add the time in milliseconds to getdata(),
|
|
|
|
# e.g. getdata(im, duration=1000)
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
if not previous:
|
|
|
|
|
|
|
|
# global header
|
2015-03-14 12:41:14 +03:00
|
|
|
for s in getheader(im)[0] + getdata(im):
|
2010-07-31 06:52:47 +04:00
|
|
|
fp.write(s)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
# delta frame
|
|
|
|
delta = ImageChops.subtract_modulo(im, previous)
|
|
|
|
|
|
|
|
bbox = delta.getbbox()
|
|
|
|
|
|
|
|
if bbox:
|
|
|
|
|
|
|
|
# compress difference
|
2015-04-24 02:41:33 +03:00
|
|
|
for s in getdata(im.crop(bbox), offset=bbox[:2]):
|
2010-07-31 06:52:47 +04:00
|
|
|
fp.write(s)
|
|
|
|
|
|
|
|
else:
|
|
|
|
# FIXME: what should we do in this case?
|
|
|
|
pass
|
|
|
|
|
|
|
|
previous = im.copy()
|
|
|
|
|
2014-05-10 08:36:15 +04:00
|
|
|
frames += 1
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
fp.write(";")
|
|
|
|
|
|
|
|
return frames
|
|
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
|
|
# main hack
|
|
|
|
|
2015-04-24 02:41:33 +03:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
def compress(infile, outfile):
|
|
|
|
|
|
|
|
# open input image, and force loading of first frame
|
|
|
|
im = Image.open(infile)
|
|
|
|
im.load()
|
|
|
|
|
|
|
|
# open output file
|
|
|
|
fp = open(outfile, "wb")
|
|
|
|
|
|
|
|
seq = image_sequence(im)
|
|
|
|
|
|
|
|
makedelta(fp, seq)
|
|
|
|
|
|
|
|
fp.close()
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
if len(sys.argv) < 3:
|
2012-10-16 06:27:35 +04:00
|
|
|
print("GIFMAKER -- create GIF animations")
|
|
|
|
print("Usage: gifmaker infile outfile")
|
2010-07-31 06:52:47 +04:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
compress(sys.argv[1], sys.argv[2])
|