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 components: 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 struc‐
ture, corresponding to the channels of that image (see image(6)).
The values of the red, green and blue components are chosen so 0 repre‐
sents 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 representation internally
can be ignored by many applications. The representation is visible,
however, when using the operations Image.readpixels and Image.writepix‐
els (see draw-image(2)). The bits representing a pixel's channel com‐
ponents are packed contiguously, and pixels are stored in contiguous
bytes. The packing of pixels into bytes and words is odd. For compat‐
ibility 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 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 problems of con‐
sistency and portability amongst Inferno applications, 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 impor‐
tant 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 converted into such
maps demonstrate conspicuous artifacts.
Rather than dice the colour cube into subregions of size 6×6×6 (as in
Netscape Navigator) or 8×8×4 picking 1 colour in each, the rgbv colour
map uses a 4×4×4 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 samples in
each), 13 shades of each primary and secondary colour (3 subcubes with
4 samples plus black) and a reasonable 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;
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) coordinates 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 uni‐
formly 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 pic‐
ture 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, photo‐
graphic film and television are both normally under-corrected, the for‐
mer 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. Prop‐
erly gamma-corrected displays with adequate low-intensity resolution
pack the high-intensity parts of the colour cube with colours whose
differences are almost imperceptible. 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 out‐
put.
SEE ALSOdraw-intro(2), draw-image(2)COLOUR(6)