# RGB332

RGB332 is a general 256 color [palette](palette.md) that encodes one color with 1 [byte](byte.md) (i.e. 8 [bits](bit.md)): 3 bits (highest) for red, 3 bits for green and 2 bits (lowest) for blue (as human eye is least sensitive to blue). RGB332 is an implicit palette -- it doesn't have to be stored in memory because the color index itself determines the color and vice versa. Compared to the classic 24 bit RGB (which assigns 8 bits to each of the RGB components), RGB332 is very "[KISS](kiss.md)/[suckless](suckless.md)" and often [good enough](good_enough.md) (especially with [dithering](dithering.md)) as it saves memory, avoids headaches with [endianness](byte_sex.md) and represents each color with just a single number (as opposed to 3), so it is often used in simple and limited computers such as [embedded](embedded.md). It is also in the [public domain](public_domain.md), unlike some other palettes, so it's additionally a legally safe choice. RGB332 also has a "sister palette" called [RGB565](rgb565.md) which uses two bytes instead of one and so offers many more colors.

A disadvantage of plain 332 palette lies in the linearity of each component's intensity, i.e. lack of [gamma correction](gamma_correction.md), so there are too many almost indistinguishable bright colors while too few darker ones { TODO: does a gamma corrected 332 exist? make it? ~drummyfish }. Another disadvantage is the non-alignment of the blue component with red and green components, i.e. while R/G components have 8 levels of intensity and so step from 0 to 255 by 36.4, the B component only has 4 levels and steps by exactly 85, which makes it impossible to create exact shades of grey (which of course have to have all R, G and B components equal).

The RGB values of the 332 palette are following:

```
#000000 #000055 #0000aa #0000ff #002400 #002455 #0024aa #0024ff
#004800 #004855 #0048aa #0048ff #006d00 #006d55 #006daa #006dff
#009100 #009155 #0091aa #0091ff #00b600 #00b655 #00b6aa #00b6ff
#00da00 #00da55 #00daaa #00daff #00ff00 #00ff55 #00ffaa #00ffff
#240000 #240055 #2400aa #2400ff #242400 #242455 #2424aa #2424ff
#244800 #244855 #2448aa #2448ff #246d00 #246d55 #246daa #246dff
#249100 #249155 #2491aa #2491ff #24b600 #24b655 #24b6aa #24b6ff
#24da00 #24da55 #24daaa #24daff #24ff00 #24ff55 #24ffaa #24ffff
#480000 #480055 #4800aa #4800ff #482400 #482455 #4824aa #4824ff
#484800 #484855 #4848aa #4848ff #486d00 #486d55 #486daa #486dff
#489100 #489155 #4891aa #4891ff #48b600 #48b655 #48b6aa #48b6ff
#48da00 #48da55 #48daaa #48daff #48ff00 #48ff55 #48ffaa #48ffff
#6d0000 #6d0055 #6d00aa #6d00ff #6d2400 #6d2455 #6d24aa #6d24ff
#6d4800 #6d4855 #6d48aa #6d48ff #6d6d00 #6d6d55 #6d6daa #6d6dff
#6d9100 #6d9155 #6d91aa #6d91ff #6db600 #6db655 #6db6aa #6db6ff
#6dda00 #6dda55 #6ddaaa #6ddaff #6dff00 #6dff55 #6dffaa #6dffff
#910000 #910055 #9100aa #9100ff #912400 #912455 #9124aa #9124ff
#914800 #914855 #9148aa #9148ff #916d00 #916d55 #916daa #916dff
#919100 #919155 #9191aa #9191ff #91b600 #91b655 #91b6aa #91b6ff
#91da00 #91da55 #91daaa #91daff #91ff00 #91ff55 #91ffaa #91ffff
#b60000 #b60055 #b600aa #b600ff #b62400 #b62455 #b624aa #b624ff
#b64800 #b64855 #b648aa #b648ff #b66d00 #b66d55 #b66daa #b66dff
#b69100 #b69155 #b691aa #b691ff #b6b600 #b6b655 #b6b6aa #b6b6ff
#b6da00 #b6da55 #b6daaa #b6daff #b6ff00 #b6ff55 #b6ffaa #b6ffff
#da0000 #da0055 #da00aa #da00ff #da2400 #da2455 #da24aa #da24ff
#da4800 #da4855 #da48aa #da48ff #da6d00 #da6d55 #da6daa #da6dff
#da9100 #da9155 #da91aa #da91ff #dab600 #dab655 #dab6aa #dab6ff
#dada00 #dada55 #dadaaa #dadaff #daff00 #daff55 #daffaa #daffff
#ff0000 #ff0055 #ff00aa #ff00ff #ff2400 #ff2455 #ff24aa #ff24ff
#ff4800 #ff4855 #ff48aa #ff48ff #ff6d00 #ff6d55 #ff6daa #ff6dff
#ff9100 #ff9155 #ff91aa #ff91ff #ffb600 #ffb655 #ffb6aa #ffb6ff
#ffda00 #ffda55 #ffdaaa #ffdaff #ffff00 #ffff55 #ffffaa #ffffff
```

## Operations

Here are [C](c.md) functions for converting RGB332 to RGB24 and back:

```
unsigned char rgbTo332(unsigned char red, unsigned char green, unsigned char blue)
{
  return ((red / 32) << 5) | ((green / 32) << 2) | (blue / 64);
}

void rgbFrom332(unsigned char colorIndex, unsigned char *red, unsigned char *green, unsigned char *blue)
{
  unsigned char value = (colorIndex >> 5) & 0x07;
  *red = value != 7 ? value * 36 : 255;

  value = (colorIndex >> 2) & 0x07;
  *green = value != 7 ? value * 36 : 255;
  
  value = colorIndex & 0x03;
  *blue = (value != 3) ? value * 72 : 255;
}
```

Addition/subtraction of two RGB332 colors can be performed by simply adding/subtracting the two color values as long as no over/underflow occurs in either component -- by adding the values we basically perform a parallel addition/subtraction of all three components with only one operation. Unfortunately checking for when exactly such overflow occurs is not easy to do quickly { Or is it? ~drummyfish }, but to rule out e.g. an overflow with addition we may for example check whether the highest bit of each component in both colors to be added is 0 (i.e. `if (((color1 & 0x92) | (color2 & 0x92)) == 0) newColor = color1 + color2;`). { Code untested. ~drummyfish }

Addition/subtraction of colors can also be [approximated](approximation.md) in a very fast way using the [OR](or.md)/[AND](and.md) operation instead of arithmetic addition/subtraction -- however this only works sometimes (check visually). For example if you need to quickly brighten/darken all pixels in a 332 image, you can just OR/AND each pixel with these values:

```
brighten by more:  doesn't really work anymore
brighten by 3:     | 0x6d  (011 011 01)
brighten by 2:     | 0x49  (010 010 01)
brighten by 1:     | 0x24  (001 001 00)
darken by 1:       & 0xdb  (110 110 11)
darken by 2:       & 0xb6  (101 101 10)
darken by 3:       & 0x92  (100 100 10)
darken by more:    doesn't really work anymore
```

{ TODO: Would it be possible to accurately add two 332 colors by adding all components in parallel using bitwise operators somehow? I briefly tried but the result seemed too complex to be worth it though. ~drummyfish }

Inverting a 332 color is done simply by inverting all bits in the color value.

TODO: blending?

## See Also

- [RGB565](rgb565.md)
- [palette](palette.md)
- [grayscale](grayscale.md)