COLOUR(6)                                               COLOUR(6)

     NAME
          colour - representation of pixels and colours

     DESCRIPTION
          An image manipulated by draw(2) (via the device draw(3)),
          including the image corresponding to a physical display,
          contains a set of pixels.  Each pixel has one or more compo-
          nents: colour components (red, green, blue); greyscale
          value; colour-map index; alpha value; and ``don't care''
          (for padding).  Each component takes a given number of bits;
          the sum of the sizes of all components determines the size
          of the pixel.  The implementation supports only pixel sizes
          that are either divisors or multiples of 8 bits.  All pixels
          in an image have the same structure, corresponding to the
          channels of that image (see image(6)).

          The values of the red, green and blue components are chosen
          so 0 represents no intensity (black) and the maximum value
          (all ones, 255 for an 8-bit component) represents full
          intensity (eg, full red).  Common colour physical display
          depths are 24 bits per pixel, with 8 bits per colour in
          order red, green, blue, and 16 bits per pixel, with 5 bits
          of red, 6 bits of green, and 5 bits of blue.

          Colors may also be created with an opacity factor called
          alpha, which is scaled so 0 represents fully transparent and
          the maximum value (eg, 255 for an 8-bit alpha component)
          represents opaque colour.  The alpha is premultiplied into
          the other channels, as described in the paper by Porter and
          Duff cited in draw-image(2). The function Draw->setalpha
          (see draw-intro(2)) aids the initialisation of colour values
          with non-trivial alpha.

          Because images are stored in memory managed by draw(3) and
          operated through draw-image(2), the details of pixel repre-
          sentation internally can be ignored by many applications.
          The representation is visible, however, when using the oper-
          ations Image.readpixels and Image.writepixels (see draw-
          image(2)). The bits representing a pixel's channel compo-
          nents are packed contiguously, and pixels are stored in con-
          tiguous bytes.  The packing of pixels into bytes and words
          is odd.  For compatibility with VGA frame buffers, the bits
          within a pixel byte are in big-endian order (leftmost pixel
          is most significant bits in byte), while bytes within a
          pixel are packed in little-endian order.  This results in
          unintuitive pixel formats. For example, for the RGB24 for-
          mat, the byte ordering is blue, green, red.

          To maintain a constant external representation, the draw(3)
          interface as well as the various graphics libraries

     Page 1                       Plan 9             (printed 3/28/24)

     COLOUR(6)                                               COLOUR(6)

          represent colours by 32-bit integers, containing red, blue,
          green and alpha components as 8-bit values, in that order
          from most to least significant byte.  The color component
          values range from 0 (no colour) to 255 (saturated); alpha
          ranges from 0 (fully transparent) to 255 (fully opaque).

          On displays with 8 bits per pixel or less, to address prob-
          lems of consistency and portability amongst Inferno applica-
          tions, Inferno uses a fixed colour map, called rgbv.
          Although this avoids problems caused by multiplexing colour
          maps between applications, it requires that the colour map
          chosen be suitable for most purposes and usable for all.
          Other systems that use fixed colour maps tend to sample the
          colour cube uniformly, which has advantages-mapping from a
          (red, green, blue) triple to the colour map and back again
          is easy-but ignores an important property of the human
          visual system: eyes are much more sensitive to small changes
          in intensity than to changes in hue.  Sampling the colour
          cube uniformly gives a colour map with many different hues,
          but only a few shades of each.  Continuous tone images con-
          verted into such maps demonstrate conspicuous artifacts.

          Rather than dice the colour cube into subregions of size
          6x6x6 (as in Netscape Navigator) or 8x8x4 picking 1 colour
          in each, the rgbv colour map uses a 4x4x4 subdivision, with
          4 shades in each subcube.  The idea is to reduce the colour
          resolution by dicing the colour cube into fewer cells, and
          to use the extra space to increase the intensity resolution.
          This results in 16 grey shades (4 grey subcubes with 4 sam-
          ples in each), 13 shades of each primary and secondary
          colour (3 subcubes with 4 samples plus black) and a reason-
          able selection of colours covering the rest of the colour
          cube.  The advantage is better representation of continuous
          tones.

          The following function computes the 256 3-byte entries in
          the colour map:

               void
               setmaprgbv(uchar cmap[256][3])
               {
                   uchar *c;
                   int r, g, b, v;
                   int num, den;
                   int i, j;

                   for(r=0,i=0; r!=4; r++)
                     for(v=0; v!=4; v++,i+=16)
                       for(g=0,j=v-r; g!=4; g++)
                         for(b=0; b!=4; b++,j++){
                           c = cmap[i+(j&15)];
                           den = r;

     Page 2                       Plan 9             (printed 3/28/24)

     COLOUR(6)                                               COLOUR(6)

                           if(g > den)
                               den = g;
                           if(b > den)
                               den = b;
                           if(den == 0) /* would divide check; pick grey shades */
                               c[0] = c[1] = c[2] = 17*v;
                           else{
                               num = 17*(4*den+v);
                               c[0] = r*num/den;
                               c[1] = g*num/den;
                               c[2] = b*num/den;
                           }
                         }
               }

          There are 4 nested loops to pick the (red,green,blue) coor-
          dinates of the subcube, and the value (intensity) within the
          subcube, indexed by r, g, b, and v, whence the name rgbv.
          The peculiar order in which the colour map is indexed is
          designed to distribute the grey shades uniformly through the
          map-the i'th grey shade, 0<=i<=15 has index i×17, with black
          going to 0 and white to 255.  Therefore, when a call to
          Image.draw (see draw-image(2)) converts a 1, 2 or 4 bit-
          per-pixel picture to 8 bits per pixel (which it does by
          replicating the pixels' bits), the converted pixel values
          are the appropriate grey shades.

          The rgbv map is not gamma-corrected, for many reasons.
          First, photographic film and television are both normally
          under-corrected, the former by an accident of physics and
          the latter by NTSC's design.  Second, we require extra
          colour resolution at low intensities because of the non-
          linear response and adaptation of the human visual system.
          Properly gamma-corrected displays with adequate low-
          intensity resolution pack the high-intensity parts of the
          colour cube with colours whose differences are almost imper-
          ceptible.  Either of these reasons suggests concentrating
          the available intensities at the low end of the range.
          Third, the compositing computations underlying the graphics
          operations in draw-image(2) assume a linear colour space.
          Finally, the right value for gamma correction is determined
          in part by the characteristics of the physical display
          device, and correction should be done on output.

     SEE ALSO
          draw-intro(2), draw-image(2)

     Page 3                       Plan 9             (printed 3/28/24)