Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ defined 16bit (high) color

I am working on a project with a TFT touch screen. With this screen there is an included library. But after some reading, I still don't get something. In the library there are some defines regarding colors:

/* some RGB color definitions                                                 */
#define Black           0x0000      /*   0,   0,   0 */
#define Navy            0x000F      /*   0,   0, 128 */
#define DarkGreen       0x03E0      /*   0, 128,   0 */
#define DarkCyan        0x03EF      /*   0, 128, 128 */
#define Maroon          0x7800      /* 128,   0,   0 */
#define Purple          0x780F      /* 128,   0, 128 */
#define Olive           0x7BE0      /* 128, 128,   0 */
#define LightGrey       0xC618      /* 192, 192, 192 */
#define DarkGrey        0x7BEF      /* 128, 128, 128 */
#define Blue            0x001F      /*   0,   0, 255 */
#define Green           0x07E0      /*   0, 255,   0 */
#define Cyan            0x07FF      /*   0, 255, 255 */
#define Red             0xF800      /* 255,   0,   0 */
#define Magenta         0xF81F      /* 255,   0, 255 */
#define Yellow          0xFFE0      /* 255, 255,   0 */
#define White           0xFFFF      /* 255, 255, 255 */
#define Orange          0xFD20      /* 255, 165,   0 */
#define GreenYellow     0xAFE5      /* 173, 255,  47 */
#define Pink                        0xF81F

Those are 16-bit colors. But how do they go from: 0, 128, 128(dark cyan) to 0x03EF. I mean, how do you convert a 16-bit color to a uint16? This doesn't need to have an answer in code, because I just want to add some colors in the library. A link to a online converter (which I could not find) would be okay as well :)

Thanks

like image 316
Bart Teunissen Avatar asked Dec 05 '12 10:12

Bart Teunissen


People also ask

What is 16bit color?

16-bit high color When all 16 bits are used, one of the components (usually green with RGB565, see below) gets an extra bit, allowing 64 levels of intensity for that component, and a total of 65536 available colors.

How many colors can be represented with 16 bits?

Up to 65,536 colors can be represented in the color palette. Most graphics formats provide 8-bit color or 24-bit color; however, graphics cards generally have an intermediate 16-bit color range that displays 65,536 colors. See color depth.

Which is better 16-bit or 32 bit color?

They both differ in the ways of encoding information. A 32 bit colored image provides more available colors than a 16 bit color image. The 32 bit color mode is preferred for accuracy and quality. However, the file size of a 32 bit color image is quiet large than in compared to a 16 bit color image file.

What RGB 565?

RGB565 is used to represent colours in 16 bits, rather than the 24bit (RGB888) web pages use to specify colours. To make full use of the 16 bits, red and blue are encoded in 5 bits and green in 6 bits. This is due to the human eyes capacity to see more shades of green.


4 Answers

From these one can easily find out the formula:

#define Red             0xF800      /* 255,   0,   0 */  
#define Magenta         0xF81F      /* 255,   0, 255 */
#define Yellow          0xFFE0      /* 255, 255,   0 */

F800 has 5 MSB bits set and FFE0 has 5 LSB not set. 0xF81F has obviously both 5 LSB's and 5 MSB's set, which proves the format to be RGB565.

The formula to convert a value 173 to Red is not as straightforward as it may look -- you can't simply drop the 3 least significant bits, but have to linearly interpolate to make 255 to correspond to 31 (or green 255 to correspond to 63).

NewValue = (31 * old_value) / 255;

(And this is still just a truncating division -- proper rounding could be needed)

With proper rounding and scaling:

Uint16_value = (((31*(red+4))/255)<<11) | 
               (((63*(green+2))/255)<<5) | 
               ((31*(blue+4))/255);

EDIT Added parenthesis to as helpfully suggested by JasonD.

like image 77
Aki Suihkonen Avatar answered Sep 20 '22 19:09

Aki Suihkonen


You need to know the exact format of the display, just "16-bit" is not enough.

There's RGB555, in which each of the three components get 5 bits. This drops the total color space to just 32,768 colors, wasting one bit but it's very simple to manage since the there's the same number of shades for each component.

There's also RGB565, in which the green component is given 6 bits (since the human eye is more sensitive to green). This might be the format you're having, since the "dark green" example is 0x03e0 which in binary is 0b0000 0011 1110 0000. Since there's 6 bits set to 1 there, I guess that's the total allocation for the green component and showing it's maximum value.

It's like this, then (with spaces separating every four bits and re-using the imaginary 0b prefix):

0bRRRR RGGG GGGB BBBB

Of course, the bit ordering can differ too, in the word.

The task of converting a triplet of numbers into a bit-packed word is quite easily done in typically programming languages that have bit manipulation operators.

In C, it's often done in a macro, but we can just as well have a function:

#include <stdint.h>

uint16_t rgb565_from_triplet(uint8_t red, uint8_t green, uint8_t blue)
{
  red   >>= 3;
  green >>= 2;
  blue  >>= 3;
  return (red << 11) | (green << 5) | blue;
}

note that the above assumes full 8-bit precision for the components, so maximum intensity for a component is 255, not 128 as in your example. If the color space really is using 7-bit components then some additional scaling would be necessary.

like image 29
unwind Avatar answered Sep 21 '22 19:09

unwind


It looks like you're using RGB565, first 5 bits for Red, then 6 bits for Green, then 5 bits for Blue.

You should mask with 0xF800 and shift right 11 bits to get the red component (or shift 8 bits to get a value from 0-255). Mask with 0x07E0 and shift right 5 bits to get green component (or 3 to get a 0-255 value). Mask with 0x001F to get the blue component (and shift left 3 bits to get 0-255).

like image 39
Karl E Avatar answered Sep 20 '22 19:09

Karl E


Your colours are in 565 format. It would be more obvious if you wrote them out in binary.

  • Blue, (0,0,255) is 0x001f, which is 00000 000000 11111
  • Green, (0, 255, 0) is 0x07e0, which is 00000 111111 00000
  • Red, (255, 0, 0) is 0xf800, which is 11111 000000 00000

To convert a 24 bit colour to 16 bit in this format, simply mask off the upper bits needed from each component, shift into position, and OR together.

The convert back into 24 bit colour from 16 bit, mask each component, shift into position, and then duplicate the upper bits into the lower bits.

In your examples it seems that some colours have been scaled and rounded rather than shifted.

I strongly recommend using the bit-shift method rather than scaling by a factor like 31/255, because the bit-shifting is not only likely to be faster, but should give better results.

like image 41
JasonD Avatar answered Sep 18 '22 19:09

JasonD