| .TH COLOR 7 |
| .SH NAME |
| color \- representation of pixels and colors |
| .SH DESCRIPTION |
| To address problems of consistency and portability among applications, |
| Plan 9 uses a fixed color map, called |
| .BR rgbv , |
| on 8-bit-per-pixel displays. |
| 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 advantages\(emmapping from a (red, green, blue) triple |
| to the color map and back again is easy\(embut 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 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. |
| .PP |
| Rather than dice the color cube into subregions of |
| size 6\(mu6\(mu6 (as in Netscape Navigator) or 8\(mu8\(mu4 |
| (as in previous releases of Plan 9), picking 1 color in each, |
| the |
| .B rgbv |
| color map uses a 4\(mu4\(mu4 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. |
| .PP |
| The following function computes the 256 3-byte entries in the color map: |
| .IP |
| .EX |
| .ta 6n +6n +6n +6n |
| 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; |
| } |
| } |
| } |
| .EE |
| .PP |
| There are 4 nested loops to pick the (red,green,blue) coordinates of the subcube, |
| and the value (intensity) within the subcube, indexed by |
| .BR r , |
| .BR g , |
| .BR b , |
| and |
| .BR v , |
| whence |
| the name |
| .IR rgbv . |
| The peculiar order in which the color map is indexed is designed to distribute the |
| grey shades uniformly through the map\(emthe |
| .IR i 'th |
| grey shade, |
| .RI 0<= i <=15 |
| has index |
| .IR i ×17, |
| with black going to 0 and white to 255. |
| Therefore, when a call to |
| .B 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. |
| .PP |
| The |
| .B rgbv |
| map is not gamma-corrected, for two 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 color 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 color cube with colors whose differences are |
| almost imperceptible. |
| Either reason suggests concentrating |
| the available intensities at the low end of the range. |
| .PP |
| 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. |
| .PP |
| Colors may also be created with an opacity factor called |
| .BR alpha , |
| which is scaled so 0 represents fully transparent and 255 represents opaque color. |
| The alpha is |
| .I premultiplied |
| into the other channels, as described in the paper by Porter and Duff cited in |
| .IR draw (3). |
| The function |
| .B setalpha |
| (see |
| .IR allocimage (3)) |
| aids the initialization of color values with non-trivial alpha. |
| .PP |
| 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 example, for the RGB24 format, |
| the byte ordering is blue, green, red. |
| .PP |
| To maintain a constant external representation, |
| the |
| .IR draw (3) |
| interface |
| as well as the |
| various graphics libraries represent colors |
| by 32-bit numbers, as described in |
| .IR color (3). |
| .SH "SEE ALSO" |
| .IR color (3), |
| .IR graphics (3), |
| .IR draw (3) |