def makedelta(fp, sequence): """Convert list of image frames to a GIF animation file""" frames = 0 previous = None for im in sequence: # # FIXME: write graphics control block before each frame if not previous: # global header for s in getheader(im)[0]: fp.write(s) for s in 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
def makedelta(fp, sequence): """Convert list of image frames to a GIF animation file""" frames = 0 previous = None loop_code = '!\xff\x0bNETSCAPE2.0\x03\x01\xff\xff\x00' for im in sequence: if not previous: # global header for s in getheader(im)[0] + [loop_code] + 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: # duplicate frame, write anyway for s in getdata(im): fp.write(s) previous = im.copy() frames = frames + 1 fp.write(";") return frames
def add_image(self, im, duration, dispose): # Prepare image im_rect, rect = im, (0, 0) if self.opt_subrectangle: im_rect, rect = self.getSubRectangle(im) im_pil = self.converToPIL(im_rect, self.opt_quantizer, self.opt_palette_size) # Get pallette - apparently, this is the 3d element of the header # (but it has not always been). Best we've got. Its not the same # as im_pil.palette.tobytes(). from PIL.GifImagePlugin import getheader palette = getheader(im_pil)[0][3] # Write image if self._count == 0: self.write_header(im_pil, palette, self.opt_loop) self._global_palette = palette self.write_image(im_pil, palette, rect, duration, dispose) # assert len(palette) == len(self._global_palette) # Bookkeeping self._previous_image = im self._count += 1
def _write_frame(self, im, duration = None, dispose = None, xy = None): duration = self.duration if duration is None else duration dispose = self.dispose if dispose is None else dispose xy = self.xy if xy is None else xy palette = getheader(im)[0][-1] if not palette: palette = im.palette.tobytes() # Gather info data = getdata(im) imdes, data = data[0], data[1:] graphext = self.pointless_instance.getGraphicsControlExt(duration, dispose) # Make image descriptor suitable for using 256 local color palette lid = self.pointless_instance.getImageDescriptor(im, xy) # Write local header if (palette != self.globalPalette) or (dispose != 2): # Use local color palette self.fp.write(encode(graphext)) self.fp.write(encode(lid)) # write suitable image descriptor self.fp.write(palette) # write local color table self.fp.write(encode('\x08')) # LZW minimum size code else: # Use global color palette self.fp.write(encode(graphext)) self.fp.write(imdes) # write suitable image descriptor # Write image data for d in data: self.fp.write(d)
def patched_get_header(im): header = getheader(im) if header[1] is not None: return header else: return im.palette.getdata()
def _init_gif(self, im): self.globalPalette = getheader(im)[0][-1] # Gather info header = self.pointless_instance.getheaderAnim(im) appext = self.pointless_instance.getAppExt(self.loops) # Write self.fp = open(self.filename, 'wb') self.fp.write(encode(header)) self.fp.write(self.globalPalette) self.fp.write(encode(appext))
def _writeGifToFile(fp, images, durations, loops): """ Given a set of images writes the bytes to the specified stream. """ # init frames = 0 previous = None for im in images: if not previous: # first image # gather data palette = getheader(im)[1] data = getdata(im) imdes, data = data[0], data[1:] header = CreateAnimationHeader(im) appext = CreateApplicationExtension(loops) graphext = CreateGraphicsControlExtension(durations[0]) # write global header fp.write(header) fp.write(palette) fp.write(appext) # write image fp.write(graphext) fp.write(imdes) for d in data: fp.write(d) else: # gather info (compress difference) data = getdata(im) imdes, data = data[0], data[1:] graphext = CreateGraphicsControlExtension(durations[frames]) # write image fp.write(graphext) fp.write(imdes) for d in data: fp.write(d) # prepare for next round previous = im.copy() frames = frames + 1 fp.write(";") # end gif return frames
def _writeGifToFile(fp, images, durations, loops): """ 把一系列图像转换为字节并存入文件流中 """ # 初始化 frames = 0 previous = None for im in images: if not previous: # 第一个图像 # 获取相关数据 palette = getheader(im)[1] #取第一个图像的调色板 data = getdata(im) imdes, data = data[0], data[1:] header = getheaderAnim(im) appext = getAppExt(loops) graphext = getGraphicsControlExt(durations[0]) # 写入全局头 fp.write(header) fp.write(palette) fp.write(appext) # 写入图像 fp.write(graphext) fp.write(imdes) for d in data: fp.write(d) else: # 获取相关数据 data = getdata(im) imdes, data = data[0], data[1:] graphext = getGraphicsControlExt(durations[frames]) # 写入图像 fp.write(graphext) fp.write(imdes) for d in data: fp.write(d) # 准备下一个回合 previous = im.copy() frames = frames + 1 fp.write(";") # 写入完成 return frames
def write_gif_to_file(fp, images, durations, loops): """ 把一系列图像转换为字节并存入文件流中 """ # 初始化 frames = 0 previous = None for im in images: if not previous: # 第一个图像 # 获取相关数据 palette = getheader(im)[1] # 取第一个图像的调色板 data = getdata(im) im_des, data = data[0], data[1:] header = get_header_animat(im) app_ext = get_app_ext(loops) graph_ext = get_graphics_control_ext(durations[0]) # 写入全局头 fp.write(header) fp.write(palette) fp.write(app_ext) # 写入图像 fp.write(graph_ext) fp.write(im_des) for d in data: fp.write(d) else: # 获取相关数据 data = getdata(im) im_des, data = data[0], data[1:] graph_ext = get_graphics_control_ext(durations[frames]) # 写入图像 fp.write(graph_ext) fp.write(im_des) for d in data: fp.write(d) # 准备下一个回合 previous = im.copy() frames += 1 # 写入完成 fp.write(";") return frames
def _writeGifToFile(fp, images, durations, loops): """ Given a set of images writes the bytes to the specified stream. """ # init frames = 0 previous = False for im in images: if not previous: palette = getheader(im)[1] data = getdata(im) imdes, data = data[0], data[1:] header = getheaderAnim(im) appext = getAppExt(loops) graphext = getGraphicsControlExt(durations[0]) # write global header fp.write(header) fp.write(palette) fp.write(appext) # write image fp.write(graphext) fp.write(imdes) for d in data: fp.write(d) else: # gather info (compress difference) data = getdata(im) imdes, data = data[0], data[1:] graphext = getGraphicsControlExt(durations[frames]) # write image fp.write(graphext) fp.write(imdes) for d in data: fp.write(d) previous = im.copy() frames = frames + 1 fp.write(";") # end gif return frames
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 loops = 2 ** 16 - 1 for s in getheader(im, info={"loop": loops})[0] + getdata(im, duration=10, loop=2 ** 16 - 1): 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], duration=10): fp.write(s) else: # FIXME: what should we do in this case? pass previous = im.copy() frames += 1 fp.write(b";") return frames
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 _writeGifToFile(fp, images, durations, loops): # init frames = 0 previous = None for im in images: if not previous: # first frame palette = getheader(im)[1] data = getdata(im) imdes, data = data[0], data[1:] header = getheaderAnim(im) appext = getAppExt(loops) graphext = getGraphicsControlExt(durations[0]) # write global header fp.write(header) fp.write(palette) fp.write(appext) # write images fp.write(graphext) fp.write(imdes) for d in data: fp.write(d) else: data = getdata(im) imdes, data = data[0], data[1:] graphext = getGraphicsControlExt(durations[frames]) # write images fp.write(graphext) fp.write(imdes) for d in data: fp.write(d) # for next loop previous = im.copy() frames += 1 fp.write(";") # done return frames
def makedelta(fp, sequence): """Convert list of image frames to a GIF animation file""" frames = 0 previous = None for im in sequence: # # FIXME: write graphics control block before each frame if not previous: for data in filter(None, getheader(im)): if isinstance(data, list): for d in data: fp.write(d) else: fp.write(data) # global header for data in getdata(im): fp.write(data) else: # delta frame delta = ImageChops.subtract_modulo(im, previous) bbox = delta.getbbox() if bbox: # compress difference for data in getdata(im.crop(bbox), offset = bbox[:2]): if isinstance(data, bytes): fp.write(data) else: import pdb; pdb.set_trace() fp.write(bytes(data)) else: # FIXME: what should we do in this case? pass previous = im.copy() frames = frames + 1 fp.write(b';') return frames
def makeAnimatedGIF(filename, images): """Convert list of image frames to a GIF animation file using simple delta coding """ frames = 0 previous = None fp = open(filename, 'wb') if images[0].mode in ('RGB', 'RGBA'): # first make an optimised palette optimPalette = makePalette(images, verbose=True) for n, im in enumerate(images): print('converting frame %i of %i to GIF' % (n + 1, len(images))) if im.mode == 'RGB': im = rgb2palette(im, palette=optimPalette, verbose=False) if not previous: # global header for s in getheader(im) + getdata(im): fp.write(s) else: # delta frame delta = ImageChops.subtract_modulo(im, previous) bbox = delta.getbbox() # compress difference if bbox: for s in getdata(im.crop(bbox), offset=bbox[:2]): fp.write(s) else: for s in getdata(im): fp.write(s) previous = im.copy() frames += 1 fp.write(";") fp.close() return frames
def writeGifToFile(self, fp, images, durations, loops, xys, disposes): """ writeGifToFile(fp, images, durations, loops, xys, disposes) Given a set of images writes the bytes to the specified stream. """ # Obtain palette for all images and count each occurance palettes, occur = [], [] for im in images: #palette = getheader(im)[1] palette = getheader(im)[0][-1] if not palette: #palette = PIL.ImagePalette.ImageColor palette = im.palette.tobytes() palettes.append(palette) for palette in palettes: occur.append( palettes.count( palette ) ) # Select most-used palette as the global one (or first in case no max) globalPalette = palettes[ occur.index(max(occur)) ] # Init frames = 0 firstFrame = True for im, palette in zip(images, palettes): if firstFrame: # Write header # Gather info header = self.getheaderAnim(im) appext = self.getAppExt(loops) # Write fp.write(encode(header)) fp.write(globalPalette) fp.write(encode(appext)) # Next frame is not the first firstFrame = False if True: # Write palette and image data # Gather info data = getdata(im) imdes, data = data[0], data[1:] graphext = self.getGraphicsControlExt(durations[frames], disposes[frames]) # Make image descriptor suitable for using 256 local color palette lid = self.getImageDescriptor(im, xys[frames]) # Write local header if (palette != globalPalette) or (disposes[frames] != 2): # Use local color palette fp.write(encode(graphext)) fp.write(encode(lid)) # write suitable image descriptor fp.write(palette) # write local color table fp.write(encode('\x08')) # LZW minimum size code else: # Use global color palette fp.write(encode(graphext)) fp.write(imdes) # write suitable image descriptor # Write image data for d in data: fp.write(d) # Prepare for next round frames = frames + 1 fp.write(encode(";")) # end gif return frames
def _writeGifToFile(fp, images, durations, loops): """ Given a set of images writes the bytes to the specified stream. """ # init frames = 0 previous = None for im in images: if not previous: # first image # gather data palette = getheader(im)[1] data = getdata(im) imdes, data = data[0], data[1:] header = getheaderAnim(im) appext = getAppExt(loops) graphext = getGraphicsControlExt(durations[0]) # write global header fp.write(header) fp.write(palette) fp.write(appext) # write image fp.write(graphext) fp.write(imdes) for d in data: fp.write(d) else: # gather info (compress difference) data = getdata(im) imdes, data = data[0], data[1:] graphext = getGraphicsControlExt(durations[frames]) # write image fp.write(graphext) fp.write(imdes) for d in data: fp.write(d) # # delta frame - does not seem to work # delta = ImageChops.subtract_modulo(im, previous) # bbox = delta.getbbox() # # if bbox: # # # gather info (compress difference) # data = getdata(im.crop(bbox), offset = bbox[:2]) # imdes, data = data[0], data[1:] # graphext = getGraphicsControlExt(durations[frames]) # # # write image # fp.write(graphext) # fp.write(imdes) # for d in data: # fp.write(d) # # else: # # FIXME: what should we do in this case? # pass # prepare for next round previous = im.copy() frames = frames + 1 fp.write(";") # end gif return frames
def writeGifToFile(self, fp, images, durations, loops, xys, disposes): """writeGifToFile(fp, images, durations, loops, xys, disposes) Given a set of images writes the bytes to the specified stream. """ # Obtain palette for all images and count each occurance palettes, occur = [], [] for im in images: header, usedPaletteColors = getheader(im) palettes.append( header[-1]) # Last part of the header is the frame palette for palette in palettes: occur.append(palettes.count(palette)) # Select most-used palette as the global one (or first in case no max) globalPalette = palettes[occur.index(max(occur))] # Init frames = 0 firstFrame = True for im, palette in zip(images, palettes): if firstFrame: # Write header # Gather info header = self.getheaderAnim(im) appext = self.getAppExt(loops) # Write fp.write(header) fp.write(globalPalette) fp.write(appext) # Next frame is not the first firstFrame = False if True: # Write palette and image data # Gather info data = getdata(im) imdes, data = b"".join(data[:-2]), data[-2:] graphext = self.getGraphicsControlExt(durations[frames], disposes[frames]) # Make image descriptor suitable for using # 256 local color palette lid = self.getImageDescriptor(im, xys[frames]) # Write local header if (palette != globalPalette) or (disposes[frames] != 2): # Use local color palette fp.write(graphext) fp.write(lid) # write suitable image descriptor fp.write(palette) # write local color table fp.write(b"\x08") # LZW minimum size code else: # Use global color palette fp.write(graphext) fp.write(imdes) # write suitable image descriptor for d in data: fp.write(d) # Prepare for next round frames = frames + 1 fp.write(b";") # end gif return frames
def writeGifToFile(self, fp, images, durations, loops, xys, disposes): """ writeGifToFile(fp, images, durations, loops, xys, disposes) Given a set of images writes the bytes to the specified stream. Requires different handling of palette for PIL and Pillow: based on https://github.com/rec/echomesh/blob/master/ code/python/external/images2gif.py """ # Obtain palette for all images and count each occurrence palettes, occur = [], [] for im in images: if not pillow: palette = getheader(im)[1] else: palette = getheader(im)[0][-1] if not palette: palette = im.palette.tobytes() palettes.append(palette) for palette in palettes: occur.append(palettes.count(palette)) # Select most-used palette as the global one (or first in case no max) globalPalette = palettes[occur.index(max(occur))] # Init frames = 0 firstFrame = True for im, palette in zip(images, palettes): if firstFrame: # Write header # Gather info header = self.getheaderAnim(im) appext = self.getAppExt(loops) # Write fp.write(header) fp.write(globalPalette) fp.write(appext) # Next frame is not the first firstFrame = False if True: # Write palette and image data # Gather info data = getdata(im) imdes, data = data[0], data[1:] graphext = self.getGraphicsControlExt(durations[frames], disposes[frames]) # Make image descriptor suitable for using 256 local color palette lid = self.getImageDescriptor(im, xys[frames]) # Write local header if (palette != globalPalette) or (disposes[frames] != 2): # Use local color palette fp.write(graphext) fp.write(lid) # write suitable image descriptor fp.write(palette) # write local color table fp.write('\x08') # LZW minimum size code else: # Use global color palette fp.write(graphext) fp.write(imdes) # write suitable image descriptor # Write image data for d in data: fp.write(d) # Prepare for next round frames = frames + 1 fp.write(";") # end gif return frames
def write_gif_to_file(self, fp, images, durations, loops, xys, disposes): """Given a set of images writes the bytes to the specified stream.""" # Obtain palette for all images and count each occurance palettes, occur = [], [] for im in images: palettes.append(getheader(im)[0][-1]) for palette in palettes: occur.append(palettes.count(palette)) # Select most-used palette as the global one (or first in case no max) global_palette = palettes[occur.index(max(occur))] # Init frames = 0 first_frame = True for im, palette in zip(images, palettes): if first_frame: # Write header # Gather info header = self.get_header_anim(im) appext = self.get_application_ext(loops) # Write fp.write(header) fp.write(global_palette) fp.write(appext) # Next frame is not the first first_frame = False if True: # Write palette and image data # Gather info data = getdata(im) imdes, data = data[0], data[1:] transparent_flag = 1 if self.transparency else 0 graphext = self.get_graphics_control_ext( durations[frames], disposes[frames], transparent_flag=transparent_flag, transparency_index=255) # Make image descriptor suitable for using 256 local color palette lid = self.get_image_descriptor(im, xys[frames]) # Write local header if (palette != global_palette) or (disposes[frames] != 2): # Use local color palette fp.write(graphext) fp.write(lid) # write suitable image descriptor fp.write(palette) # write local color table fp.write('\x08') # LZW minimum size code else: # Use global color palette fp.write(graphext) fp.write(imdes) # write suitable image descriptor # Write image data for d in data: fp.write(d) # Prepare for next round frames = frames + 1 fp.write(";") # end gif return frames
def writeGifToFile(self, fp, images, durations, loops, xys, disposes): """ writeGifToFile(fp, images, durations, loops, xys, disposes) Given a set of images writes the bytes to the specified stream. """ # Obtain palette for all images and count each occurance palettes, occur = [], [] for im in images: palette = getheader(im)[1] if not palette: palette = PIL.ImagePalette.ImageColor if isinstance(palette, type(os)): # Older or newer? version of Pil(low) data = PIL.ImagePalette.ImagePalette().getdata() palette = data[0].encode('utf-8') + data[1] # Arg this does not work. Go use imageio raise RuntimeError('Cannot get palette. ' 'Maybe you should try imageio instead.') palettes.append(palette) for palette in palettes: occur.append(palettes.count(palette)) # Select most-used palette as the global one (or first in case no max) globalPalette = palettes[ occur.index(max(occur)) ] # Init frames = 0 firstFrame = True for im, palette in zip(images, palettes): if firstFrame: # Write header # Gather info header = self.getheaderAnim(im) appext = self.getAppExt(loops) # Write fp.write(header)#.encode('utf-8')) fp.write(globalPalette) fp.write(appext)#.encode('utf-8')) # Next frame is not the first firstFrame = False if True: # Write palette and image data # Gather info data = getdata(im) imdes, data = data[0], data[1:] graphext = self.getGraphicsControlExt(durations[frames], disposes[frames]) # Make image descriptor suitable for using 256 local color palette lid = self.getImageDescriptor(im, xys[frames]) # Write local header if (palette != globalPalette) or (disposes[frames] != 2): # Use local color palette fp.write(graphext)#.encode('utf-8')) fp.write(lid)#.encode('utf-8')) # write suitable image descriptor fp.write(palette) # write local color table fp.write('\x08'.encode('utf-8')) # LZW minimum size code else: # Use global color palette fp.write(graphext.encode('utf-8')) fp.write(imdes) # write suitable image descriptor # Write image data for d in data: fp.write(d) # Prepare for next round frames = frames + 1 fp.write(";".encode('utf-8')) # end gif return frames
def _writeGifToFile(fp, images, durations, loops): """ Given a set of images writes the bytes to the specified stream. """ # Obtain palette for all images and count each occurance palettes, occur = [], [] for im in images: palettes.append(getheader(im)[1]) for palette in palettes: occur.append(palettes.count(palette)) # Select most-used palette as the global one (or first in case no max) globalPalette = palettes[occur.index(max(occur))] # Init frames = 0 firstFrame = True for im, palette in zip(images, palettes): if firstFrame: # Write header # Gather info header = getheaderAnim(im) appext = getAppExt(loops) # Write fp.write(header) fp.write(globalPalette) fp.write(appext) # Next frame is not the first firstFrame = False if True: # Write palette and image data # Gather info data = getdata(im) imdes, data = data[0], data[1:] graphext = getGraphicsControlExt(durations[frames]) # Make image descriptor suitable for using 256 local color palette lid = getImageDescriptor(im) # Write local header if palette != globalPalette: # Use local color palette fp.write(graphext) fp.write(lid) # write suitable image descriptor fp.write(palette) # write local color table fp.write('\x08') # LZW minimum size code else: # Use global color palette fp.write(graphext) fp.write(imdes) # write suitable image descriptor # Write image data for d in data: fp.write(d) # Prepare for next round frames = frames + 1 fp.write(";") # end gif return frames
def writeGifToFile(self, fp, images, durations, loops, xys, disposes): """ writeGifToFile(fp, images, durations, loops, xys, disposes) Given a set of images writes the bytes to the specified stream. """ # Obtain palette for all images and count each occurance palettes, occur = [], [] for im in images: palette = getheader(im)[1] if not palette: palette = PIL.ImagePalette.ImageColor if isinstance(palette, type(os)): # Older or newer? version of Pil(low) data = PIL.ImagePalette.ImagePalette().getdata() palette = data[0].encode('utf-8') + data[1] # Arg this does not work. Go use imageio raise RuntimeError('Cannot get palette. ' 'Maybe you should try imageio instead.') palettes.append(palette) for palette in palettes: occur.append(palettes.count(palette)) # Select most-used palette as the global one (or first in case no max) globalPalette = palettes[occur.index(max(occur))] # Init frames = 0 firstFrame = True for im, palette in zip(images, palettes): if firstFrame: # Write header # Gather info header = self.getheaderAnim(im) appext = self.getAppExt(loops) # Write fp.write(header.encode('utf-8')) fp.write(globalPalette) fp.write(appext.encode('utf-8')) # Next frame is not the first firstFrame = False if True: # Write palette and image data # Gather info data = getdata(im) imdes, data = data[0], data[1:] graphext = self.getGraphicsControlExt(durations[frames], disposes[frames]) # Make image descriptor suitable for using 256 local color palette lid = self.getImageDescriptor(im, xys[frames]) # Write local header if (palette != globalPalette) or (disposes[frames] != 2): # Use local color palette fp.write(graphext.encode('utf-8')) fp.write( lid.encode('utf-8')) # write suitable image descriptor fp.write(palette) # write local color table fp.write('\x08'.encode('utf-8')) # LZW minimum size code else: # Use global color palette fp.write(graphext.encode('utf-8')) fp.write(imdes) # write suitable image descriptor # Write image data for d in data: fp.write(d) # Prepare for next round frames = frames + 1 fp.write(";".encode('utf-8')) # end gif return frames