Another interesting application of the RGBOfunction is to generate gradients. When you move from one comer to another on the same side of the RGBcube (as from red to black or fromgreen to blue), one or more components change value. The colors along the path that connects any two points in the RGBcube form a gradient. To specify a gradient, you must call the RGBOfunction many times, each time with a slightly different argument. Suppose you want to fill a rectangle with a . gradient. Because there’s no function to produce the gradient, you must draw . vertical or horizontal lines with slightly different colors and cover the area of the rectangle. Figure 7.2 shows the ClrGrads application, which lets you specify the starting and ending colors of the gradient (with the two narrow PictureBox controls on either side of the Form), and then it generates linear and circular gradients. When you click the two narrow PictureBox controls at the two ends of the Form, the Color common dialog box is displayed, where you can select the gradient’s starting and ending colors.
The starw color is the triplet (startRed, startGreen, startBlue), and the ending color is the boiplet(endRed, endGreen, endBlue). If the rectangle’s width in pixels is PWidth, you must write a loop that increases the red component by retUne, which is (EndRed StartRed)/PWi dth; the green component by greenlnc, or (EndGreen StartGreen) /Pwidth, and the blue component by bluelnc, or (EndBlue StartBlue)/PWidth. Following is the complete code for painting the rectangle with a gradient.
The ClrGrads Application
nus code draws as many vertical lines as there are pixels along the PictureBox. (The control Scale Mode should be 3-Pixel.) Each new line’s color will be quite similar to the color of the previous line, with its three components adjusted by the amount redlnc, greenlnc, and bluelnc. The values of the increments are chosen so that the first line·has the gradient’s starting color and the last line has the gradient’s ending color. With variations on this technique, you can design vertical, diagonal, and eve” circular gradients. For a circular gradient, draw circles, starting with the outer: one, and then decrease the radius at each step. You’ll see this technique in the Gradients application.1ater in the chapter. The code in the ChGrad applications for generating gradients is straightforward, but it requires that you supply the color components of the starting and ending colors. Although this may be feasible in some applications, it’s best to let the user select . two colors and then have the program generate the gradient between them. The tricky part for you will be extracting the three basic color components from a Color value, a topic covered in the following section.
The RGBO function combines the three color components to produce a Color value, which isa Long number, but Visual Basic lacks a function to return the three color componere from a Color v.ilue. Sun,?osc u user select.sviorvalue from the Color C(lUt(lUi, diaiog box, and your application needs to know its color components. Ir. an image processing application, such as the one we’ll develop later you want to read pixel values, isolate their RGB color components, and then process them separately. The Gradient application must calculate the three basic components of the starting and ending colors selected by the user with tile help of the Color common dialog box. It’s necessary, therefore, to write a function that extracts the RGB color components from any Color value.
To do so, you must first look at how the three color components are stored in a Long integer. A Long integer is made up of four bytes, three of which store the values of the RGB components and one that stores zero. The most significant byte is zero, followed by the blue, green, and red components, respectively. The Long integer that corresponds to the triplet (64, 32,192) is 12591168. This number bears no-similarity to the original numbers. If you represent the color components with their hexadecimal values, the RGB triplet is (40, 20, CO).If you place these numbers next to one another, the result is the hexadecimal format of the Long number. If you get the hexadecimal representation of the number 12591168 (with the Hex() function), the value is C02040. The last two digits correspond to the red component, the next two digits correspond to the green component, and the l!0 most significant hexadecimal digits correspond to the Blue value. Wher\ you place the decimal values of the color components next to each another, the result bears no resemblance to the Long Integer value they represent. If you place the hexadecimal values of the color components next to each other, you get the hexadecimal representation of the Long integer that corresponds to the Color value. And this explains why hexadecimal numbers are used so frequently in specifying Color values. The following three statements extract the values of the three color components from a Color value stored in the pixel& variable:
The i and the j variables are the coordinates of the point whose value we’re examining. Since the Red value is stored in the least significant byte of the number, it’s the remainder of dividing the number by 256. To extract the next most significant byte, you must set the byte in front of it and after it to zero. This is done by combining the number with the hex number OOFFOO’ using the AND operator. If you type this number, though, VISual Basi~ truncates it to FFOOautomatically, because the.1eading zeros make no differenCe. But when VISual Basic ANDs the two numbers, it takes into consideration the last two bytes
(the length of the number FFOO)and doesn’t AND the high order bytes (the first two bytes). To force Visual Basic to AND all the digits, you must use the number FFOOFFOOT.he high order byte of the Color value is zero anyway, so it doesn’t make any difference what value it’s ANDed with. The Green value is stored in the results’ second least significant byte. To reduce it to a Byte value, divide it by 256. Finally, you do something similar with the third byte from the right. YouAND the Color value with FFOOOOto zero the other bytes and then divide the result by 65536 (which is 256 • 256).
If you aren’t familiar with hexadecimal number operations, print the intermediate results to see why this technique works. Let’s start with the Color value 12591168. If you AND it with FFOOFFOOth, e result is 12591104.The hexadecimal format of this number is 002000. The byte 20 is there already, but it must be shifted down to the least significant byte position, which is what happens when it’s divided by 256. The result is the value of the green color component. To extract the Blue value, the Color value is ANDed with FFOOOOT.he result of the operation 12591168 AND FFOOOOis 12582912 in decimal format, and COOOOOin hexadecimal. The Blue component’s value is there, but this time it must be shifted to the right by two bytes, which is accomplished by dividing it with 65536. The process is depicted graphically
the number at the top is the hexadecimal representation of a Long Color value and the number below is the mask, which must be ANDed with the Color value to extract the RGB components of the color. The left-most value is the Red component (always in hexadecimal notation). The next value must be shifted to the right by two digits to yield the Green component, and the last value must be shifted to the right by four digits to yield the Blue component. To shift a hexadecimal value to the right by a digit, you must divide it by 16 (to shift it by two digits divide by 16.••16, or 256, and so on). There’s also another technique to extract the color components from a Color value, which is conceptually simpler, but a bit slower. If you use the hexadecimal represent .rion of the original Color value, the values of all three color,COOlpO’ nents already exist. All you have to do is extract them with string manipulation functions. The hexadecimal format of the number 12591168is the string IC02040″.
The Red color component is the value of the hexadecimal number formatted with the two right-most digits of the number. The Green component is the value of the hexadecimal number formatted with the next two digits, and the Red component is the value of the hexadecimal number formatted with the two left-most digits of the number. Here’s the equivalent code:
Now you can write three functions, GetRedO, GetGreenO, and GetBlue(), which accept as an argument a Color value and return the value’s RGB components. The code for the three functions that extract a color’s basic components follows,
You should replace the term 256&t • 256& with 65536 to speed up the calculation a little. I’ve used the product to make the code easier to read and understand.) With the help. of these functions, you can extract the color components of the gradient”s starting and ending colon, calculate the increment, and use it to generate and display the desired gradient. Following is the compIete code behind the Linear Gradient button
The code behind the Circular Gradient button is quite similar, but instead of drawing lines, it draws circles of varying colors. First, it draws the largest circle, then it draws all the successive circles, each having a radius smaller than that of the previous circleby one pixel. You can try other types of gradients on your J own, such as diagonal gradients or off-center circular gradients. You can also use this technique to fill your Forms or certain controls with gradients when a Form is loaded. Grayscale gradients make quite interesting backgrounds. They have a subtle effect and add a nice three-dimensional look to your applicatioal5 are interface.
The FrmGrad application (which you’ll find in the chapter’s folder on the CD), shown in Figure 7.4, uses the code of the ClrGrads application to design a gradient as a background. (The buttons on the Form don’t do ,mythin)~j the figure simply shows how to use the gradient as a backdrop on a Form.) The gradient is generated as the program loads. The code is nearly identical to that presented earlier in the ClrGrads application and is executed from within the Form’s Resize event so that the gradient is adjusted each time the user changes the Form’s size. The FrmGrad Form won’t look as nice on systems with 256 colors because the current palette doesn’t contain all the colors required by the gradient.