ABCDEFGHIJKLMNOPQRSTUVWXYZAAAB
1
This spreadsheet stems from three issues:
1) I believe that LittlevGL's current 565 (and perhaps others) to 888 conversion code is flawed
2
lv_misc/lv_color.h:
static inline uint32_t lv_color_to32(lv_color_t color)
{
...
#elif LV_COLOR_DEPTH == 16
lv_color32_t ret;
ret.ch.red = color.ch.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
ret.ch.green = color.ch.green * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/
ret.ch.blue = color.ch.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/
ret.ch.alpha = 0xFF;
return ret.full;
...
}
3
The above code **should** cleanly convert 565 LV_COLOR_RED of 0xF800 to 888 of 0xFF0000.
The 5 bit red channel of 0xF800 is 2^5-1 or 31 or 0x1F.
Per the above code logic, 31 * 8 is 248, or 0xF8.
Thus, the above code converts 565 0xF800 to 888 of 0xF80000 instead of 0xFF0000.
I understand that 565 to 888 conversion is `lossy`, but when mapping a number from one scale to another, I believe at least the min and max values should convert without loss.
Thus, I think that the above code needs to change.
4
2) The mystery of the numbers in this commonly used more precise RGB 565 to 888 conversion code:
5
How does one convert 16-bit RGB565 to 24-bit RGB888?
6
https://stackoverflow.com/a/9069480/252308
7
R8 = ( R5 * 527 + 23 ) >> 6;
G8 = ( G6 * 259 + 33 ) >> 6;
B8 = ( B5 * 527 + 23 ) >> 6;
8
The discussion in that SO answer suggests 527 may have been incorrectly rounded up instead of down.
Searching the internets gave me no clue as to the origin of these values.
The "2^5" and "2^6" tabs of this spreadsheet contain my exploration in deriving these values.
It seems like nearly any listed multiplier and adder can be used, but it is still a mystery to me why those specific 6 bit shift values were chosen.
Here is the code that I have calculated:
9
R8 = ( R5 * 526 + 14 ) / 64;
G8 = ( G6 * 259 + 3 ) / 64;
B8 = ( B5 * 526 + 14 ) / 64;
10
(31 * 526 + 14) / 64 = 255
(63 * 259 + 3) / 64 = 255
11
Apple uses the following code:
12
https://developer.apple.com/documentation/accelerate/1533159-vimageconvert_rgb565toargb8888
13
Pixel8 alpha = alpha
Pixel8 red = (5bitRedChannel * 255 + 15) / 31
Pixel8 green = (6bitGreenChannel * 255 + 31) / 63
Pixel8 blue = (5bitBlueChannel * 255 + 15) / 31
14
I don't know how Apple determined these values, but they do seem to work...
15
(31 * 255 + 15) / 31 = 255
(63 * 255 + 31) / 63 = 255
16
I guess integer division rounding **can** be your friend in multiple ways!
17
18
19
20
21
22
23
24
25
26
27
28
29