1
1
import utime
2
2
import array
3
+ import struct
3
4
import _stage
4
5
5
6
@@ -167,13 +168,13 @@ def read_palette(self):
167
168
palette [color ] = (c << 8 ) | (c >> 8 )
168
169
return palette
169
170
170
- def read_data (self , offset = 0 , buffer = None ):
171
+ def read_data (self , buffer = None ):
171
172
line_size = self .width >> 1
172
173
if buffer is None :
173
174
buffer = bytearray (line_size * self .height )
174
175
175
176
with open (self .filename , 'rb' ) as f :
176
- f .seek (self .data + offset )
177
+ f .seek (self .data )
177
178
index = (self .height - 1 ) * line_size
178
179
for line in range (self .height ):
179
180
chunk = f .read (line_size )
@@ -182,6 +183,142 @@ def read_data(self, offset=0, buffer=None):
182
183
return buffer
183
184
184
185
186
+ def read_blockstream (f ):
187
+ while True :
188
+ size = f .read (1 )[0 ]
189
+ if size == 0 :
190
+ break
191
+ for i in range (size ):
192
+ yield f .read (1 )[0 ]
193
+
194
+
195
+ class EndOfData (Exception ):
196
+ pass
197
+
198
+
199
+ class LZWDict :
200
+ def __init__ (self , code_size ):
201
+ self .code_size = code_size
202
+ self .clear_code = 1 << code_size
203
+ self .end_code = self .clear_code + 1
204
+ self .codes = []
205
+ self .clear ()
206
+
207
+ def clear (self ):
208
+ self .last = b''
209
+ self .code_len = self .code_size + 1
210
+ self .codes [:] = []
211
+
212
+ def decode (self , code ):
213
+ if code == self .clear_code :
214
+ self .clear ()
215
+ return b''
216
+ elif code == self .end_code :
217
+ raise EndOfData ()
218
+ elif code < self .clear_code :
219
+ value = bytes ([code ])
220
+ elif code <= len (self .codes ) + self .end_code :
221
+ value = self .codes [code - self .end_code - 1 ]
222
+ else :
223
+ value = self .last + self .last [0 :1 ]
224
+ if self .last :
225
+ self .codes .append (self .last + value [0 :1 ])
226
+ if (len (self .codes ) + self .end_code + 1 >= 1 << self .code_len and
227
+ self .code_len < 12 ):
228
+ self .code_len += 1
229
+ self .last = value
230
+ return value
231
+
232
+
233
+ def lzw_decode (data , code_size ):
234
+ dictionary = LZWDict (code_size )
235
+ bit = 0
236
+ try :
237
+ byte = next (data )
238
+ try :
239
+ while True :
240
+ code = 0
241
+ for i in range (dictionary .code_len ):
242
+ code |= ((byte >> bit ) & 0x01 ) << i
243
+ bit += 1
244
+ if bit >= 8 :
245
+ bit = 0
246
+ byte = next (data )
247
+ yield dictionary .decode (code )
248
+ except EndOfData :
249
+ while True :
250
+ next (data )
251
+ except StopIteration :
252
+ return
253
+
254
+
255
+ class GIF16 :
256
+ def __init__ (self , filename ):
257
+ self .filename = filename
258
+
259
+ def read_header (self ):
260
+ with open (self .filename , 'rb' ) as f :
261
+ header = f .read (6 )
262
+ if header not in {b'GIF87a' , b'GIF89a' }:
263
+ raise ValueError ("Not GIF file" )
264
+ self .width , self .height , flags , self .background , self .aspect = (
265
+ struct .unpack ('<HHBBB' , f .read (7 )))
266
+ self .palette_size = 1 << ((flags & 0x07 ) + 1 )
267
+ if not flags & 0x80 or self .palette_size > 16 :
268
+ raise ValueError ("16-color GIF expected" )
269
+
270
+ def read_palette (self ):
271
+ palette = array .array ('H' , (0 for i in range (16 )))
272
+ with open (self .filename , 'rb' ) as f :
273
+ f .seek (13 )
274
+ for color in range (self .palette_size ):
275
+ buffer = f .read (3 )
276
+ c = color565 (buffer [2 ], buffer [1 ], buffer [0 ])
277
+ palette [color ] = (c << 8 ) | (c >> 8 )
278
+ return palette
279
+
280
+ def read_data (self , buffer = None ):
281
+ line_size = self .width >> 1
282
+ if buffer is None :
283
+ buffer = bytearray (line_size * self .height )
284
+ with open (self .filename , 'rb' ) as f :
285
+ f .seek (13 + self .palette_size * 3 )
286
+ while True : # skip to first frame
287
+ block_type = f .read (1 )[0 ]
288
+ if block_type == 0x2c :
289
+ break
290
+ elif block_type == 0x21 : # skip extension
291
+ extension_type = f .read (1 )[0 ]
292
+ while True :
293
+ size = f .read (1 )[0 ]
294
+ if size == 0 :
295
+ break
296
+ f .seek (1 , size )
297
+ elif block_type == 0x3b :
298
+ raise ValueError ("no frames" )
299
+ x , y , w , h , flags = struct .unpack ('<HHHHB' , f .read (9 ))
300
+ if flags & 0x80 :
301
+ raise ValueError ("local palette" )
302
+ if flags & 0x40 :
303
+ raise ValueError ("interlaced" )
304
+ if w != self .width or h != self .height or x != 0 or y != 0 :
305
+ raise ValueError ("partial frame" )
306
+ min_code_size = f .read (1 )[0 ]
307
+ x = 0
308
+ y = 0
309
+ for decoded in lzw_decode (read_blockstream (f ), min_code_size ):
310
+ for pixel in decoded :
311
+ if x & 0x01 :
312
+ buffer [(x >> 1 ) + y * line_size ] |= pixel
313
+ else :
314
+ buffer [(x >> 1 ) + y * line_size ] = pixel << 4
315
+ x += 1
316
+ if (x >= self .width ):
317
+ x = 0
318
+ y += 1
319
+ return buffer
320
+
321
+
185
322
class Bank :
186
323
def __init__ (self , buffer = None , palette = None ):
187
324
self .buffer = buffer
@@ -192,9 +329,19 @@ def from_bmp16(cls, filename):
192
329
bmp = BMP16 (filename )
193
330
bmp .read_header ()
194
331
if bmp .width != 16 or bmp .height != 256 :
195
- raise ValueError ("bitmap size not 16x256" )
332
+ raise ValueError ("image size not 16x256" )
196
333
palette = bmp .read_palette ()
197
- buffer = bmp .read_data (0 )
334
+ buffer = bmp .read_data ()
335
+ return cls (buffer , palette )
336
+
337
+ @classmethod
338
+ def from_gif16 (cls , filename ):
339
+ gif = GIF16 (filename )
340
+ gif .read_header ()
341
+ if gif .width != 16 or gif .height != 256 :
342
+ raise ValueError ("image size not 16x256" )
343
+ palette = gif .read_palette ()
344
+ buffer = gif .read_data ()
198
345
return cls (buffer , palette )
199
346
200
347
0 commit comments