I’ve talked w/ kisvegabor and embeddedt a bit about this in a semi-unrelated PR, but I thought I would discuss this here more visibly before I start coding anything.
- I believe that LittlevGL’s current 565 to 888 conversion code is flawed (which opens up the possibility of others to/from)
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;
...
}
I think the above code should cleanly convert 565 LV_COLOR_RED of 0xF800 to 888 of 0xFF0000, but it doesn’t.
I understand the important performance rationale for 255/31=8
and not using an actual floating point of 8.22580645 and the loss that integer division introduces; minimizing this loss is actually one of my points for suggesting an improvement.
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/imperfect”, 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.
- There is a mystery in the numbers of this commonly used more precise RGB 565 to 888 conversion code:
SO Q&A: How does one convert 16-bit RGB565 to 24-bit RGB888?
R8 = ( R5 * 527 + 23 ) >> 6;
G8 = ( G6 * 259 + 33 ) >> 6;
B8 = ( B5 * 527 + 23 ) >> 6;
The discussion in the above SO answer suggests 527 may have been incorrectly rounded up instead of down and should be 526 (which if true would also change the 23
addition.
Searching the internets gave me no clue as to the origin of these values.
I have created a spreadsheet exploring how these values were derived.
https://docs.google.com/spreadsheets/d/1PppX8FJpddauAPasHwlNgIPGIuPGPNvRbhilIQ8w-7g/edit#gid=0
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 over any others.
So, with all of the above said, has anyone noticed undesirable 565 to 888 color conversions, or others, or am I the only one?
Pv