24b color to 16b

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
lama
Member
Member
Posts: 83
Joined: Thu Apr 16, 2009 8:41 am

24b color to 16b

Post by lama »

hello everyone, how can i recalculate 24bit color (for example 0x545454) to 16 bit color? (that 16bit color should then be the closest possible match of the original, 24 bit color).
thanks.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: 24b color to 16b

Post by Combuster »

Question shotgun time.

how many values does each color component have in 24 bits? how many in 16 bits? for each red value in 16bits, how many values in 24 bits will have to use that color? What input values (write them out in binary) would result in a red value of 0, which ones would result in 1, which ones in a 2? do you see a pattern yet?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: 24b color to 16b

Post by Brendan »

Hi,
lama wrote:hello everyone, how can i recalculate 24bit color (for example 0x545454) to 16 bit color? (that 16bit color should then be the closest possible match of the original, 24 bit color).
For 16-bpp you typically get 5-bit red, 6-bit green and 5-bit blue. You'd want the most significant source bits to end up in the destination bits. For example, you might do "dest = ((source & 0x00F80000) >> 8 ) | ((source & 0x0000FC00) >> 5) | ((source & 0x000000F8) >> 3)". Unfortunately this causes a slight loss of intensity (e.g. a photo will look slightly darker) because you're essentially using "round to lowest".

To avoid the slight loss of intensity, you'd need to round to nearest. For example, "dest = (((source & 0x00F80000) + 0x00040000) >> 8 ) | (((source & 0x0000FC00) + 0x00000200) >> 5) | (((source & 0x000000F8) + 0x00000002) >> 3)". This causes an extra problem, because values may overflow (e.g. 0xFF becomes 0x00). To work around that you'd need to do something like (for the red only) "if( (source & 0x00FC0000) == 0x00FC0000) { dest = 0x0000F800; } else { dest = (((source & 0x00F80000) + 0x00040000) >> 8 ); }".

Of course that only really reduces the chance of the problem happening. If you've got large area/s that happens to be the same colour, then you'll end up with either a slight loss of intensity or a slight increase in intensity (depending on if that colour is rounded up or down); and because red, green and blue are handled separately you might (for e.g.) increase red while reducing green and blue, causing slight shifts in hue.

The other problem is something called posterization or colour banding.

To avoid all of these problems (intensity shift, hue shift and posterization/colour banding), you need to use some form of dithering.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
lama
Member
Member
Posts: 83
Joined: Thu Apr 16, 2009 8:41 am

Re: 24b color to 16b

Post by lama »

thanks for your full explanation and example how to do that . it is working now :) you may lock this thread.
Post Reply