-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathresize_gif.py
118 lines (90 loc) · 2.81 KB
/
resize_gif.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
from PIL import Image
# Original code - https://stackoverflow.com/a/41827681/14746647
def resize_gif(path, resize_to):
"""
Resizes the GIF to a given length
Parameters
----------
path : str
Path of the GIF to resize.
resize_to : tuple
Dimensions to be resize to.
"""
all_frames = extract_and_resize_frames(path, resize_to)
save_as = path
all_frames[0].save(
save_as, optimize=True, save_all=True, append_images=all_frames[1:], loop=1000
)
def analyseImage(path):
"""
Pre-process pass over the image to determine the mode (full or additive).
Necessary as assessing single frames isn't reliable. Need to know the mode
before processing all frames.
Parameters
----------
path : str
Path of the GIF to resize.
"""
im = Image.open(path)
results = {
"size": im.size,
"mode": "full",
}
try:
while True:
if im.tile:
tile = im.tile[0]
update_region = tile[1]
update_region_dimensions = update_region[2:]
if update_region_dimensions != im.size: # pragma: no cover
results["mode"] = "partial"
break
im.seek(im.tell() + 1)
except EOFError:
pass
im.close()
return results
def extract_and_resize_frames(path, resize_to):
"""
Iterate the GIF, extracting each frame and resizing them
Parameter
---------
path : str
Path of the GIF to resize.
Returns
-------
all_frames : list
"""
mode = analyseImage(path)["mode"]
im = Image.open(path)
i = 0
p = im.getpalette()
last_frame = im.convert("RGBA")
all_frames = []
try:
while True:
"""
If the GIF uses local colour tables, each frame will have its own
palette. If not, we need to apply the global palette to the new
frame.
"""
if not im.getpalette(): # pragma: no cover
im.putpalette(p)
new_frame = Image.new("RGBA", im.size)
"""
Is this file a "partial"-mode GIF where frames update a region of
a different size to the entire image? If so, we need to construct
the new frame by pasting it on top of the preceding frames.
"""
if mode == "partial": # pragma: no cover
new_frame.paste(last_frame)
new_frame.paste(im, (0, 0), im.convert("RGBA"))
new_frame.thumbnail(resize_to, Image.ANTIALIAS)
all_frames.append(new_frame)
i += 1
last_frame = new_frame
im.seek(im.tell() + 1)
except EOFError:
pass
im.close()
return all_frames