1
1
import time
2
2
import array
3
- import digitalio
4
3
import struct
5
4
try :
6
5
import zlib
@@ -155,8 +154,6 @@ def __init__(self, filename):
155
154
self .colors = 0
156
155
157
156
def read_header (self ):
158
- """Read the file's header information."""
159
-
160
157
if self .colors :
161
158
return
162
159
with open (self .filename , 'rb' ) as f :
@@ -168,10 +165,9 @@ def read_header(self):
168
165
f .seek (46 )
169
166
self .colors = int .from_bytes (f .read (4 ), 'little' )
170
167
171
- def read_palette (self ):
172
- """Read the color palette information."""
173
-
174
- palette = array .array ('H' , (0 for i in range (16 )))
168
+ def read_palette (self , palette = None ):
169
+ if palette is None :
170
+ palette = array .array ('H' , (0 for i in range (16 )))
175
171
with open (self .filename , 'rb' ) as f :
176
172
f .seek (self .data - self .colors * 4 )
177
173
for color in range (self .colors ):
@@ -181,7 +177,6 @@ def read_palette(self):
181
177
return palette
182
178
183
179
def read_data (self , buffer = None ):
184
- """Read the image data."""
185
180
line_size = self .width >> 1
186
181
if buffer is None :
187
182
buffer = bytearray (line_size * self .height )
@@ -196,143 +191,6 @@ def read_data(self, buffer=None):
196
191
return buffer
197
192
198
193
199
- def read_blockstream (f ):
200
- while True :
201
- size = f .read (1 )[0 ]
202
- if size == 0 :
203
- break
204
- for i in range (size ):
205
- yield f .read (1 )[0 ]
206
-
207
-
208
- class EndOfData (Exception ):
209
- pass
210
-
211
-
212
- class LZWDict :
213
- def __init__ (self , code_size ):
214
- self .code_size = code_size
215
- self .clear_code = 1 << code_size
216
- self .end_code = self .clear_code + 1
217
- self .codes = []
218
- self .clear ()
219
-
220
- def clear (self ):
221
- self .last = b''
222
- self .code_len = self .code_size + 1
223
- self .codes [:] = []
224
-
225
- def decode (self , code ):
226
- if code == self .clear_code :
227
- self .clear ()
228
- return b''
229
- elif code == self .end_code :
230
- raise EndOfData ()
231
- elif code < self .clear_code :
232
- value = bytes ([code ])
233
- elif code <= len (self .codes ) + self .end_code :
234
- value = self .codes [code - self .end_code - 1 ]
235
- else :
236
- value = self .last + self .last [0 :1 ]
237
- if self .last :
238
- self .codes .append (self .last + value [0 :1 ])
239
- if (len (self .codes ) + self .end_code + 1 >= 1 << self .code_len and
240
- self .code_len < 12 ):
241
- self .code_len += 1
242
- self .last = value
243
- return value
244
-
245
-
246
- def lzw_decode (data , code_size ):
247
- dictionary = LZWDict (code_size )
248
- bit = 0
249
- try :
250
- byte = next (data )
251
- try :
252
- while True :
253
- code = 0
254
- for i in range (dictionary .code_len ):
255
- code |= ((byte >> bit ) & 0x01 ) << i
256
- bit += 1
257
- if bit >= 8 :
258
- bit = 0
259
- byte = next (data )
260
- yield dictionary .decode (code )
261
- except EndOfData :
262
- while True :
263
- next (data )
264
- except StopIteration :
265
- return
266
-
267
-
268
- class GIF16 :
269
- """Read 16-color GIF files."""
270
-
271
- def __init__ (self , filename ):
272
- self .filename = filename
273
-
274
- def read_header (self ):
275
- with open (self .filename , 'rb' ) as f :
276
- header = f .read (6 )
277
- if header not in {b'GIF87a' , b'GIF89a' }:
278
- raise ValueError ("Not GIF file" )
279
- self .width , self .height , flags , self .background, self .aspect = (
280
- struct .unpack ('<HHBBB' , f .read (7 )))
281
- self .palette_size = 1 << ((flags & 0x07 ) + 1 )
282
- if not flags & 0x80 :
283
- raise NotImplementedError ()
284
- if self .palette_size > 16 :
285
- raise ValueError ("Too many colors (%d/16)." % self .palette_size )
286
-
287
- def read_palette (self ):
288
- palette = array .array ('H' , (0 for i in range (16 )))
289
- with open (self .filename , 'rb' ) as f :
290
- f .seek (13 )
291
- for color in range (self .palette_size ):
292
- buffer = f .read (3 )
293
- c = color565 (buffer [0 ], buffer [1 ], buffer [2 ])
294
- palette [color ] = ((c << 8 ) | (c >> 8 )) & 0xffff
295
- return palette
296
-
297
- def read_data (self , buffer = None ):
298
- line_size = (self .width + 1 ) >> 1
299
- if buffer is None :
300
- buffer = bytearray (line_size * self .height )
301
- with open (self .filename , 'rb' ) as f :
302
- f .seek (13 + self .palette_size * 3 )
303
- while True : # skip to first frame
304
- block_type = f .read (1 )[0 ]
305
- if block_type == 0x2c :
306
- break
307
- elif block_type == 0x21 : # skip extension
308
- extension_type = f .read (1 )[0 ]
309
- while True :
310
- size = f .read (1 )[0 ]
311
- if size == 0 :
312
- break
313
- f .seek (1 , size )
314
- elif block_type == 0x3b :
315
- raise NotImplementedError ()
316
- x , y , w , h , flags = struct .unpack ('<HHHHB' , f .read (9 ))
317
- if (flags & 0x80 or flags & 0x40 or
318
- w != self .width or h != self .height or x != 0 or y != 0 ):
319
- raise NotImplementedError ()
320
- min_code_size = f .read (1 )[0 ]
321
- x = 0
322
- y = 0
323
- for decoded in lzw_decode (read_blockstream (f ), min_code_size ):
324
- for pixel in decoded :
325
- if x & 0x01 :
326
- buffer [(x >> 1 ) + y * line_size ] |= pixel
327
- else :
328
- buffer [(x >> 1 ) + y * line_size ] = pixel << 4
329
- x += 1
330
- if (x >= self .width ):
331
- x = 0
332
- y += 1
333
- return buffer
334
-
335
-
336
194
class PNG16 :
337
195
"""Read 16-color PNG files."""
338
196
@@ -564,6 +422,7 @@ def __init__(self, width, height, font=None, palette=None, buffer=None):
564
422
565
423
def char (self , x , y , c = None , hightlight = False ):
566
424
"""Get or set the character at the given location."""
425
+
567
426
if not 0 <= x < self .width or not 0 <= y < self .height :
568
427
return
569
428
if c is None :
@@ -575,6 +434,7 @@ def char(self, x, y, c=None, hightlight=False):
575
434
576
435
def move (self , x , y , z = None ):
577
436
"""Shift the whole layer respective to the screen."""
437
+
578
438
self .x = x
579
439
self .y = y
580
440
if z is not None :
@@ -583,6 +443,7 @@ def move(self, x, y, z=None):
583
443
584
444
def cursor (self , x = None , y = None ):
585
445
"""Move the text cursor to the specified row and column."""
446
+
586
447
if y is not None :
587
448
self .row = min (max (0 , y ), self .width - 1 )
588
449
if x is not None :
@@ -593,6 +454,7 @@ def text(self, text, hightlight=False):
593
454
Display text starting at the current cursor location.
594
455
Return the dimensions of the rendered text.
595
456
"""
457
+
596
458
longest = 0
597
459
tallest = 0
598
460
for c in text :
@@ -612,6 +474,7 @@ def text(self, text, hightlight=False):
612
474
613
475
def clear (self ):
614
476
"""Clear all text from the layer."""
477
+
615
478
for i in range (self .width * self .height ):
616
479
self .buffer [i ] = 0
617
480
@@ -647,6 +510,7 @@ def __init__(self, display, fps=6, scale=None):
647
510
648
511
def tick (self ):
649
512
"""Wait for the start of the next frame."""
513
+
650
514
self .last_tick += self .tick_delay
651
515
wait = max (0 , self .last_tick - time .monotonic ())
652
516
if wait :
@@ -656,6 +520,7 @@ def tick(self):
656
520
657
521
def render_block (self , x0 = None , y0 = None , x1 = None , y1 = None ):
658
522
"""Update a rectangle of the screen."""
523
+
659
524
if x0 is None :
660
525
x0 = self .vx
661
526
if y0 is None :
@@ -676,6 +541,7 @@ def render_block(self, x0=None, y0=None, x1=None, y1=None):
676
541
677
542
def render_sprites (self , sprites ):
678
543
"""Update the spots taken by all the sprites in the list."""
544
+
679
545
layers = [l .layer for l in self .layers ]
680
546
for sprite in sprites :
681
547
x = int (sprite .x ) - self .vx
0 commit comments