mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 01:46: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.
|
# 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"
|
__version__ = "0.9"
|
||||||
|
|
||||||
|
@ -284,8 +284,10 @@ RAWMODE = {
|
||||||
"P": "P",
|
"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:
|
if _imaging_gif:
|
||||||
# call external driver
|
# call external driver
|
||||||
|
@ -315,23 +317,47 @@ def _save(im, fp, filename):
|
||||||
palette = None
|
palette = None
|
||||||
im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
|
im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
|
||||||
|
|
||||||
header, used_palette_colors = getheader(im_out, palette, im.encoderinfo)
|
if save_all:
|
||||||
for s in header:
|
previous = None
|
||||||
fp.write(s)
|
|
||||||
|
|
||||||
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):
|
if bbox:
|
||||||
flags = flags | 64
|
# 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
|
flags = 0
|
||||||
get_local_header(fp, im, (0, 0), flags)
|
|
||||||
|
|
||||||
im_out.encoderconfig = (8, get_interlace(im))
|
if get_interlace(im):
|
||||||
ImageFile._save(im_out, fp, [("gif", (0, 0)+im.size, 0,
|
flags = flags | 64
|
||||||
RAWMODE[im_out.mode])])
|
|
||||||
|
|
||||||
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
|
fp.write(b";") # end of file
|
||||||
|
|
||||||
|
@ -354,7 +380,7 @@ def get_interlace(im):
|
||||||
return interlace
|
return interlace
|
||||||
|
|
||||||
|
|
||||||
def get_local_header(fp, im, offset, flags):
|
def _get_local_header(fp, im, offset, flags):
|
||||||
transparent_color_exists = False
|
transparent_color_exists = False
|
||||||
try:
|
try:
|
||||||
transparency = im.encoderinfo["transparency"]
|
transparency = im.encoderinfo["transparency"]
|
||||||
|
@ -577,7 +603,7 @@ def getdata(im, offset=(0, 0), **params):
|
||||||
im.encoderinfo = params
|
im.encoderinfo = params
|
||||||
|
|
||||||
# local image header
|
# 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])])
|
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_open(GifImageFile.format, GifImageFile, _accept)
|
||||||
Image.register_save(GifImageFile.format, _save)
|
Image.register_save(GifImageFile.format, _save)
|
||||||
|
Image.register_save_all(GifImageFile.format, _save_all)
|
||||||
Image.register_extension(GifImageFile.format, ".gif")
|
Image.register_extension(GifImageFile.format, ".gif")
|
||||||
Image.register_mime(GifImageFile.format, "image/gif")
|
Image.register_mime(GifImageFile.format, "image/gif")
|
||||||
|
|
||||||
|
|
26
PIL/Image.py
26
PIL/Image.py
|
@ -204,6 +204,7 @@ ID = []
|
||||||
OPEN = {}
|
OPEN = {}
|
||||||
MIME = {}
|
MIME = {}
|
||||||
SAVE = {}
|
SAVE = {}
|
||||||
|
SAVE_ALL = {}
|
||||||
EXTENSION = {}
|
EXTENSION = {}
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
@ -1669,6 +1670,10 @@ class Image(object):
|
||||||
# may mutate self!
|
# may mutate self!
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
|
save_all = False
|
||||||
|
if 'save_all' in params:
|
||||||
|
save_all = params['save_all']
|
||||||
|
del params['save_all']
|
||||||
self.encoderinfo = params
|
self.encoderinfo = params
|
||||||
self.encoderconfig = ()
|
self.encoderconfig = ()
|
||||||
|
|
||||||
|
@ -1686,11 +1691,12 @@ class Image(object):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise KeyError(ext) # unknown extension
|
raise KeyError(ext) # unknown extension
|
||||||
|
|
||||||
try:
|
if format.upper() not in SAVE:
|
||||||
save_handler = SAVE[format.upper()]
|
|
||||||
except KeyError:
|
|
||||||
init()
|
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):
|
if isPath(fp):
|
||||||
fp = builtins.open(fp, "wb")
|
fp = builtins.open(fp, "wb")
|
||||||
|
@ -2469,6 +2475,18 @@ def register_save(id, driver):
|
||||||
SAVE[id.upper()] = 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):
|
def register_extension(id, extension):
|
||||||
"""
|
"""
|
||||||
Registers an image extension. This function should not be
|
Registers an image extension. This function should not be
|
||||||
|
|
|
@ -14,104 +14,9 @@
|
||||||
# See the README file for information on usage and redistribution.
|
# 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 __future__ import print_function
|
||||||
|
|
||||||
from PIL import Image, ImageChops, ImageSequence
|
from PIL import Image
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
@ -122,4 +27,5 @@ if __name__ == "__main__":
|
||||||
print("Usage: gifmaker infile outfile")
|
print("Usage: gifmaker infile outfile")
|
||||||
sys.exit(1)
|
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