11# SPDX-FileCopyrightText: 2019 Radomir Dopieralski for Adafruit Industries
2+ # SPDX-FileCopyrightText: 2022 Matt Land
23#
34# SPDX-License-Identifier: MIT
45
910Load pixel values (indices or colors) into a bitmap and colors into a palette
1011from a GIF file.
1112
12- * Author(s): Radomir Dopieralski
13+ * Author(s): Radomir Dopieralski, Matt Land
1314
1415"""
1516
1617import struct
1718
19+ try :
20+ from typing import Tuple , Iterator , Optional , List
21+ from io import BufferedReader
22+ from displayio import Palette , Bitmap
23+ from .displayio_types import PaletteConstructor , BitmapConstructor
24+ except ImportError :
25+ pass
1826
1927__version__ = "0.0.0-auto.0"
2028__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git"
2129
2230
23- def load (file , * , bitmap = None , palette = None ):
31+ def load (
32+ file : BufferedReader ,
33+ * ,
34+ bitmap : BitmapConstructor ,
35+ palette : PaletteConstructor = None
36+ ) -> Tuple [Bitmap , Optional [Palette ]]:
2437 """Loads a GIF image from the open ``file``.
2538
2639 Returns tuple of bitmap object and palette object.
2740
41+ :param BufferedReader file: The *.gif file being loaded
2842 :param object bitmap: Type to store bitmap data. Must have API similar to `displayio.Bitmap`.
2943 Will be skipped if None
3044 :param object palette: Type to store the palette. Must have API similar to
3145 `displayio.Palette`. Will be skipped if None"""
3246 header = file .read (6 )
3347 if header not in {b"GIF87a" , b"GIF89a" }:
3448 raise ValueError ("Not a GIF file" )
35- width , height , flags , _ , _ = struct .unpack ("<HHBBB" , file .read (7 ))
49+ width , height , flags , _ , _ = struct .unpack ( # pylint: disable=no-member
50+ "<HHBBB" , file .read (7 )
51+ )
3652 if (flags & 0x80 ) != 0 :
3753 palette_size = 1 << ((flags & 0x07 ) + 1 )
3854 palette_obj = palette (palette_size )
@@ -57,9 +73,11 @@ def load(file, *, bitmap=None, palette=None):
5773 return bitmap_obj , palette_obj
5874
5975
60- def _read_frame (file , bitmap ):
61- """Read a signle frame and apply it to the bitmap."""
62- ddx , ddy , width , _ , flags = struct .unpack ("<HHHHB" , file .read (9 ))
76+ def _read_frame (file : BufferedReader , bitmap : Bitmap ) -> None :
77+ """Read a single frame and apply it to the bitmap."""
78+ ddx , ddy , width , _ , flags = struct .unpack ( # pylint: disable=no-member
79+ "<HHHHB" , file .read (9 )
80+ )
6381 if (flags & 0x40 ) != 0 :
6482 raise NotImplementedError ("Interlacing not supported" )
6583 if (flags & 0x80 ) != 0 :
@@ -78,7 +96,7 @@ def _read_frame(file, bitmap):
7896 y += 1
7997
8098
81- def _read_blockstream (file ) :
99+ def _read_blockstream (file : BufferedReader ) -> Iterator [ int ] :
82100 """Read a block from a file."""
83101 while True :
84102 size = file .read (1 )[0 ]
@@ -95,21 +113,21 @@ class EndOfData(Exception):
95113class LZWDict :
96114 """A dictionary of LZW codes."""
97115
98- def __init__ (self , code_size ) :
116+ def __init__ (self , code_size : int ) -> None :
99117 self .code_size = code_size
100118 self .clear_code = 1 << code_size
101119 self .end_code = self .clear_code + 1
102- self .codes = []
103- self .last = None
120+ self .codes = [] # type: List[bytes]
121+ self .last = b""
104122 self .clear ()
105123
106- def clear (self ):
124+ def clear (self ) -> None :
107125 """Reset the dictionary to default codes."""
108126 self .last = b""
109127 self .code_len = self .code_size + 1
110128 self .codes [:] = []
111129
112- def decode (self , code ) :
130+ def decode (self , code : int ) -> bytes :
113131 """Decode a code."""
114132 if code == self .clear_code :
115133 self .clear ()
@@ -133,7 +151,7 @@ def decode(self, code):
133151 return value
134152
135153
136- def lzw_decode (data , code_size ) :
154+ def lzw_decode (data : Iterator [ int ] , code_size : int ) -> Iterator [ bytes ] :
137155 """Decode LZW-compressed data."""
138156 dictionary = LZWDict (code_size )
139157 bit = 0
0 commit comments