mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 17:36:18 +03:00
Merged gifmaker into GifImagePlugin
This commit is contained in:
parent
75be4af068
commit
2c4fe7281f
|
@ -24,7 +24,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||
from PIL import Image, ImageFile, ImagePalette, ImageChops, ImageSequence, _binary
|
||||
|
||||
__version__ = "0.9"
|
||||
|
||||
|
@ -284,8 +284,10 @@ RAWMODE = {
|
|||
"P": "P",
|
||||
}
|
||||
|
||||
def _save_all(im, fp, filename):
|
||||
_save(im, fp, filename, save_all=True)
|
||||
|
||||
def _save(im, fp, filename):
|
||||
def _save(im, fp, filename, save_all=False):
|
||||
|
||||
if _imaging_gif:
|
||||
# call external driver
|
||||
|
@ -315,23 +317,47 @@ def _save(im, fp, filename):
|
|||
palette = None
|
||||
im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
|
||||
|
||||
header, used_palette_colors = getheader(im_out, palette, im.encoderinfo)
|
||||
for s in header:
|
||||
fp.write(s)
|
||||
if save_all:
|
||||
previous = None
|
||||
|
||||
flags = 0
|
||||
for im_frame in ImageSequence.Iterator(im_out):
|
||||
# To specify duration, add the time in milliseconds to getdata(),
|
||||
# e.g. getdata(im_frame, duration=1000)
|
||||
if not previous:
|
||||
# global header
|
||||
for s in getheader(im_frame, palette, im.encoderinfo)[0] + getdata(im_frame):
|
||||
fp.write(s)
|
||||
else:
|
||||
# delta frame
|
||||
delta = ImageChops.subtract_modulo(im_frame, previous)
|
||||
bbox = delta.getbbox()
|
||||
|
||||
if get_interlace(im):
|
||||
flags = flags | 64
|
||||
if bbox:
|
||||
# compress difference
|
||||
for s in getdata(im_frame.crop(bbox), offset=bbox[:2]):
|
||||
fp.write(s)
|
||||
else:
|
||||
# FIXME: what should we do in this case?
|
||||
pass
|
||||
previous = im_frame.copy()
|
||||
else:
|
||||
header = getheader(im_out, palette, im.encoderinfo)[0]
|
||||
for s in header:
|
||||
fp.write(s)
|
||||
|
||||
# local image header
|
||||
get_local_header(fp, im, (0, 0), flags)
|
||||
flags = 0
|
||||
|
||||
im_out.encoderconfig = (8, get_interlace(im))
|
||||
ImageFile._save(im_out, fp, [("gif", (0, 0)+im.size, 0,
|
||||
RAWMODE[im_out.mode])])
|
||||
if get_interlace(im):
|
||||
flags = flags | 64
|
||||
|
||||
fp.write(b"\0") # end of image data
|
||||
# local image header
|
||||
_get_local_header(fp, im, (0, 0), flags)
|
||||
|
||||
im_out.encoderconfig = (8, get_interlace(im))
|
||||
ImageFile._save(im_out, fp, [("gif", (0, 0)+im.size, 0,
|
||||
RAWMODE[im_out.mode])])
|
||||
|
||||
fp.write(b"\0") # end of image data
|
||||
|
||||
fp.write(b";") # end of file
|
||||
|
||||
|
@ -354,7 +380,7 @@ def get_interlace(im):
|
|||
return interlace
|
||||
|
||||
|
||||
def get_local_header(fp, im, offset, flags):
|
||||
def _get_local_header(fp, im, offset, flags):
|
||||
transparent_color_exists = False
|
||||
try:
|
||||
transparency = im.encoderinfo["transparency"]
|
||||
|
@ -577,7 +603,7 @@ def getdata(im, offset=(0, 0), **params):
|
|||
im.encoderinfo = params
|
||||
|
||||
# local image header
|
||||
get_local_header(fp, im, offset, 0)
|
||||
_get_local_header(fp, im, offset, 0)
|
||||
|
||||
ImageFile._save(im, fp, [("gif", (0, 0)+im.size, 0, RAWMODE[im.mode])])
|
||||
|
||||
|
@ -594,6 +620,7 @@ def getdata(im, offset=(0, 0), **params):
|
|||
|
||||
Image.register_open(GifImageFile.format, GifImageFile, _accept)
|
||||
Image.register_save(GifImageFile.format, _save)
|
||||
Image.register_save_all(GifImageFile.format, _save_all)
|
||||
Image.register_extension(GifImageFile.format, ".gif")
|
||||
Image.register_mime(GifImageFile.format, "image/gif")
|
||||
|
||||
|
|
26
PIL/Image.py
26
PIL/Image.py
|
@ -204,6 +204,7 @@ ID = []
|
|||
OPEN = {}
|
||||
MIME = {}
|
||||
SAVE = {}
|
||||
SAVE_ALL = {}
|
||||
EXTENSION = {}
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
@ -1669,6 +1670,10 @@ class Image(object):
|
|||
# may mutate self!
|
||||
self.load()
|
||||
|
||||
save_all = False
|
||||
if 'save_all' in params:
|
||||
save_all = params['save_all']
|
||||
del params['save_all']
|
||||
self.encoderinfo = params
|
||||
self.encoderconfig = ()
|
||||
|
||||
|
@ -1686,11 +1691,12 @@ class Image(object):
|
|||
except KeyError:
|
||||
raise KeyError(ext) # unknown extension
|
||||
|
||||
try:
|
||||
save_handler = SAVE[format.upper()]
|
||||
except KeyError:
|
||||
if format.upper() not in SAVE:
|
||||
init()
|
||||
save_handler = SAVE[format.upper()] # unknown format
|
||||
if save_all:
|
||||
save_handler = SAVE_ALL[format.upper()]
|
||||
else:
|
||||
save_handler = SAVE[format.upper()]
|
||||
|
||||
if isPath(fp):
|
||||
fp = builtins.open(fp, "wb")
|
||||
|
@ -2469,6 +2475,18 @@ def register_save(id, driver):
|
|||
SAVE[id.upper()] = driver
|
||||
|
||||
|
||||
def register_save_all(id, driver):
|
||||
"""
|
||||
Registers an image function to save all the frames
|
||||
of a multiframe format. This function should not be
|
||||
used in application code.
|
||||
|
||||
:param id: An image format identifier.
|
||||
:param driver: A function to save images in this format.
|
||||
"""
|
||||
SAVE_ALL[id.upper()] = driver
|
||||
|
||||
|
||||
def register_extension(id, extension):
|
||||
"""
|
||||
Registers an image extension. This function should not be
|
||||
|
|
|
@ -14,104 +14,9 @@
|
|||
# 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...
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from PIL import Image, ImageChops, ImageSequence
|
||||
|
||||
from PIL.GifImagePlugin import getheader, getdata
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# straightforward delta encoding
|
||||
|
||||
|
||||
def makedelta(fp, sequence):
|
||||
"""Convert list of image frames to a GIF animation file"""
|
||||
|
||||
frames = 0
|
||||
|
||||
previous = None
|
||||
|
||||
for im in sequence:
|
||||
|
||||
# To specify duration, add the time in milliseconds to getdata(),
|
||||
# e.g. getdata(im, duration=1000)
|
||||
|
||||
if not previous:
|
||||
|
||||
# global header
|
||||
for s in getheader(im)[0] + getdata(im):
|
||||
fp.write(s)
|
||||
|
||||
else:
|
||||
|
||||
# delta frame
|
||||
delta = ImageChops.subtract_modulo(im, previous)
|
||||
|
||||
bbox = delta.getbbox()
|
||||
|
||||
if bbox:
|
||||
|
||||
# compress difference
|
||||
for s in getdata(im.crop(bbox), offset=bbox[:2]):
|
||||
fp.write(s)
|
||||
|
||||
else:
|
||||
# FIXME: what should we do in this case?
|
||||
pass
|
||||
|
||||
previous = im.copy()
|
||||
|
||||
frames += 1
|
||||
|
||||
fp.write(b";")
|
||||
|
||||
return frames
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# main hack
|
||||
|
||||
|
||||
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 = ImageSequence.Iterator(im)
|
||||
|
||||
makedelta(fp, seq)
|
||||
|
||||
fp.close()
|
||||
|
||||
from PIL import Image
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
|
@ -122,4 +27,5 @@ if __name__ == "__main__":
|
|||
print("Usage: gifmaker infile outfile")
|
||||
sys.exit(1)
|
||||
|
||||
compress(sys.argv[1], sys.argv[2])
|
||||
im = Image.open(sys.argv[1])
|
||||
im.save(sys.argv[2], save_all=True)
|
||||
|
|
Loading…
Reference in New Issue
Block a user