mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 01:47:47 +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,7 +317,31 @@ 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)
 | 
			
		||||
    if save_all:
 | 
			
		||||
        previous = None
 | 
			
		||||
 | 
			
		||||
        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 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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -325,7 +351,7 @@ def _save(im, fp, filename):
 | 
			
		|||
            flags = flags | 64
 | 
			
		||||
 | 
			
		||||
        # local image header
 | 
			
		||||
    get_local_header(fp, im, (0, 0), flags)
 | 
			
		||||
        _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,
 | 
			
		||||
| 
						 | 
				
			
			@ -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