My brother had some questions about how color is represented on many devices, so I wrote a simple app called ColorCode awhile
back as a demo of basic RGB principles and I decided to post it here.
Most anyone reading this knows that generating complex color on a TV, computer monitor, or a typical laser projector is a simple
matter of combining various levels of Red, Green, and Blue together into one package. If you lock all 3 color channels to the
same varying value, you get Black & White like an old TV set.
I bought my first PC in 91, and the video card was good old fashioned palette so you could only have a mere 256 colors out of
some 256K possibilities on the screen at any one time, due to austere memory and bit precision limits. A few years later, I
got my hands on a 24 bit 'true color' card that allowed a full 8 bits of precision (a range of 0-255) for each color channel
of every pixel on the screen. I bought a couple of discs of high quality photo images to put my new card to the test. Back then,
I could only code palette-based DOS graphics and had no way to work in the true color domain. The desire to get a handle on
discrete RGB control lead me to creating test images in Windows Paint and then hacking them in a hex editor to crack the code
of the 24 bit color bitmap format so that I could blindly write test patterns to a BMP file and view the result after the fact...
it was worth the trouble!
I finally got what I wanted, total independent control of RGB- now what? Working with two variables is not so bad, but three is a
daunting mess if you have no strategy to orchestrate them together in a meaningful way. The first step is to strategically ramp
levels of all three colors in a single organized number line to produce the basic RGB spectrum. Building the basic spectrum
is a matter of holding one color channel at max level and ramping the second (up or down), while leaving the third at zero
throughout and grinding through all the combinations - it's much easier to illustrate than to describe.
The result is similar to a rainbow, or white light split though a prism, but there are important differences- particularly
in the violet range. The RGB spectrum is better represented as a wrap-around continuum.
The 24 bit RGB spectrum has a total of 1530 discrete values (255 * 6) and you could think of this spectrum as a 1530 color palette
that can be readily loaded into an array for easy indexing over a range of 0-1529. Here is an example:
Dim N As Integer
Dim R(0 To 1530) as Byte
Dim G(0 To 1530) as Byte
Dim B(0 To 1530) as Byte
Note that color index value 1530 is equal to color index 0, so the total range of unique values goes from 0-1529.
Negative color: RGB has its equivalent of the old photographic film version. In RGB there are no negative numbers; each channel
can only range from 0-255, and white is the sum total of everything (all color channels set at 255), so a negative is white minus
the positive, and the two added together equal white.
Rn = 255 - R
Gn = 255 - G
Bn = 255 - B
Grayscale: If you lock RGB channels to the same value and ramp that single level up you progress from black through gray into white.
Color to Grayscale (Black & White or Intensity) conversion:
In the upper right corner of ColorCode there are three rows of color boxes: the first is white (R + G + B), second is R, G,and B
at full 255 level, and the last row is Yellow (R + G), Cyan (G + B), and Magenta (B + R). Even though R, G, and B boxes are at full
numerical level, the perceived brightness of each color is quite different- Green is way brighter than Blue, and Red falls somewhere
in between. The perceived differences in brightness must be taken into account when calculating an overall Intensity (I) or Grayscale
value for a given RGB combo. Green by far carries the most weight, as the human eye is most sensitive to it.
I = 0.299 * R + 0.587 * G + 0.114 * B
Now all you have to do is to set R, G, and B to I and it's like the 1950's all over again.
Here's the RGB spectrum converted to grayscale.
As to the pedigree of the individual RGB coefficients, one theory states that they are a result of careful measurements of the lengths
of passageways in the Great Pyramid... another theory holds that they are a result of measured exposure levels on common black and white
film using white light passed through red, green, and blue filters. Back in 1914, Charles Taze Russell seemed to favor the pyramid thing.
Who knows. More to come.
Once you build the basic RGB spectrum described earlier, the next thing is to know how to systematically lighten or darken it.
Darkening is easy, simply multiply RGB channels by a Saturation factor (S) where S is between 0 and 1. When S = 1, color is at its maximum level.
Rnew = R(X) * S
Gnew = G(X) * S
Bnew = B(X) * S
You could think of the above as a 2D palette or color plane where X is Hue and Y is Saturation.
Lightening takes an additional step- as mentioned previously, if you lock RGB channels to the same value and ramp that single level up
you progress from black through gray into white.
To lighten, lower S to ramp down the original RGB color and add in a ramped up white bias as the additional step.
WhiteBias = (1 - S) * 255
Rnew = R(X) * S + WhiteBias
Gnew = G(X) * S + WhiteBias
Bnew = B(X) * S + WhiteBias
Light and dark together:
The key thing missing in the above image is gray. The next step is to establish a way to transition from
the dark to the light using a third variable which I will call WhiteLevel and it lies between 0 and 1.
Rnew = R(X) * S + OverallBias
Gnew = G(X) * S + OverallBias
Bnew = B(X) * S + OverallBias
WhiteLevel at half scale (medium gray 0.5):
Now with Hue, Saturation and WhiteLevel you have an organized 3D continuum to work with:
There are plenty of other ways to manage RGB in a structured 3 component model.
Pick a color... This is a shot of the custom color selection tool from the Windows Common Dialogue that is accessible from many graphic utilities:
Near the middle is a 2D color plane where X is Hue and Y is Saturation with WhiteLevel fixed at medium gray (0.5). The third variable is a Luminance
level on the right and it applies the lightening and darkening formulas defined earlier to the selected point in the 2D color plane to yield the
custom color.