gif圖片拆幀及合成[python]實現
阿新 • • 發佈:2019-01-29
python版本2.7,使用PIL庫,程式碼如下:
import ImageGrab # from PIL import time import string from PIL import Image, ImageChops from PIL.GifImagePlugin import getheader, getdata import os def intToBin(i): """ 把整型數轉換為雙位元組 """ # 先分成兩部分,高8位和低8位 i1 = i % 256 i2 = int( i/256) # 合成小端對齊的字串 return chr(i1) + chr(i2) def getheaderAnim(im): """ 生成動畫檔案頭 """ bb = "GIF89a" bb += intToBin(im.size[0]) bb += intToBin(im.size[1]) bb += "\x87\x00\x00" #使用全域性顏色表 return bb def getAppExt(loops=0): """ 應用擴充套件,預設為0,為0是表示動畫是永不停止 """ bb = "\x21\xFF\x0B" # application extension bb += "NETSCAPE2.0" bb += "\x03\x01" if loops == 0: loops = 2**16-1 bb += intToBin(loops) bb += '\x00' # end return bb def getGraphicsControlExt(duration=0.1): """ 設定動畫時間間隔 """ bb = '\x21\xF9\x04' bb += '\x08' # no transparancy bb += intToBin( int(duration*100) ) # in 100th of seconds bb += '\x00' # no transparant color bb += '\x00' # end return bb 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 writeGif(filename, images, duration=0.1, loops=0, dither=1): """ writeGif(filename, images, duration=0.1, loops=0, dither=1) 從輸入的影象序列中建立GIF動畫 images 是一個PIL Image [] 或者 Numpy Array """ images2 = [] # 先把影象轉換為PIL格式 for im in images: if isinstance(im,Image.Image): #如果是PIL Image images2.append( im.convert('P',dither=dither) ) elif np and isinstance(im, np.ndarray): #如果是Numpy格式 if im.dtype == np.uint8: pass elif im.dtype in [np.float32, np.float64]: im = (im*255).astype(np.uint8) else: im = im.astype(np.uint8) # 轉換 if len(im.shape)==3 and im.shape[2]==3: im = Image.fromarray(im,'RGB').convert('P',dither=dither) elif len(im.shape)==2: im = Image.fromarray(im,'L').convert('P',dither=dither) else: raise ValueError("影象格式不正確") images2.append(im) else: raise ValueError("未知影象格式") # 檢查動畫播放時間 durations = [duration for im in images2] # 開啟檔案 fp = open(filename, 'wb') # 寫入GIF try: n = _writeGifToFile(fp, images2, durations, loops) finally: fp.close() return n ############################################################ ## 將多幀點陣圖合成為一幅gif影象 def images2gif( images, giffile, durations=0.05, loops = 1): seq = [] for i in range(len(images)): im = Image.open(images[i]) background = Image.new('RGB', im.size, (255,255,255)) background.paste(im, (0,0)) seq.append(background) frames = writeGif( giffile, seq, durations, loops) print frames, 'images has been merged to', giffile ## 將gif影象每一幀拆成獨立的點陣圖 def gif2images( filename, distDir = '.', type = 'bmp' ): if not os.path.exists(distDir): os.mkdir(distDir) print 'spliting', filename, im = Image.open( filename ) im.seek(0) # skip to the second frame cnt = 0 type = string.lower(type) mode = 'RGB' # image modea if type == 'bmp' or type == 'png': mode = 'P' # image mode im.convert(mode).save(distDir+'/%d.'%cnt+type ) cnt = cnt+1 try: while 1: im.seek(im.tell()+1) im.convert(mode).save(distDir+'/%d.'%cnt+type) cnt = cnt+1 except EOFError: pass # end of sequence white = (255,255,255) preIm = Image.open(distDir+'/%d.'%0+type).convert('RGB') size = preIm.size prePixs = preIm.load() for k in range (1,cnt): print '.', im = Image.open(distDir+'/%d.'%k+type).convert('RGB') pixs = im.load() for i in range(size[0]): for j in range(size[1]): if pixs[i,j] == white: pixs[i,j] = prePixs[i,j] preIm = im prePixs = preIm.load() im.convert(mode).save(distDir+'/%d.'%k+type) print '\n', filename, 'has been splited to directory: [',distDir,']' return cnt # 總幀數 ############################################################## if __name__ == '__main__': frames = gif2images('source.gif',distDir='tmp',type='png') images = [] for i in range(frames-1,-1,-1): images.append('tmp/%d.png'%i) images2gif(images,'save.gif', durations = 0.05)
參考:http://blog.csdn.net/hackjames/article/details/6950837