36
36
__version__ = "0.0.0-auto.0"
37
37
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git"
38
38
39
+
39
40
def load (file , * , bitmap = None , palette = None ):
40
41
"""Loads a GIF image from the open ``file``.
41
42
@@ -48,7 +49,7 @@ def load(file, *, bitmap=None, palette=None):
48
49
header = file .read (6 )
49
50
if header not in {b'GIF87a' , b'GIF89a' }:
50
51
raise ValueError ("Not a GIF file" )
51
- w , h , flags , background , aspect = struct .unpack ('<HHBBB' , file .read (7 ))
52
+ width , height , flags , _ , _ = struct .unpack ('<HHBBB' , file .read (7 ))
52
53
if (flags & 0x80 ) != 0 :
53
54
palette_size = 1 << ((flags & 0x07 ) + 1 )
54
55
palette_obj = palette (palette_size )
@@ -57,70 +58,75 @@ def load(file, *, bitmap=None, palette=None):
57
58
else :
58
59
palette_obj = None
59
60
color_bits = ((flags & 0x70 ) >> 4 ) + 1
60
- bitmap_obj = bitmap (w , h , (1 << color_bits ) - 1 )
61
+ bitmap_obj = bitmap (width , height , (1 << color_bits ) - 1 )
61
62
while True :
62
63
block_type = file .read (1 )[0 ]
63
64
if block_type == 0x2c : # frame
64
- dx , dy , frame_w , frame_h , flags = struct .unpack ('<HHHHB' ,
65
- file .read (9 ))
66
- if (flags & 0x40 ) != 0 :
67
- raise NotImplementedError ("Interlacing not supported" )
68
- if (flags & 0x80 ) != 0 :
69
- palette_size = 1 << ((flags & 0x07 ) + 1 )
70
- frame_palette = palette (palette_size )
71
- for i in range (palette_size ):
72
- frame_palette [i ] = file .read (3 )
73
- if palette_obj is None :
74
- # if there is no global palette, use local one
75
- palette_obj = frame_palette
76
- min_code_size = file .read (1 )[0 ]
77
- x = 0
78
- y = 0
79
- for decoded in lzw_decode (_read_blockstream (file ), min_code_size ):
80
- for byte in decoded :
81
- bitmap_obj [dx + x , dy + y ] = byte
82
- x += 1
83
- if x >= frame_w :
84
- x = 0
85
- y += 1
65
+ _read_frame (file , bitmap_obj )
86
66
elif block_type == 0x21 : # extension
87
- extension_type = file .read (1 )[0 ]
67
+ _ = file .read (1 )[0 ]
88
68
# 0x01 = label, 0xfe = comment
89
- data = bytes (_read_blockstream (file ))
69
+ _ = bytes (_read_blockstream (file ))
90
70
elif block_type == 0x3b : # terminator
91
71
break
92
72
else :
93
73
raise ValueError ("Bad block type" )
94
74
return bitmap_obj , palette_obj
95
75
96
76
97
- def _read_blockstream (f ):
77
+ def _read_frame (file , bitmap ):
78
+ """Read a signle frame and apply it to the bitmap."""
79
+ ddx , ddy , width , _ , flags = struct .unpack ('<HHHHB' , file .read (9 ))
80
+ if (flags & 0x40 ) != 0 :
81
+ raise NotImplementedError ("Interlacing not supported" )
82
+ if (flags & 0x80 ) != 0 :
83
+ palette_size = 1 << ((flags & 0x07 ) + 1 )
84
+ for _ in range (palette_size ):
85
+ _ = file .read (3 )
86
+ min_code_size = file .read (1 )[0 ]
87
+ x = 0
88
+ y = 0
89
+ for decoded in lzw_decode (_read_blockstream (file ), min_code_size ):
90
+ for byte in decoded :
91
+ bitmap [ddx + x , ddy + y ] = byte
92
+ x += 1
93
+ if x >= width :
94
+ x = 0
95
+ y += 1
96
+
97
+
98
+ def _read_blockstream (file ):
99
+ """Read a block from a file."""
98
100
while True :
99
- size = f .read (1 )[0 ]
101
+ size = file .read (1 )[0 ]
100
102
if size == 0 :
101
103
break
102
- for i in range (size ):
103
- yield f .read (1 )[0 ]
104
+ for _ in range (size ):
105
+ yield file .read (1 )[0 ]
104
106
105
107
106
108
class EndOfData (Exception ):
107
- pass
109
+ """Signified end of compressed data."""
108
110
109
111
110
112
class LZWDict :
113
+ """A dictionary of LZW codes."""
111
114
def __init__ (self , code_size ):
112
115
self .code_size = code_size
113
116
self .clear_code = 1 << code_size
114
117
self .end_code = self .clear_code + 1
115
118
self .codes = []
119
+ self .last = None
116
120
self .clear ()
117
121
118
122
def clear (self ):
123
+ """Reset the dictionary to default codes."""
119
124
self .last = b''
120
125
self .code_len = self .code_size + 1
121
126
self .codes [:] = []
122
127
123
128
def decode (self , code ):
129
+ """Decode a code."""
124
130
if code == self .clear_code :
125
131
self .clear ()
126
132
return b''
@@ -135,16 +141,17 @@ def decode(self, code):
135
141
if self .last :
136
142
self .codes .append (self .last + value [0 :1 ])
137
143
if (len (self .codes ) + self .end_code + 1 >= 1 << self .code_len and
138
- self .code_len < 12 ):
139
- self .code_len += 1
144
+ self .code_len < 12 ):
145
+ self .code_len += 1
140
146
self .last = value
141
147
return value
142
148
143
149
144
150
def lzw_decode (data , code_size ):
151
+ """Decode LZW-compressed data."""
145
152
dictionary = LZWDict (code_size )
146
153
bit = 0
147
- byte = next (data )
154
+ byte = next (data ) # pylint: disable=stop-iteration-return
148
155
try :
149
156
while True :
150
157
code = 0
@@ -153,8 +160,8 @@ def lzw_decode(data, code_size):
153
160
bit += 1
154
161
if bit >= 8 :
155
162
bit = 0
156
- byte = next (data )
163
+ byte = next (data ) # pylint: disable=stop-iteration-return
157
164
yield dictionary .decode (code )
158
165
except EndOfData :
159
166
while True :
160
- next (data )
167
+ next (data ) # pylint: disable=stop-iteration-return
0 commit comments