This repository has been archived by the owner on Apr 13, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 63
/
giftool.py
185 lines (159 loc) · 5.17 KB
/
giftool.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# __author__ = 'Yaoshi'
# -*- coding: utf-8 -*-
import ImageGrab # from PIL
import time
import numpy as np
import string
from PIL import Image, ImageChops
from PIL.GifImagePlugin import getheader, getdata
import os
def intToBin(i):
# int to binary
i1 = i % 256
i2 = int(i / 256)
return chr(i1) + chr(i2)
def getheaderAnim(im):
# generate the head of the gif
bb = "GIF89a"
bb += intToBin(im.size[0])
bb += intToBin(im.size[1])
bb += "\x87\x00\x00"
return bb
def getAppExt(loops=0):
# get application extension
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):
# set duration between every 2 frames
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):
# 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 writeGif(filename, images, duration=0.1, loops=0, dither=1):
# images is a PIL Image [] or Numpy Array
images2 = []
# image to 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 format
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("Image format error")
images2.append(im)
else:
raise ValueError("Unknown format")
durations = [duration for im in images2]
fp = open(filename, 'wb')
try:
n = _writeGifToFile(fp, images2, durations, loops)
finally:
fp.close()
return n
# merge frame to build a new 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
# git to images
def gif2images(filename, distDir='.', type='bmp'):
if not os.path.exists(distDir):
os.mkdir(distDir)
print 'splitting', 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 += 1
try:
while 1:
im.seek(im.tell() + 1)
im.convert(mode).save(distDir + '/%d.' % cnt + type)
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 split to directory: [', distDir, ']'
return cnt # total number of frames
if __name__ == '__main__':
frames = gif2images('', 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)