-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathimages.py
80 lines (65 loc) · 3.05 KB
/
images.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
from PIL import Image
from PyQt4 import QtGui
from apng import APNG
import io
APNG_DISPOSE_OP_NONE = 0
APNG_DISPOSE_OP_BACKGROUND = 1
APNG_DISPOSE_OP_PREVIOUS = 2
APNG_BLEND_OP_SOURCE = 0
APNG_BLEND_OP_OVER = 1
disposes = ["APNG_DISPOSE_OP_NONE", "APNG_DISPOSE_OP_BACKGROUND", "APNG_DISPOSE_OP_PREVIOUS"]
blends = ["APNG_BLEND_OP_SOURCE", "APNG_BLEND_OP_OVER"]
# layman's terms of above apng constants so i can easily wrap my head around it:
#
# APNG_DISPOSE_OP_NONE: do nothing with next frame, keep it as it is
# APNG_DISPOSE_OP_BACKGROUND: turn the current frame into full transparency before pasting the next frame
# APNG_DISPOSE_OP_PREVIOUS: grab the previous frame, and paste the next one into THAT previous frame
#
# APNG_BLEND_OP_SOURCE: replace frame region
# APNG_BLEND_OP_OVER: blend with frame
def load_apng(file): # this one was hell to implement compared to the three funcs below
img = APNG.open(file)
frames = []
pilframes = []
dispose_op = 0
dur = 0
width, height = img.frames[0][0].width, img.frames[0][0].height
outputbuf = Image.new("RGBA", (width, height), (255,255,255,0))
prev_frame = None
for frame, frame_info in img.frames:
i = img.frames.index((frame, frame_info))
pilframe = Image.open(io.BytesIO(frame.to_bytes())).convert("RGBA")
#print str(i)+"\t"+disposes[dispose_op]+"\t\t"+blends[frame_info.blend_op]
if dispose_op == APNG_DISPOSE_OP_BACKGROUND or (i == 0 and dispose_op == APNG_DISPOSE_OP_PREVIOUS):
prev_frame = outputbuf.copy()
emptyrect = Image.new("RGBA", (img.frames[i-1][0].width, img.frames[i-1][0].height), (255,255,255,0))
outputbuf.paste(emptyrect, (img.frames[i-1][1].x_offset, img.frames[i-1][1].y_offset))
elif dispose_op == APNG_DISPOSE_OP_PREVIOUS:
outputbuf = prev_frame.copy()
else:
prev_frame = outputbuf.copy()
if frame_info:
outputbuf.paste(pilframe, (frame_info.x_offset, frame_info.y_offset), pilframe.convert("RGBA") if frame_info.blend_op == APNG_BLEND_OP_OVER else None)
else:
outputbuf.paste(pilframe, (0, 0))
final_frame = outputbuf.copy()
pilframes.append(final_frame)
if frame_info:
dur += frame_info.delay*10 # convert delay from centiseconds to milliseconds
frames.append([final_frame.toqimage(), frame_info.delay*10]) # convert delay from centiseconds to milliseconds
dispose_op = frame_info.depose_op
else:
frames.append([final_frame.toqimage(), 0])
for frame in pilframes: frame.close()
return frames, dur
#return pilframes
def load_webp(file):
img = Image.open(file)
frames = []
dur = 0
for i in range(img.n_frames):
img.seek(i)
img.load() # strange thing with Pillow and animated webp's is that the img.info dictionary attr doesn't update unless you call a function like this
frames.append([img.toqimage(), img.info["duration"]])
dur += img.info["duration"]
return frames, img.info["loop"], dur