31
31
import gc
32
32
import struct
33
33
import board
34
- from displayio import Bitmap , Palette , Display
34
+ from displayio import Bitmap , Palette , Display , ColorConverter
35
35
36
36
try :
37
37
from typing import Tuple , Optional , Union
@@ -81,11 +81,38 @@ def _rgb565_to_bgr_tuple(color: int) -> Tuple[int, int, int]:
81
81
return blue , green , red
82
82
83
83
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
+
84
111
# pylint:disable=too-many-locals
85
112
def _write_pixels (
86
113
output_file : BufferedWriter ,
87
114
pixel_source : Union [Bitmap , Display ],
88
- palette : Optional [Palette ],
115
+ palette : Optional [Union [ Palette , ColorConverter ] ],
89
116
) -> None :
90
117
saving_bitmap = isinstance (pixel_source , Bitmap )
91
118
width , height = _rotated_height_and_width (pixel_source )
@@ -97,7 +124,13 @@ def _write_pixels(
97
124
# pixel_source: Bitmap
98
125
for x in range (width ):
99
126
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
+
101
134
for _ in range (3 ):
102
135
row_buffer [buffer_index ] = color & 0xFF
103
136
color >>= 8
@@ -124,7 +157,7 @@ def _write_pixels(
124
157
def save_pixels (
125
158
file_or_filename : Union [str , BufferedWriter ],
126
159
pixel_source : Union [Display , Bitmap ] = None ,
127
- palette : Optional [Palette ] = None ,
160
+ palette : Optional [Union [ Palette , ColorConverter ] ] = None ,
128
161
) -> None :
129
162
"""Save pixels to a 24 bit per pixel BMP file.
130
163
If pixel_source if a displayio.Bitmap, save it's pixels through palette.
@@ -140,8 +173,10 @@ def save_pixels(
140
173
pixel_source = board .DISPLAY
141
174
142
175
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
+ )
145
180
elif not isinstance (pixel_source , Display ):
146
181
raise ValueError ("Second argument must be a Bitmap or Display" )
147
182
try :
0 commit comments