Articles Archive
Articles Search
Director Wiki

Poaching Adobe's RGB Color Picker

October 1, 2000
by Tim Bank

Why reinvent the wheel, when you can borrow one from someone else? That's the question that came to mind when I needed a quick color picker to add to a prototype application I was working on. Director 8's Imaging Lingo allowed me to quickly and easily reproduce Adobe Illustrator's RGB color picker, all within Director, without using an Xtra.

A Director 8 sample movie is available for download in Mac or PC format.

The first thing I had to do was reverse-engineer Adobe's picker. It consists of 3 sliders: Red, Green, and Blue. These sliders range from 0 to 255 and describe the RGB values of the color. The tricky part is that when the slider is moved, the 3 color "tracks" change color gradients.

If you look, the colors on each track that the sliders point to are the same for each track. When you adjust one color value by moving the slider, the colors of the other two sliders change to represent the colors that could now be created by changing the remaining values. It's important to note that the colors in the track that you are adjusting remain constant, while the other two change.

Knowing this, you can now create all three tracks, given the current value of each slider. You will need to iterate through each color value, while keeping the other two color values constant. Where redindex, greenindex, and blueindex are the color values for each slider:

repeat with x = 0 to 255

  rgb( x, greenindex, blueindex) --for the red slider
  rgb( redindex, x, blueindex) --for the green slider
  rgb( redindex, greenindex, x) --for the blue slider

end repeat

By locking the other two color values, you can obtain every color that a specific color slider can represent (and you will need these values later).

Now that you can generate the colors needed, you need to paint them into the slider tracks. Use the setPixel() function to do this.

setPixel() follows the syntax of :

imageObject.setpixel(<location in image>, <color>)

Where <location in image> can be either X and Y coordinates

setpixel(0,23, <color>)

or a point. For <color>, it gets tricky. The color can be either a color object (such as rgb(0,0,255) for blue) or an index or raw integer. For consistency, I recommend using the colorObject, because it works regardless of the color depth you are displaying. But for pure speed, if you can use the raw integer, you will get much better performance.

What is a raw integer? A raw integer is a 24 bit number that describes the color. It allocates the leftmost 8 bits for red, the center 8 bits for green, and the rightmost 8 bits for blue. This is where we get the 0-255 number values for each color (8 bits ON is 255). To count by bits, we count using 1s and 0s, so the number 6 is represented as 00000110 in 8 bits (00000000 = 0, 00000001 = 1, 00000010 = 2, 00000011 = 3, 00000100 = 4, 00000101 = 5, etc.). By concatenating the three 8 bit strings together, we get a 24 bit number that represents all 3 colors, each described with 8 bits. This would make black = 0, or 000000000000000000000000 when expressed as a raw integer. White would then be 16,777,216, or 111111111111111111111111 when expressed as a raw integer.

For 8 bit colors, you are actually using an 8 bit index into a Color Lookup Table, or CLUT, of 24 bit colors. Using 8 bit colors is very fast, but you need to know the location of the color you want in the CLUT, and if the active palette is the CLUT you are intending to use. If I index into what I think is the Mac system palette, and it is actually the Windows system palette, I will get colors that are completely different from what I am expecting. So again, my advice is to use a color object if there is a specific color you want, and you don't feel like checking what color depth you are in or indexing into a color palette. (I also recommend that you read up on color() in Director's help to learn the many cool features of color objects).

Drawing the tracks

Each track is a separate #bitmap cast member, 1 pixel tall by 100 pixels wide (stretched on the Stage to 4 pixels tall). This means you need to squeeze 256 color values into 100 pixels. The resulting code, where members 10, 11, and 12 are the color tracks, looks like this:

repeat with x = 0 to 99

  member(10).image.setPixel(x, 0, rgb(integer(x / 99.0 * 255) ,greenindex, blueindex))
  member(11).image.setPixel(x, 0, rgb( redindex,integer(x / 99.0 * 255), blueindex))
  member(12).image.setPixel(x, 0, rgb( redindex,greenindex, integer(x / 99.0 * 255)))

end repeat

To obtain a value from 0 to 255 evenly spread between 100 pixels, I am iterating from 0 to 99 (that is, 100 times) and creating a percentage or ratio that is then applied to 255. The first pixel will be 0% of 255, or 0, and the last pixel will be 99/99, or 100% of 255, or 255. I am also moving one pixel to the right (in the X direction) for each color that I am iterating through. The finished product is a smooth gradient from 0 to 255 for that color. Since the track is vertically uniform, I can stretch it on the Stage to 4 pixels tall and skip having to calculate the line 3 more times for each track (which would make the image 4 pixels tall and not make it necessary to stretch it on the Stage).

Color Chips

To show what color the user has selected, there are two color chips on the left side of the sliders (one for line color, and the other for fill color). By making the chips 1 bit bitmaps, I can make them any color I want to by setting the color property for the sprite.

sprite(fillsprite).color = rgb(redindex,greenindex,blueindex)

The three RGB color values are my slider values. By coloring the sprite and not repainting the #bitmap, I not only get better performance, but I also am not altering the #bitmap cast member (a possibly destructive thing if your code goes awry).

I also wrote handlers that bring the color chip into focus when it's clicked on (resetting all the sliders), limit text entry for the RGB values, and a slider behavior that is attached to both the slider and the tracks themselves. That's it!

Tim has a BS degree in Cognitive Science from UCSD where he learned to program in LISP and CLOS (the origins of Lingo). He has been working with Director since version 3 (RIP overview) and lived through the "Purple Revolution Party" (Director's migration to the PC). Tim also enjoys working with 3D Studio MAX and doing GUI design. He has developed numerous projects for clients such as GTE, HP, and the Office of Naval Research.

Copyright 1997-2019, Director Online. Article content copyright by respective authors.