1616import sys
1717
1818try :
19- from typing import Tuple , Optional
19+ from typing import Union , Optional , Tuple
2020 from io import BufferedReader
21- from displayio import Bitmap
2221 from ..displayio_types import BitmapConstructor
2322except ImportError :
2423 pass
2524
26- from displayio import ColorConverter , Colorspace
25+ from displayio import ColorConverter , Colorspace , Bitmap
2726
2827__version__ = "0.0.0+auto.0"
2928__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git"
3029
30+ bitfield_colorspaces = (
31+ { # 16-bit RGB555
32+ "mask_values" : (0x00007C00 , 0x000003E0 , 0x0000001F ),
33+ "color_space" : Colorspace .RGB555 ,
34+ },
35+ { # 16-bit RGB565
36+ "mask_values" : (0x0000F800 , 0x000007E0 , 0x0000001F ),
37+ "color_space" : Colorspace .RGB565 ,
38+ },
39+ { # 24 or 32-bit RGB888 (Alpha ignored for 32-bit)
40+ "mask_values" : (0x0000FF00 , 0x00FF0000 , 0xFF000000 ),
41+ "color_space" : Colorspace .RGB888 ,
42+ },
43+ )
44+
45+
46+ def bitfield_format (bitfield_mask ):
47+ """Returns the colorspace for the given bitfield mask"""
48+ mask = (bitfield_mask ["red" ], bitfield_mask ["green" ], bitfield_mask ["blue" ])
49+ for colorspace in bitfield_colorspaces :
50+ if colorspace ["mask_values" ] == mask :
51+ return colorspace ["color_space" ]
52+ return None
53+
3154
3255def load (
3356 file : BufferedReader ,
3457 width : int ,
3558 height : int ,
3659 data_start : int ,
3760 color_depth : int ,
61+ bitfield_masks : Union [dict , None ],
3862 * ,
3963 bitmap : Optional [BitmapConstructor ] = None ,
4064) -> Tuple [Optional [Bitmap ], Optional [ColorConverter ]]:
@@ -46,6 +70,7 @@ def load(
4670 :param int height: Image height in pixels
4771 :param int data_start: Byte location where the data starts (after headers)
4872 :param int color_depth: Number of bits used to store a value
73+ :param dict bitfield_masks: The bitfield masks for each color if using bitfield compression
4974 :param BitmapConstructor bitmap: a function that returns a displayio.Bitmap
5075 """
5176 # pylint: disable=too-many-arguments,too-many-locals,too-many-branches
@@ -55,7 +80,13 @@ def load(
5580 # Set up a ColorConverter object and set appropriate colorspace
5681 # to convert from based on the color depth
5782 input_colorspace = Colorspace .RGB888
58- if color_depth == 16 :
83+ if bitfield_masks is not None :
84+ colorspace = bitfield_format (bitfield_masks )
85+ if colorspace is not None :
86+ input_colorspace = colorspace
87+ else :
88+ raise NotImplementedError ("Bitfield mask not supported" )
89+ elif color_depth == 16 :
5990 input_colorspace = Colorspace .RGB555
6091 converter_obj = ColorConverter (input_colorspace = input_colorspace )
6192 if sys .maxsize > 1073741823 :
@@ -64,7 +95,7 @@ def load(
6495
6596 # convert unsigned int to signed int when height is negative
6697 height = negative_height_check (height )
67- bitmap_obj = bitmap (width , abs (height ), 65535 )
98+ bitmap_obj = Bitmap (width , abs (height ), 65535 )
6899 file .seek (data_start )
69100 line_size = width * (color_depth // 8 )
70101 # Set the seek direction based on whether the height value is negative or positive
@@ -84,10 +115,23 @@ def load(
84115
85116 for x in range (width ):
86117 i = x * bytes_per_pixel
87- if color_depth == 16 :
88- pixel = chunk [i ] | chunk [i + 1 ] << 8
118+ if bitfield_masks is not None :
119+ color = 0
120+ for byte in range (bytes_per_pixel ):
121+ color |= chunk [i + byte ] << (8 * byte )
122+ mask = (
123+ bitfield_masks ["red" ]
124+ | bitfield_masks ["green" ]
125+ | bitfield_masks ["blue" ]
126+ )
127+ if color_depth in (24 , 32 ):
128+ mask = mask >> 8
129+ pixel = color & mask
89130 else :
90- pixel = chunk [i + 2 ] << 16 | chunk [i + 1 ] << 8 | chunk [i ]
131+ if color_depth == 16 :
132+ pixel = chunk [i ] | chunk [i + 1 ] << 8
133+ else :
134+ pixel = chunk [i + 2 ] << 16 | chunk [i + 1 ] << 8 | chunk [i ]
91135 bitmap_obj [offset + x ] = converter_obj .convert (pixel )
92136
93137 return bitmap_obj , ColorConverter (input_colorspace = Colorspace .RGB565 )
0 commit comments