-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtestgif.py
executable file
·145 lines (128 loc) · 4.85 KB
/
testgif.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
#!/usr/bin/python3
# based on: https://github.com/deshipu/circuitpython-gif/blob/master/code.py
import struct
#import traceback
def read_blockstream(f):
data=b''
while True:
size = f.read(1)[0]
# print("block",size)
if size==0: break
data+=f.read(size)
print("GIF blockstream len:",len(data))
return data
class EndOfData(Exception):
pass
class LZWDict:
def __init__(self, code_size):
self.code_size = code_size
self.clear_code = 1 << code_size
self.end_code = self.clear_code + 1
self.codes = []
self.clear()
def clear(self):
self.last = b''
self.code_len = self.code_size + 1
self.codes[:] = []
def decode(self, code):
if code == self.clear_code:
print("GIF lzw: clear code found")
self.clear()
return b''
elif code == self.end_code:
print("GIF lzw: end code reached")
raise EndOfData()
elif code < self.clear_code:
value = bytes([code])
elif code <= len(self.codes) + self.end_code:
value = self.codes[code - self.end_code - 1]
else:
value = self.last + self.last[0:1]
if self.last:
self.codes.append(self.last + value[0:1])
if (len(self.codes) + self.end_code + 1 >= 1 << self.code_len and
self.code_len < 12):
self.code_len += 1
self.last = value
return value
def lzw_decode(data, code_size):
dictionary = LZWDict(code_size)
bit = 0
byte=data[0]
p=1
try:
while True:
code = 0
for i in range(dictionary.code_len):
if bit >= 8:
bit = 0
# if p>=len(data): break # EOF
byte=data[p]
p+=1
code |= ((byte >> bit) & 0x01) << i
bit += 1
yield dictionary.decode(code)
except EndOfData:
print("GIF EndOfData:",p,len(data))
except Exception as e:
print("GIF lzw error:",repr(e))
class Frame:
def __init__(self, f, colors):
# self.bitmap_class = bitmap
# self.palette_class = palette
self.x, self.y, self.w, self.h, flags = struct.unpack('<HHHHB', f.read(9))
self.palette_flag = (flags & 0x80) != 0
self.interlace_flag = (flags & 0x40) != 0
self.sort_flag = (flags & 0x20) != 0
self.palette_size = 1 << ((flags & 0x07) + 1)
print("GIF-frame:",self.x, self.y, self.palette_size if self.palette_flag else -1, self.w, self.h, flags) # GIF-frame: 0 0 2 721 721 0
if self.palette_flag:
self.read_palette(f)
colors = self.palette_size
self.min_code_sz = f.read(1)[0]
self.data = read_blockstream(f)
self.pixels=0
for decoded in lzw_decode(self.data, self.min_code_sz): self.pixels+=len(decoded) # decode stream
def read_palette(self, f):
self.palette = [None]*self.palette_size
for i in range(self.palette_size):
self.palette[i] = f.read(3)
def testgif(f):
try:
# header
magic = f.read(6)
if magic not in [b'GIF87a', b'GIF89a']: return 100 # raise ValueError("Not GIF file")
w, h, flags, background, aspect = struct.unpack('<HHBBB', f.read(7))
palette_flag = (flags & 0x80) != 0
sort_flag = (flags & 0x08) != 0
color_bits = ((flags & 0x70) >> 4) + 1
palette_size = 1 << ((flags & 0x07) + 1)
print("GIF:",w, h, palette_size, flags, background, aspect) # GIF: 721 721 64 213 0 0
if w<0 or w>8192 or h<0 or h>4096: return 10 # bad size # gif/Auflage_Gasfeder.GIF: GIF image data, version 87a, 4277 x 3024
if palette_flag: palette = f.read(3*palette_size)
ok=0
while True:
block_type = f.read(1)
if len(block_type)!=1: break # EOF
block_type=block_type[0] # bytes->int
print("GIF: block 0x%X"%block_type)
if block_type == 0x3b:
break
elif block_type == 0x2c:
frame=Frame(f, palette_size)
print("GIF frame pixels:",frame.pixels,frame.w*frame.h)
if frame.pixels == frame.w*frame.h: ok+=1
# break # XXX only read the first frame for now
elif block_type == 0x21:
extension_type = f.read(1)[0] # 0x01 = label, 0xfe = comment
ext_data = read_blockstream(f)
else:
return 20 # raise ValueError('Bad block {0:2x}'.format(block_type))
print("GIF: %d frames decoded OK"%ok)
return 0 if ok else 1
except Exception as e:
print(repr(e))
# print("exception while decoding:"+traceback.format_exc())
return 100
if __name__ == "__main__":
with open("hibas.gif", 'rb') as f: testgif(f)