RGB332

   RGB332 is a general 256 color [1]palette that encodes one color with 1
   [2]byte (i.e. 8 [3]bits): 3 bits (highest) for red, 3 bits for green and 2
   bits (lowest) for blue (as human eye is least sensitive to blue we choose
   to allocate fewest bits to blue). RGB332 is an implicit palette -- it
   doesn't have to be stored in memory (though doing so also has
   justifications) 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 "[4]KISS/[5]suckless" and
   often [6]good enough (especially with [7]dithering) as it saves memory,
   avoids headaches with [8]endianness 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 [9]embedded. It is also in the [10]public domain, unlike
   some other palettes, so it's additionally a legally safe choice. RGB332
   also has a "sister palette" called [11]RGB565 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 [12]gamma correction, 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 [13]C 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;
 }

   NOTE on rgbFrom332: a quick naive idea on getting the 8bit values for R, G
   and B components out of RGB332 color is to simply take the bits and pad
   them with zeros from bottom to the 8bit values -- though that will
   somewhat work, it won't be completely correct; consider e.g. an input
   value 11100000 where R is 111, i.e. at maximum -- by padding this to
   11100000 we however don't get the desired maximum value 11111111 (if we
   pad with 1s we'll have the same problem for the zero value). This is why
   the code isn't as simple as the rgbTo332 function where we really do just
   chop off the unneeded bits.

   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 [14]approximated in a very fast
   way using the [15]OR/[16]AND 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

   Division by power of two is also fairly fast, you may simply shift the
   whole value right and zero appropriate bits, for example to darken a color
   twice you can just do (color >> 1) & 0x6d { Again code untested sorry.
   ~drummyfish }. Multiplying by power of two is not as simple though
   (consider e.g. a value 1011 shifted left once will result in a smaller
   value 0110; you may still try some tricks like a bitwise or with the
   previous value but that will already be an approximation);

   { 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

     * [17]RGB565
     * [18]palette
     * [19]grayscale

Links:
1. palette.md
2. byte.md
3. bit.md
4. kiss.md
5. suckless.md
6. good_enough.md
7. dithering.md
8. byte_sex.md
9. embedded.md
10. public_domain.md
11. rgb565.md
12. gamma_correction.md
13. c.md
14. approximation.md
15. or.md
16. and.md
17. rgb565.md
18. palette.md
19. grayscale.md