COLOR(6)COLOR(6)NAMEcolor - representation of pixels and colors
DESCRIPTION
To address problems of consistency and portability among applications,
Plan 9 uses a fixed color map, called rgbv, on 8-bit-per-pixel dis‐
plays. Although this avoids problems caused by multiplexing color maps
between applications, it requires that the color map chosen be suitable
for most purposes and usable for all. Other systems that use fixed
color maps tend to sample the color cube uniformly, which has advan‐
tages—mapping from a (red, green, blue) triple to the color map and
back again is easy—but ignores an important property of the human vis‐
ual system: eyes are much more sensitive to small changes in intensity
than to changes in hue. Sampling the color cube uniformly gives a
color 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 color cube into subregions of size 6×6×6 (as in
Netscape Navigator) or 8×8×4 (as in previous releases of Plan 9), pick‐
ing 1 color in each, the rgbv color map uses a 4×4×4 subdivision, with
4 shades in each subcube. The idea is to reduce the color resolution
by dicing the color 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 color (3 subcubes with 4 samples plus black) and a reasonable
selection of colors covering the rest of the color cube. The advantage
is better representation of continuous tones.
The following function computes the 256 3-byte entries in the color
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
color 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 draw
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 two 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 color 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 color cube with colors whose dif‐
ferences are almost imperceptible. Either reason suggests concentrat‐
ing the available intensities at the low end of the range.
On `true-color' displays with separate values for the red, green, and
blue components of a pixel, the values are chosen so 0 represents no
intensity (black) and the maximum value (255 for an 8-bit-per-color
display) represents full intensity (e.g., full red). Common display
depths are 24 bits per pixel, with 8 bits per color 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 255 represents opaque
color. The alpha is premultiplied into the other channels, as
described in the paper by Porter and Duff cited in draw(2). The func‐
tion setalpha (see allocimage(2)) aids the initialization of color val‐
ues with non-trivial alpha.
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. Pixels are stored in
contiguous bytes. This results in unintuitive pixel formats. For exam‐
ple, for the RGB24 format, 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 colors by 32-bit
numbers, as described in color(2).
SEE ALSOcolor(2), graphics(2), draw(2)COLOR(6)