3131import gc
3232import struct
3333import board
34- from displayio import Bitmap , Palette , Display
34+ from displayio import Bitmap , Palette , Display , ColorConverter
3535
3636try :
3737 from typing import Tuple , Optional , Union
@@ -81,11 +81,38 @@ def _rgb565_to_bgr_tuple(color: int) -> Tuple[int, int, int]:
8181 return blue , green , red
8282
8383
84+ def rgb565_to_rgb888 (rgb565 ):
85+ """
86+ Convert from an integer representing rgb565 color into an integer
87+ representing rgb888 color.
88+ :param rgb565: Color to convert
89+ :return int: rgb888 color value
90+ """
91+ # Shift the red value to the right by 11 bits.
92+ red5 = rgb565 >> 11
93+ # Shift the green value to the right by 5 bits and extract the lower 6 bits.
94+ green6 = (rgb565 >> 5 ) & 0b111111
95+ # Extract the lower 5 bits for blue.
96+ blue5 = rgb565 & 0b11111
97+
98+ # Convert 5-bit red to 8-bit red.
99+ red8 = round (red5 / 31 * 255 )
100+ # Convert 6-bit green to 8-bit green.
101+ green8 = round (green6 / 63 * 255 )
102+ # Convert 5-bit blue to 8-bit blue.
103+ blue8 = round (blue5 / 31 * 255 )
104+
105+ # Combine the RGB888 values into a single integer
106+ rgb888_value = (red8 << 16 ) | (green8 << 8 ) | blue8
107+
108+ return rgb888_value
109+
110+
84111# pylint:disable=too-many-locals
85112def _write_pixels (
86113 output_file : BufferedWriter ,
87114 pixel_source : Union [Bitmap , Display ],
88- palette : Optional [Palette ],
115+ palette : Optional [Union [ Palette , ColorConverter ] ],
89116) -> None :
90117 saving_bitmap = isinstance (pixel_source , Bitmap )
91118 width , height = _rotated_height_and_width (pixel_source )
@@ -97,7 +124,13 @@ def _write_pixels(
97124 # pixel_source: Bitmap
98125 for x in range (width ):
99126 pixel = pixel_source [x , y - 1 ]
100- color = palette [pixel ] # handled by save_pixel's guardians
127+ if isinstance (palette , Palette ):
128+ color = palette [pixel ] # handled by save_pixel's guardians
129+ elif isinstance (palette , ColorConverter ):
130+ converted = palette .convert (pixel )
131+ converted_888 = rgb565_to_rgb888 (converted )
132+ color = converted_888
133+
101134 for _ in range (3 ):
102135 row_buffer [buffer_index ] = color & 0xFF
103136 color >>= 8
@@ -124,7 +157,7 @@ def _write_pixels(
124157def save_pixels (
125158 file_or_filename : Union [str , BufferedWriter ],
126159 pixel_source : Union [Display , Bitmap ] = None ,
127- palette : Optional [Palette ] = None ,
160+ palette : Optional [Union [ Palette , ColorConverter ] ] = None ,
128161) -> None :
129162 """Save pixels to a 24 bit per pixel BMP file.
130163 If pixel_source if a displayio.Bitmap, save it's pixels through palette.
@@ -140,8 +173,10 @@ def save_pixels(
140173 pixel_source = board .DISPLAY
141174
142175 if isinstance (pixel_source , Bitmap ):
143- if not isinstance (palette , Palette ):
144- raise ValueError ("Third argument must be a Palette for a Bitmap save" )
176+ if not isinstance (palette , Palette ) and not isinstance (palette , ColorConverter ):
177+ raise ValueError (
178+ "Third argument must be a Palette or ColorConverter for a Bitmap save"
179+ )
145180 elif not isinstance (pixel_source , Display ):
146181 raise ValueError ("Second argument must be a Bitmap or Display" )
147182 try :
0 commit comments