This is everything I have come to know about IDL and colors.
It's substantial.

Colors and IDL
==================

In IDL, a color is composed of 3 values, known as a color triple.  The
color may be expresses as (red, green, blue) where each of the
three values dictates the amount of red, green, and blue light
assigned to this color on the display device.  Each value has an 8-bit
range and may be assigned a value between 0 and 255.  So, a specific
color may be composed of 28 shades of red, 28 shades of green, and 
28 shades of blue, for a grand total of 224 ( = 16.77 million) available 
colors.

COLOR TABLES

A color table consists of three columns of numbers, the first
containing values of red, the second values of green, the last values
of blue.  You can access a color in the color table using an
index, which is just the row of the color table.  The color
index tells the computer where to go and grab a color in the color
table.  So, if a pixel in an image has the value 64, then the color
index is 64; the computer grabs the 64th row of the color table.  This
might happen to be (255,255,0), which would correspond to the color
yellow.  This is known as the Indexed Color Model, since an index is
used to specify a color.

IDL always uses the Indexed Color Model when run on 8-bit display
devices.  This is completely necessary since there are a maximum of
28 colors available on such devices!

COLORS ON A 24-BIT DISPLAY





[The semantics seem odd here: in reality, a color table forces a
representation for a color to be broken into its constituent elements
(r,g,b) and placed into a table, thus the value representing a color
is necessarily decomposed; however, the RGB Color Model
requires that the constituent parts be combined into a single color
value, which is certainly an undecomposed quantity.  Rather, my
guess as to how this confusing nomenclature surfaced is as follows:
the Indexed Color Model picks a color (any color) based on an index,
which itself contains no information on the (r,g,b) content of the
color that it references in the color table, so in this sense it is
undecomposed into r,g,b values; the RGB Color Model accesses a
color with an index that is built from the r,g,b contributions to the
color, hence the single value references a color whose r,g,b values
can be decomposed.  I think this was a poor choice for a
descriptor.]


X WINDOWS VISUAL CLASSES

A more fundamental issue than how IDL handles color is how the
hardware handles color!  There are three types of displays: Gray
Scale, Pseudo Color and Decomposed Color displays.

* decomposed (separated into constituent parts)


* visual classes

* N.B.  Usually, your desktop manager sucks up (quite) a few color
table indices, so if you start up IDL... 

Display Device  : X
Visual Class    : PseudoColor
Visual Depth    : 8-Bit
Color Table Size: 50
Number of Colors: 50
Decomposed Color: 0

use window, colors=256

Display Device  : X
Visual Class    : PseudoColor
Visual Depth    : 8-Bit
Color Table Size: 256
Number of Colors: 256
Decomposed Color: 0

* xdpyinfo


Visual NameColorColormap8-bit24-bit
StaticGrayGrayscaleStatic++
GrayScaleGrayscaleDynamic++
StaticColorUndecomposedStatic++
PseudoColorUndecomposedDynamic++
TrueColorDecomposedStatic-+
DirectColorDecomposedDynamic-+
When using a 24-bit display, IDL uses "decomposed" color when the RGB Color Model is used. Rather than a single color index which corresponds to a row in the color table, IDL tries to decompose the color index into 3 separate indices. It assumes that the color index is a 24-bit long integer. The lowest 8 bits of the number represent the red index, the middle 8 bits the green index, and the last 8 bits the blue index. Here's how to convert color indices (0 to 255) into a 24-bit integer: COLOR_INDEX = R + G*256L + B*(256L)^2 or, if you're nasty, COLOR_INDEX = long(R) + ishft(long(G),8) + ishft(long(B),16) You could use hexadecimal notation, but real men and women don't. In case you're wondering, it takes only 2 hexadecimal digits to set 8 bits. The digits 0-9,A-F correspond to 0-15, so that '6B'xL = (6*16)+11 = 107 and 'FF'xL = (15*16)+15 = 255. In hexadecimal, yellow would be 'FFFF00'xL. (In IDL, hexadecimals need to be in single quotes and followed by an x. We include the L to make sure the resulting value will be a 24-bit long integer.) The only two visual classes that use the RGB Color Model are TrueColor and DirectColor. static = read-only colormap dynamic = writable colormap , a static color display in which colors are displayed directly. A dynamic color table has the property (good or bad) of changing the color of a pixel immediately when a color table is changed. However, a static color table will (for the most part) allow pixels to retain their colors when color table values are changed since the colors are specified directly. Therefore, 24-bit displays are incredibly valuable tools for research since they are able to display all 224 colors simultaneously, while 8-bit displays can only display 28 simultaneous colors even though more than 16 million are available! You can discover what IDL is color model you are using as follows: IDL> device, get_visual_name=name, get_visual_depth=depth IDL> print, name, depth The visual name will be either PseudoColor, DirectColor, or TrueColor, while the depth will be either 8, 16 or 24 (the number of bits necessary to specify a color in the visual class.) EASY... PseudoColor : a dynamic color visual TrueColor : a static color visual NOT-SO-EASY... DirectColor : only available on UNIX machines. Usual side effect is a private color map in which the graphics window takes up all the correct colors, causing other windows to disappear. This problem has earned its own name: "the color flashing problem". Doesn't always happen, but more than likely it will. the problem is a result of the way in which the X Window manager handles color tables. Here are the options you have for the visual class assignment statements using UNIX: IDL> device, pseudo=8, retain=2 IDL> device, true_color=24, retain=2 IDL> device, direct_color=24, retain=2 You may as well stick the correct one for your system in your .idlstartup file. SPECIFYING COLORS ON 8-BIT DISPLAYS Suppose you wanted to input the color yellow into the current color table at the position 66 and the color red at position 132. Just use the tvlct command. Here's an example that will show you what's happening: IDL> device, get_visual_name=a, get_visual_depth=b IDL> print, 'Visual: ', a, b IDL> ysize = 256 IDL> xsize = 256 IDL> window, 0, ysize=ysize, xsize=xsize IDL> loadct, 6 IDL> tvlct, 255, 255, 0, 66 IDL> tvlct, 255, 0, 0, 132 IDL> tv, indgen(ysize) ## (intarr(xsize)+1) KEEPING TRACK OF THE COLOR TABLE All IDL color table procedures keep track of the current color table in a common block called COLORS: common COLORS, r_orig, g_orig, b_orig, r_curr, g_curr, b_curr Each variable is an array of length equal to the number of color indices. If you want to access and diddle with the color table, the convention is to read the current table from r_orig, g_orig, b_orig, modify it, load it with the tvlct procedure and leave the modified color table in r_curr, g_curr, b_curr. SWITCHING DEVICES BUT KEEPING THE SAME COLOR TABLE If you want to conserve the current color table but send your image to a new device, say a PostScript file, send both the /color and the /interpolate keywords to your call to device. MAKE DEVICE INDEPENDENT COLORS STRETCHING A COLORTABLE If you want to take the currently loaded color table and stretch the entire range of colors over a subset of color indices, use the stretch procedure: IDL> stretch, 66, 200 stretches the color table from index 66 to 200. Everything outside of this range will be set to the maximum color index. Use the /chop keyword to set the outside range to 0. BLAHBETY BLAH BLAH loadct, 3 stretch, 0, !d.table_size-8 setcolors tv, bytscl(image, top=!d.table_size-8) N.B. You might think, as I did, that the following would be equivalent: tvscl, image, top=!d.table_size-8 but according to Fanning, "if color is important to you (and it almost always is), then you probably never want to use the TVScl command." Rather, scale the data yourself. Since both TV and TVScl are proprietary, there's no easy way of making an absolute comparison, but one thing is certain: TVScl scales an image into the number of colors in your IDL session. Also, two data sets may have different ranges, so scaling with TVScl will introduce errors! Now overplot or xyouts accessing the colors stored in plotcolors. (If you want to make an image of a separate data set, but over the same data range, make use of the min and max keywords for BytScl.) DISPLAYING 24-BIT IMAGES If you want to display a 24-bit image, you must either load a gray-scale color table or set the decomposed device keyword to 1! A 24-bit image will always be a 3-D data set... 3 2-D images: the red version, the green version, and the blue version. For completeness: IMAGE: LINGO: m-by-n-by-3 band-interleaved m-by-3-by-n row-interleaved 3-by-m-by-n pixel-interleaved When displaying a 24-bit image with TV, you need to specify which interleaving was used with the True keyword: True=1 pixel-interleaved True=2 row-interleaved True=3 band-interleaved *** If you want to view a 24-bit image, but you're on an 8-bit display, here's what you do (take image to be your 3-D color image): IDL> image2d = color_quan(image, 1, r, g, b) IDL> tvlct, r, g, b IDL> tv, image2d I've never tried this, but it's supposed to give you a ratty version of a 24-bit color image. I'd suggest just throwing your monitor out the window, saying it was stolen, and having your advisor buy you a new one with a 24-bit display. IMAGE INTERLEAVING redimg = byte( (0 > (intimg1*colr[ colorimg, 0])) < 255) grnimg = byte( (0 > (intimg1*colr[ colorimg, 1])) < 255) bluimg = byte( (0 > (intimg1*colr[ colorimg, 2])) < 255) ;DISPLAY THE IMAGE INTERLEAVED DATA CUBE... tv, [[[redimg]], [[grnimg]], [[bluimg]]], $ xtvleft, ytvbottom, ysize=yplotsize, xsize=xplotsize, $ /normal, true=3 DISPLAYING A 24-BIT IMAGE ON AN 8-BIT DISPLAY DISPLAYING AN 8-BIT IMAGE ON A 24-BIT DISPLAY Since 24-bit colors are directly accessed, working with color tables on a 24-bit machine is tricky. Therefore, if you change the color table, you need to redisplay your image to see the changes. On an 8-bit machine, you see the changes as soon as you change the color table since the colors are indexed to a value in a color lookup table. However, DirectColor devices are dynamic color devices: a change to the color table values automatically causes a change to the image! TrueColor devices are static color devices: "the colors used for the graphics are not tied in any way to the colors loaded in the current color table. If you change the color table values, you MUST redisplay the graphic to see the colors take effect. I presume, but do not know for sure, that the Mac is also a True-Color device." (Fanning) If on a static color device, set color decomposition off, change the color table, then redisplay the image. Probably want to set color decomposition back on after redisplaying the image. HAVEN'T COME UP WITH A WAY TO FIX THIS, BUT FANNING HAS A WAY. Color Images in PostScript ========================== Images may be made with 1,2,4,8 bits per pixel yielding 1,2,16,256 possible colors. A pseudo-color image is a 2D image with each pixel indexing the color table, obtaining an RGB value for each possible pixel value. A true-color image is a 3D image, one of the dimensions having a size of three (one for each color component, RGB). It is therefore, three 2D images... one for each color component. By convention the color order is ALWAYS RGB. So an n x m true-color image can be ordered in the following ways: (3,n,m) : pixel interleaved (n,3,m) : row interleaved (n,m,3) : image interleaved When calling TV or TVSCL, the TRUE keyword must be set to: 1 : pixel interleaving 2 : row interleaving 3 : image interleaving So, in order to set up the PostScript device with 24-bit color (8 bits per color!) set_plot, 'ps', /copy, /interpolate device, file='file.ps', /color, bits_per_pixel=8 [N.B. COPY keyword demands that the device color tables are copied directly from IDL's internal color tables. However, if the new device's color tables contain more indices than those of the old device, the new device's tables are not completely filled!! Use the INTERPOLATE keyword to force the internal color tables to be interpolated to fill the range of the new device!] Now, combine your red, grn, and blu images to (n,m,3) cube (image interleaved) and TV them with true color: tv, [[[red]], [[grn]], [[blu]]], true=3 Now revert back to x-windows: device, /close set_plot, 'x' ----- We may also create a pseudo-color table based on the Lightness-Hue-Brightness (LHB) system. Carl suggests this color mapping: pseudo, 100, 100, 100, 100, 22.5, .7, colr