Working with Colors and Brushes


Now that you have a concrete understanding of using the drawing functions provided by the GD extension, it's time to introduce the concept of working with brushes when using the drawing functions and to explain some of the less-obvious issues encountered when working with the color palette. Because you have already been exposed to the simplest form of color allocation using imagecolorallocate(), I'll take things from there.

Working with the Image Palette

In all the examples thus far, I have focused on creation of a brand-new canvas. These canvases used only a handful of colors, which were all allocated using the imagecolorallocate() function. Although this method has served my purposes nicely thus far, in a real application of the GD extension, this concept alone is not enough. Along with standard color allocation, the GD extension provides a number of methods that can be used to take advantage of an already existing color palette. Although most useful when working with images that are loaded using a function such as imagecreatefromjpeg(), these functions have uses in many circumstances.

Matching Colors in an Existing Palette

When the imagecolorallocate() function is used, it attempts to create a new color in the palette. However, when you're working with an already existing palette, it's possible that the color you need may already have been allocated. In situations where this is a possibility, the GD extension provides the imagecolorexact() function with the following syntax:

 imagecolorexact($img_r, $red, $green, $blue); 

$img_r is the image resource and $red, $green, and $blue represent the RGB triplet to allocate. If the specified color exists in the palette, this function will return the index of it; however, if the color does not exist, the value of 1 is returned.

As the name of this function implies, the imagecolorexact() function returns only the index of a color in the palette if it matches exactly with the specified color. For situations where a "close" (but not exact) match would be suitable, the GD extension provides the imagecolorclosest() function. The syntax for this function is as follows:

 imagecolorclosest($img_r, $red, $green, $blue); 

$img_r is the image resource and $red, $green, and $blue represent the desired RGB triplet color. When executed, this function will return the index of an already existing palette color that most closely matches the requested color. The closest color is determined by mapping every color triplet in the palette to the X, Y, Z coordinate of a three-dimensional point (red = X, blue = Y, green = Z). The requested color is then also mapped in the same fashion and the color that is mathematically closest to the requested color is returned. This means that for an image with a small number of colors (or a large number of colors of similar shades) in its palette, it is likely that the color returned by imagecolorclosest() may be drastically different from the color requested.

As I just stated, depending on your needs the imagecolorclosest() function may produce undesirable results. Another alternative to this function, which typically produces better results (closer matches), is to match the color based on its hue, whiteness, and blackness though the use of the imagecolorclosesthwb() function. The syntax for imagecolorclosesthwb() is as follows:

 imagecolorclosesthwb($img_r, $red, $green, $blue); 

$img_r is the image resource and $red, $green, and $blue represent the RGB triplet to allocate. For images that are not considered "true color" (such as those allocated using imagecreate() instead of imagecreatetruecolor()), this function may return 1 if no colors have yet been allocated. However, in the case of true-color images, this function will always successfully return an index to the desired color.

As you may have already realized, the color-retrieval functions that have been discussed could be combined into a custom function resembling something like the following:

 <?php     function getcolor($img, $red, $green, $blue) {         $color = imagecolorexact($img, $red, $green, $blue);         if($color == -1) {             $color = imagecolorallocate($img, $red, $green, $blue);             if($color == -1) {                 $color = imagecolorclosest($img, $red, $green, $blue);             }         }         return $color;     } ?> 

A function such as the preceding getcolor()example would ensure that the best match for the requested color was always returned without allocating any new colors unless it is necessary. However, as is usually the case with PHP, someone has already taken care of this for you! The imagecolorresolve() function (which is a part of the GD extension) ccomplishes the same task as my getcolor() function example. The syntax for this function is as you might expect:

 imagecolorresolve($img_r, $red, $green, $blue); 

$img_r is the image resource, and $red, $green, and $blue is the RGB triplet. As is the case with the preceding getcolor() function example, this function is guaranteed to return the best possible match for the desired color by first attempting to match exactly, allocate, or match closest to the provided color.

NOTE

The imagecolorresolve() function uses the imagecolorclosest() function to determine the closest match to a color (not imagecolorclosesthwb()).


Removing and/or Modifying Palette Colors

Thus far, you have been exposed only to functions that work with creating or retrieving a color from the image palette. However, the GD extension allows you to also remove or alter a particular color in the palette. To remove images from a palette, PHP provides the imagecolordeallocate() function with the following syntax:

 imagecolordeallocate($img_r, $color); 

$img_r is the image resource to remove the color from, and $color is the index in the palette to remove. When a color has been removed from the palette, the slot that contained that color will be reused the next time a color is allocated using a facility such as imagecolorallocate(). In these cases, any pixels in the image that used the original color will instead use the newly allocated color. To illustrate this, see Listing 27.7:

Listing 27.7. Using imagedeallocate()
 <?php     define("WIDTH", 200);     define("HEIGHT", 200);     $img = imagecreate(WIDTH, HEIGHT);     $bg = $white = imagecolorallocate($img, 0xFF, 0xFF, 0xFF);     $black = imagecolorallocate($img, 0, 0, 0);     imagefilledrectangle($img, 10, 10, WIDTH-11, HEIGHT-11, $black);     imagecolordeallocate($img, $black);     $red = imagecolorallocate($img, 0xFF, 0, 0);     header("Content-Type: image/png");     imagepng($img); ?> 

Figure 27.7. Using the color palette for flood filling.


Although this is an effective means of replacing all occurrences of one color with another, the GD extension provides a more straightforward approach by allowing you to directly replace a particular index in the palette with another color using the imagecolorset() function. The syntax for this function is as follows:

 imagecolorset($img_r, $color, $red, $green, $blue); 

$img_r is the image resource; $color is the color index in the palette to replace; and $red, $green, and $blue is the RGB triplet to replace $color with. Using this function, the example in Listing 27.7 could be rewritten by replacing imagecolordeallocate($img, $black);

 $red = imagecolorallocate($img, 0xFF, 0, 0); 

with the following single line of code:

 imagecolorset($img, $black, 0xFF, 0, 0); 

Creating Transparency in Images

When creating or working with images, it is sometimes quite useful to designate a particular color within the image as transparent. Although the GD extension no longer supports images in the GIF format, the supported PNG format supports the use of transparent colors. From PHP, creating a transparent image is as simple as designating an allocated color in the palette as the "transparent" color using the imagecolortransparent() function. The syntax of this function is as shown:

 imagecolortransparent($img_r [, $color]) 

$img_r is the image resource, and the optional parameter $color is the color to designate as the transparent color. When a color has been designated as the transparent color, it will not be drawnallowing whatever was underneath it (the background) to be shown. When executed, this function returns either the transparent color in the palette or, if the $color parameter was not specified, the current transparent color.

NOTE

Only one transparent color can be specified for a given image. Hence, multiple calls to the imagecolortransparent() function will cause the previous transparent color to revert to a real color.


Color Transparency Using Alpha Blending

Now that you have been exposed to the concept of transparency, it is time to discuss the concept of RGBA colors. The acronym RGBA stands for Red, Green, Blue, Alpha and is a method of defining "transparent" colors. These colors, like normal colors, are created from a RGB triplet; however, they also have associated with them an "alpha level." This value has a range from zero to 127 (0x0 to 0x7F in hex) and represents how transparent that color is when drawn on the canvas (0x7f/127 is maximum transparency).

The basic concept of RGBA colors is that when a color is allocated using the RGBA method and then drawn to the canvas, the color that is underneath the drawing area will not be completely erased. Instead, this color will be combined with the RGB value of the color being drawn to produce the actual color represented on the canvas.

NOTE

Because of the nature of alpha blending, chances are you will not receive the expected results unless you are working with a true-color image. For best results, use GD alpha blending with true-color images only (such as those created with the imagecreatetruecolor() PHP function).


To create an RGBA color, the GD extension provides the imagecolorallocatealpha() function with the following syntax:

 imagecolorallocatealpha($img_r, $red, $green, $blue, $alpha); 

$img_r is the image resource; $red, $green, and $blue is the RGB triplet for the allocated color; and $alpha represents the alpha level to use. As already stated, $alpha can be any value between zero (no transparency) and 127 (full transparency).

To illustrate the use of RGBA colors, the following script in Listing 27.8 shows how an RGBA color interacts with the other colors in an image:

Listing 27.8. Using imagecolorallocatealpha
 <?php         define("WIDTH", 300);         define("HEIGHT", 300);         $img = imagecreatetruecolor(WIDTH, HEIGHT);         $white = imagecolorallocate($img, 0xFF, 0xFF, 0xFF);         $yellow = imagecolorallocate($img, 0xFF, 0xFF, 00);         $red = imagecolorallocate($img, 0xFF, 0, 0);         $blue_t   = imagecolorallocatealpha($img, 0, 0, 0xFF, 0x40);         imagefill($img, 1, 1, $white);         imageline($img, 0,0, WIDTH-1, HEIGHT-1, $blue_t);         imagefilledrectangle($img, (WIDTH/2)-50, (HEIGHT/2)-50,                              (WIDTH/2)+50, (HEIGHT/2)+50, $yellow);         imagefilledrectangle($img, (WIDTH/2)-30, (HEIGHT/2)-30,                              (WIDTH/2)+30, (HEIGHT/2)+30, $red);         imagefilledrectangle($img, 10, 10, WIDTH-11, HEIGHT-11, $blue_t);         header("Content-Type: image/png");         imagepng($img); ?> 

As shown in Figure 27.8, three filled rectangles have been drawn on top of a diagonal blue line. As you can see, even though both smaller rectangles and the line were drawn prior to the large blue RGBA rectangle, all three are still visible. This is because this rectangle has been drawn with an alpha level set at half transparency (0x40 in hex; 64 in decimal) and was blended as necessary with the colors it was overwriting. This produces the visual effect that you can see "through" the large RGBA rectangle to the other colored shapes beneath it.

Figure 27.8. Using alpha channels.


Along with the imagecolorallocatealpha() function, the GD extension also provides the similar facilities to access colors in an existing palette, as was found for the non-RGBA color retrieval functions. Specifically, the GD extension also provides the following functions for working with RGBA colors:

 imagecolorallocatealpha($img_r, $red, $green, $blue, $alpha); imagecolorexactalpha($img_r, $red, $green, $blue, $alpha); imagecolorclosestalpha($img_r, $red, $green, $blue, $alpha); imagecolorresolvealpha($img_r, $red, $green, $blue, $alpha); 

As you can see, the same color retrieval functions that you have already been introduced to each have RGBA equivalent functions. Because each of these functions requires an identical set of parameters, there is no need to describe each one individually. For each of the preceding functions, $img_r is the image resource and $red, $green, and $blue represent the RGB triplet of the color. As expected, $alpha is the alpha level for the RGBA triplet and has a range of zero to 127 (0x0 to 0x7F).

Drawing Using Brushes

Now that I have exhausted nearly every topic related to colors and to using the palette in the GD extension, let's turn our attention to using brushes with the PHP drawing functions. When the GD extension is instructed to draw something on the canvas (such as when the imagerectangle() function is called) all drawing is done using a digital "brush" on the canvas. By default, this brush is defined as a single pixel of the requested color in the palette. Beyond this default brush (which is always available) the GD extension permits you to define any number of auxiliary brushes that can be used in its place. Changing the properties of the brush is done through a set of functions, which is the focus of this section.

Starting with the default brush, the most straightforward modification is to change the thickness of the brush. This modification is accomplished using the imagesetthickness() function, which has the following syntax:

 imagesetthickness($img_r, $thickness); 

$img_r is the image resource and $thickness is how thick (in pixels) to set the brush. As you would expect, the $thickness parameter must be greater than zero. When executed, this function will increase the size of the default brush to $thickness pixels.

Although imagesetthickness() enables you to draw shapes of arbitrary thickness and color on the canvas, it does not allow you to draw such things as dashed lines. For these relatively simple multicolored brushes, the GD extension provides the imagesetstyle() function. The syntax for this function is as follows:

 imagesetstyle($img_r, $style); 

$img_r is the image resource and $style is a style definition. In PHP, styles are defined as indexed arrays containing, in order, the colors defining the brush pixel-by-pixel. For example, assuming the variables $white and $black exist and represent their respective colors, the following array would represent a "dashed line" brush:

 $dashed = array($black, $black, $black, $white $white $white); 

In this example, the $dashed array now represents a simple brush that consists of three black pixels followed immediately by three white pixels. This array then could be provided as the $style parameter to the imagesetstyle() function to define the current brush style. After a style has been set using this function, it can be used to draw any geometric shape GD supports by using the IMG_COLOR_STYLED constant in place of what normally would represent the color in the function call. To illustrate this concept, Listing 27.9 draws a few simple geometric shapes using a styled brush. The resulting image is shown in Figure 27.9:

Listing 27.9. Using the imagesetstyle() Function
 <?php     define("WIDTH", 200);     define("HEIGHT", 200);     $img = imagecreate(WIDTH, HEIGHT);     $background = $white = imagecolorallocate($img, 0xFF, 0xFF, 0xFF);     $black = imagecolorallocate($img, 0, 0, 0);     imagerectangle($img, 0, 0, WIDTH-1, HEIGHT-1, $black);     /* Define Style arrays */     $dashed = array($black, $black, $black, $white, $white, $white);     $sos = array($black, $black,                     $white, $white,                     $black, $black,                     $white, $white,                     /* . . . */                     $black, $black,                     $white, $white,                     $black, $black, $black, $black,                     $white, $white,                     $black, $black, $black, $black,     /* - - - */                     $white, $white,                     $black, $black, $black, $black,                     $white, $white,                     $black, $black,                     $white, $white,                     /* . . . */                     $black, $black,                     $white, $white,                     $black, $black,                     $white, $white,$white, $white,$white, $white);     imagesetstyle($img, $sos);     imageline($img, 0, 0, WIDTH-1, HEIGHT-1, IMG_COLOR_STYLED);     imageline($img, 0, HEIGHT-1, WIDTH-1, 0, IMG_COLOR_STYLED);     imagesetstyle($img, $dashed);     imagerectangle($img, 30, 30, WIDTH-31, HEIGHT-31, IMG_COLOR_STYLED);     imagerectangle($img, 50, 50, WIDTH-51, HEIGHT-51, $black);     header("Content-Type: image/png");     imagepng($img); ?> 

Figure 27.9. Using GD brush styles.


As is shown both in the code found in Listing 27.9 and the image created by it in Figure 27.9, this script example makes use of two different styles represented by the arrays $sos (a famous Morse code signal) and $dashed (a simple dashed line). These two styles are then used to draw two lines (using the $sos style) and a rectangle (using the $dashed style). Note that in every case that a style was used, the style was first selected using the imagesetstyle() function, and then the IMG_COLOR_STYLED constant was used in place of a color to indicate each time the current style should be used in drawing.

As I have already stated, the imagesetstyle() function is used when defining simple brushes. For defining complex brushes that are multiple pixels in width, another method must be used, which involves the creation of another "brush" image using the imagesetbrush() function. The syntax for this function is as follows:

 imagesetbrush($img_r, $brush_r); 

$img_r is the image resource, and $brush_r is another (different) image resource containing the brush to use. This brush image resource is in no way different from any other image resource you have been exposed to, and it can be created using the entire range of GD image manipulation functions. As is the case with the imagesetstyle() function, the imagesetbrush() function must be called every time the brush is changed. As is also the case with imagesetstyle(), a special constant IMG_COLOR_BRUSHED must be used in place of the color anytime a GD drawing function that uses the brush is called. An example of using this function can be found in Listing 27.10:

Listing 27.10. Using the imagesetbrush() Function
 <?php     define("WIDTH", 200);     define("HEIGHT", 200);     define("B_WIDTH", 20);     define("B_HEIGHT",20);     $img = imagecreate(WIDTH, HEIGHT);     $background = $white = imagecolorallocate($img, 0xFF, 0xFF, 0xFF);     $black = imagecolorallocate($img, 0, 0, 0);     $brush = imagecreate(B_WIDTH, B_HEIGHT);     $b_bkgr = $b_white = imagecolorallocate($brush, 0xFF, 0xFF, 0xFF);     $b_black = imagecolorallocate($brush, 0, 0, 0);     imagecolortransparent($brush, $b_bkgr);     imageellipse($brush, B_WIDTH/2, B_HEIGHT/2, B_WIDTH/2, B_HEIGHT/2, $black);     imagerectangle($img, 0, 0, WIDTH-1, HEIGHT-1, $black);     imagesetbrush($img, $brush);     imageline($img, 0, HEIGHT-1, WIDTH-1, 0, IMG_COLOR_BRUSHED);     imageellipse($img, WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2, IMG_COLOR_BRUSHED);     header("Content-Type: image/png");     imagepng($img); ?> 

NOTE

When you use image brushes, if a color has been defined within it as the transparent color, it will not be drawn as part of the brush (transparency will be in effect). This can be used to create very complex and interesting brushes for use with borders and so on.


As shown previously, Listing 27.10 defines two separate images: $img (the actual image) and $brush (the brush image). For the brush, I have created a simple black circle with a transparent background. The $brush image is then selected as the brush that is used to draw a diagonal line and a circle using the special IMG_COLOR_BRUSHED color.

The resulting image in Figure 27.10 shows that for every pixel that would have been drawn without using a brush, a circle has instead been drawn. Because these circles overlap each other, the result is basically solid black. To correct this situation, brushes can also be combined with styles that dictate the interval at which the brush image is drawna "styled brush." This technique combines both the imagesetstyle() and imagesetbrush() functions to dictate the interval at which the brush will be used.

Figure 27.10. Using brush images in GD.


Unlike using the imagesetstyle() function in conjunction with the IMG_COLOR_STYLED special color, the actual values of the elements of the style array are mostly irrelevant. Specifically, values greater than zero will result in the brush image being used, whereas a value of zero effectively "turns off" the brush. When using styles and brushes together in a single drawing operation, the special color IMG_COLOR_STYLEDBRUSHED must be used. To illustrate this principal, Listing 27.11 draws a number of lines using different styles:

Listing 27.11. Using imagesetstyle() and imagesetbrush() Together
 <?php     define("WIDTH", 200);     define("HEIGHT", 200);     define("B_WIDTH", 20);     define("B_HEIGHT",20);     $img = imagecreate(WIDTH, HEIGHT);     $background = $white = imagecolorallocate($img, 0xFF, 0xFF, 0xFF);     $black = imagecolorallocate($img, 0, 0, 0);     $brush = imagecreate(B_WIDTH, B_HEIGHT);     $b_bkgr = $b_white = imagecolorallocate($brush, 0xFF, 0xFF, 0xFF);     $b_black = imagecolorallocate($brush, 0, 0, 0);     imagecolortransparent($brush, $b_bkgr);     imageellipse($brush, B_WIDTH/2, B_HEIGHT/2, B_WIDTH/2, B_HEIGHT/2, $black);     imagerectangle($img, 0, 0, WIDTH-1, HEIGHT-1, $black);     imagesetbrush($img, $brush);     $style_a = array_fill(0, B_WIDTH/2, 0);     $style_a[] = 1;     imagesetstyle($img, $style_a);     imageline($img, 0, 50, WIDTH-1, 50, IMG_COLOR_STYLEDBRUSHED);     $style_b = array_fill(0, B_WIDTH/4, 0);     $style_b[] = 1;     imagesetstyle($img, $style_b);     imageline($img, 0, 100, WIDTH-1, 100, IMG_COLOR_STYLEDBRUSHED);     $style_c = array_fill(0, B_WIDTH/8, 0);     $style_c[] = 1;     imagesetstyle($img, $style_c);     imageline($img, 0, 150, WIDTH-1, 150, IMG_COLOR_STYLEDBRUSHED);     header("Content-Type: image/png");     imagepng($img); ?> 

As indicated by the code in Listing 27.11 and the resulting image in Figure 27.11, three separate lines have been drawn on the canvas. Each of these lines uses the same brush; however, the style used has changed. The first of these styles places B_WIDTH/4 zeros (indicating no drawing of the brush) followed by a single 1 (indicating drawing of the brush). Each successive line uses a style with less space between the circles. These results are reflected in the image generated in Figure 27.11.

Figure 27.11. Using styled brushes.


NOTE

Unlike previous examples where I manually constructed the array used in the imagesetstyle() function in Listing 27.11, the array_fill() function was used instead. This was done both to show you another technique for creating style arrays and to clean up the example in general.


Using Custom Brushes for Filling

The GD extension also allows brushes to be used when you're filling in regions of the canvas. These regions may be defined by a geometric shape (when using imagefilledpolygon(), for example) or a more general-use filling function such as imagefill(). This filling pattern is called a tile and is defined by using the imagesettile() function with the following syntax:

 imagesettile($img_r, $tile_r); 

$img_r is the image resource to set the tile for, and $tile_r is another image resource defining the tile. Like brushes, tiles are represented as another image and can be loaded or manipulated using any of the GD graphics functions. After a tile has been designated as the current tile for the GD filling functions, it can be used by specifying the IMG_COLOR_TILED special color within any of the GD graphic functions that support filling. An example of tiles in use is shown in Listing 27.12:

Listing 27.12. Using imagesettile()
 <?php     define("WIDTH", 200);     define("HEIGHT", 200);     define("T_WIDTH", 20);     define("T_HEIGHT",20);     $img = imagecreate(WIDTH, HEIGHT);     $background = $white = imagecolorallocate($img, 0xFF, 0xFF, 0xFF);     $black = imagecolorallocate($img, 0, 0, 0);     $tile = imagecreate(T_WIDTH, T_HEIGHT);     $t_bkgr = $t_white = imagecolorallocate($tile, 0xFF, 0xFF, 0xFF);     $t_black = imagecolorallocate($tile, 0,0,0);     imagefilledrectangle($tile, 0, 0, T_WIDTH/2, T_HEIGHT/2, $t_black);     imagefilledrectangle($tile, T_WIDTH/2, T_HEIGHT/2,                          T_WIDTH-1, T_HEIGHT-1, $t_black);     imagerectangle($img, 0, 0, WIDTH-1, HEIGHT-1, $black);     imagesettile($img, $tile);     imagefilledrectangle($img, 1, 1, WIDTH-2, HEIGHT-2, IMG_COLOR_TILED);     header("Content-Type: image/png");     imagepng($img); ?> 

Figure 27.12. Using tiled fill colors in GD.




PHP 5 Unleashed
PHP 5 Unleashed
ISBN: 067232511X
EAN: 2147483647
Year: 2004
Pages: 257

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net