ost likely, the first time you heard about image filters was when you had to edit your vacation pictures to remove the “red eye” effect or an undesirable face. For such basic purposes, a little practice and some specialized software such as Adobe Photoshop or Paint Shop Pro is sufficient to end up with great pictures. But if you want to go beyond the basics you need to understand what a picture actually is, what the main algorithms dedicated to image processing are, and how a programming language, as PHP per example, can help you. Images are wonderfully malleable, and after you understand those points, you can develop your own custom image filters with PHP. This article covers:
- Introduction to the GD library, which provides PHP support for image processing
- Creating custom image filters by modifying pixel colors
- Implementing the “convolution” technique
- Creating custom image filters by modifying pixel positions
Author’s Note: All the examples apply filters to the JPG image (tree.jpg) shown in Figure 1. |
![]() | |
Figure 1. Tree at Sunrise: This single image is used as the example for all the different image filters you’ll see in this article. |
Introduction to the GD Library
If you are using PHP 4.3.0, or newer, then the GD library is already available; otherwise, you have to download it and install it manually. Because it’s is an extension you must activate it in php.ini by uncommenting the following line (just delete the leading semicolon):
;extension=php_gd2.dll
Author’s Note: After making the modification you must restart the web server. |
To see the GD library version you may use this short PHP script:
After enabling GD support, if you look at the GD section of php.ini you should see something like Figure 2.
![]() | |
Figure 2. The GD Library Version: Here’s how the GD section of php.ini should look with GD support enabled. |
Creating and Destroying Images in PHP
The main PHP functions for creating an image are:
- resource imagecreate(int $width, int $height): This function returns a blank image that supports only 256 colors. The two arguments represent the width and height of the image.
- resource imagecreatetruecolor(int $width, int $height): This function returns a blank image that supports any number of colors. The two arguments represent the width and height of the image.
To destroy an image use the following function:
- bool imagedestroy(resource $image): This function frees the memory used by the image.
Assigning Pixel Colors
To assign a specific color to a pixel, use the RGBA color model and the following PHP functions:
- int imagecolorallocate(resource $image, int $red, int $green, int $blue): This function returns a color identifier representing the color composed of the given RGB components.
- int imagecolorallocatealpha (resource $image, int $red, int $green, int $blue, int $alpha): This function behaves like imagecolorallocate, but also specifies a transparency (alpha) parameter.
To de-allocate a color previously allocated with one of the functions described above, use this function:
bool imagecolordeallocate (resource $image, int $color)
Creating Images
A set of PHP functions lets you create new images from a source image, which is useful when you want to modify an existing image. The functions create image identifiers from GIF, JPEG, and PNG images:
- resource imagecreatefromgif(string $filename): This function returns an image identifier representing the GIF image obtained from the given file.
- resource imagecreatefromjpeg(string $filename)
- resource imagecreatefrompng(string $filename)
Saving Images
You can save images into a file or send them directly to a browser by using the following GD functions:
- bool imagejpeg(resource $image [, string $filename [, int $quality ]]): This function outputs or saves the given JPEG image.
- bool imagepng (resource $image [, string $filename [, int $quality [, int $filters ]]])
- bool imagegif (resource $image [, string $filename ])
For sending images directly to browser you have to set the “Content-type” header as shown in the following example (for GIFs, PNGs, or other formats just place the right MIME type as the value of the header):
//EXAMPLE header("Content-type: image/jpeg"); imagejpeg($image);
Getting Image Dimensions
For determine the width and height of an image you can use one of these functions:
- int imagesx (resource $image): This function returns the width of the given image resource.
- int imagesy (resource $image): This function returns the height of the given image resource.
- array getimagesize (string $filename [, array &$imageinfo ]): This function returns an array that contains a set of image parameters. Index 0 stores the width, index 1 stores the height and the rest of indexes contain other parameters.
Copying Portions of Images
To copy only a portion (sub-rectangle) of an image, use the imagecopy function. Its prototype is:
- bool imagecopy (resource $dst_im, resource $src_im, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_w, int $src_h): This function copies a piece from $src_im image into $dst_im image starting at the $src_x and $src_y coordinates, and with $src_w width and $src_h height. It places the copied portion at the $dst_x and $dst_y coordinates.
Color Bitwise Operations
The right-shift (>>) and OR (|) bitwise operators play an important role in color representation. For example, as you probably know, a color can be represented by a 32-bit integer; each color component uses a specific number of bits—eight bits in the default color model (RGBA). The following example creates the pure red color A=255,R=255,G=0,B=0 by using the right-shift operator to set the bits for each color component and then using the OR operator to combine the color components to represent the final color.
For example, to form a pure red color, you set the color by shifting the alpha value (255) by 24 positions, the red value (255) by 16 positions, the green value (0) by 8 positions, and the blue value (0) by 0 positions:
![]() | |
Figure 3. Seeing Red: Here’s the sequence of bitwise operations to create a pure red color, showing the RGB color components of an integer. |
A=A>>24 R=R>>16 G=G>>8 B=B>>0
Figure 3 shows the operation.
You can also use the bit operators to extract the individual RGB values for a given color. In the following example, the imagecolorat function returns the color of a pixel, and the bit shift operations extract the individual RGB values:
// Listing rgb.php > 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; echo " r= ".$r." g= ".$g." b= ".$b; ?>
![]() | |
Figure 4. The Green Band: After removing the red and blue bands of the tree.jpg picture, the image appears in shades of green. |
In a larger version of the same technique you can extract the color bands of an entire image. The following code extracts the red, green and blue color bands by looping through each pixel, retrieving the color value for that pixel, and then extracting the various color components. The code to get and assign the red and blue bands is commented out, so the resulting image shows only the green band (see Figure 4):
// Listing RGBbands.php > 16) & 0xFF; //$red = imagecolorallocate($im, $r, 0, 0); //imagesetpixel($im, $i, $j, $red); $g = ($rgb >> 8) & 0xFF; $green = imagecolorallocate($im, 0, $g, 0); imagesetpixel($im, $i, $j, $green); //$b = $rgb & 0xFF; //$blue = imagecolorallocate($im, 0, 0, $b); //imagesetpixel($im, $i, $j, $blue); } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Similarly, you can extract the red or blue bands by un-commenting the appropriate section of code in the preceding example.
Using the bitwise operators and playing around with pixel colors you can obtain great filters with only a few lines of code. To give you a sense of the possibilities, the rest of this article discusses and shows the code for many different filters, all of which are fairly simple to create and apply. Some of these filters alter color while some alter other properties such as brightness or contrast. Finally, you’ll see some built-in filters that can perform embossing, edge-smoothing, and other filtering operations.
Color-Altering Filters
All the filters in this group work by altering colors. Each filter applies a specific operation to all or a subset of the image pixels, resulting in an entirely new and often quite different image from the original.
Grayscale Filter
By removing all the color values and replacing them with shades of gray, you can create nice-looking black and white images (see Figure 5).
![]() | |
Figure 5. Grayscale Filter: The grayscale filter removes color from images. |
// Listing grayscale_filter.php > 16; $g = $rgb&0x0000FF00; $g = $g >> 8; $b = $rgb&0x0000FF; // calculate the grayscale $bw=($r+$g+$b)/3; $result = (0x000000FF<<24)|($bw<<16)|($bw<<8)|$bw; // create the new color values $new_r = ($result >> 16) & 0xFF; $new_g = ($result >> 8) & 0xFF; $new_b = $result & 0xFF; // assign the grayscale color $new_color = imagecolorallocate($im, $new_r, $new_g, $new_b); imagesetpixel($im, $i, $j, $new_color); } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Negate Filter
![]() | |
Figure 6. Negate Filter: This filter reverses, or negates the colors in an image. |
This application creates a “negate” filter (see Figure 6) by applying an exclusive OR operation to the red, green, and blue portions of the color while leaving the alpha channel intact:
// Listing negate_filter.php > 16) & 0xFF; $new_g = ($result >> 8) & 0xFF; $new_b = $result & 0xFF; $new_color = imagecolorallocate($im, $new_r, $new_g, $new_b); imagesetpixel($im, $i, $j, $new_color); } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Flea Filter
![]() | |
Figure 7. Flea Filter: An interesting colorization effect, this filter works by OR’ing the existing colors in an image with a random color. |
A flea filter is a random color value OR’d with the existing color values in an image. It produces a colorful and interesting effect (see Figure 7):
// Listing flea_filter.php
Fog Filter
![]() | |
Figure 8. Fog Filter: By using the alpha channel value (which requires the PNG format instead of JPG), this filter applies a fog-like film to an image. |
As the name implies, a fog filter applies a hazy film over an image (see Figure 8). Note that in this case you have to covert the tree.jpg file to a Portable Network Graphics (PNG) file (tree.png) before beginning the operation, because images in PNG format can use alpha channel values while images in JPEG format do not.
// Listing fog_filter.php > 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; //Turn off transparency blending imagealphablending($im, false); //Create a new transparent color for image $color = imagecolorallocatealpha($im, $r, $g, $b, 100); //Set the new color imagesetpixel($im, $i, $j, $color); //Restore transparency blending imagesavealpha($im, true); } } header('content-type: image/png'); imagepng($im); ?>
Dark Filter
![]() | |
Figure 9. Dark Filter: This filter reduces all RGB values by a predetermined amount. |
You can darken an image by using a dark filter, which reduces all the RGB values by some specified fractional amount (see Figure 9):
// Listing dark_filter.php > 16; $g = $rgb&0x0000FF00; $g = $g >> 8; $b = $rgb&0x0000FF; $frac = 0.5; // 0.0 < frac < 1.0 $rr = (int)($r*$frac); $gg = (int)($g*$frac); $bb = (int)($b*$frac); $result = (0x000000FF<<24)| ($rr <<16)|($gg << 8)|$bb; $new_r = ($result >> 16) & 0xFF; $new_g = ($result >> 8) & 0xFF; $new_b = $result & 0xFF; $new_color = imagecolorallocate( $im, $new_r, $new_g, $new_b); imagesetpixel($im, $i, $j, $new_color); } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Black Filter
![]() | |
Figure 10. Black Filter: Increasing the amount of black in an image doesn’t simply darken it, it alters the effect. |
This application uses a filter that increases the black color in an image by choosing a random threshold value between 0 and 255, and then setting all the pixels where the R, G, and B values exceed that threshold to black (0, 0, 0). Note that this operates primarily on the darker-colored pixels in the image (see Figure 10):
// Listing strong_filter.php > 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $profile = rand(0,255); if(($r<$profile)&&($g<$profile)&& ($b<$profile)) { $new_color = imagecolorallocate( $im, 0, 0, 0); imagesetpixel($im, $i, $j, $new_color); } } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Black-Removal Filter
![]() | |
Figure 11. Snow Filter: Increasing the amount of white in an image functions as a “snow” filter. |
The reverse of a black filter takes dark pixels and changes them to another color—white in this example—creating a “snow” filter (see Figure 11):
// Listing black_removal_filter.php > 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; if(($r<50)&&($g<50)&&($b<50)) { $color = imagecolorallocate( $im, $red, $green, $blue); imagesetpixel($im, $i, $j, $color); } } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Shading Filter
![]() | |
Figure 12. Shading Filter: AND’ing a specific color with the existing colors in an image produces a color-shading effect. |
You can display an image in shades of a specific color using this filter by AND’ing the existing color with the filter-specific color. The example in Figure 12 uses a hard-coded orange hue, but you can use any color you like.
// Listing mixed_filter.php > 16) & 0xFF; $g = ($rgb >> 16) & 0xFF; $b = $rgb & 0xFF; $color = imagecolorallocate( $im, $red, $green, $blue); $result = $rgb & $color; imagesetpixel($im, $i, $j, $result); } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Paint Filter
![]() | |
Figure 13. Paint Filter: The Paint Filter provides an unusual “hand-painted” effect. |
Here’s a slightly more complex filter that “paints” a picture (see Figure 13):
// Listing paint_filter.php > 16) & 0xFF; $green = ($rgb >> 16) & 0xFF; $blue = $rgb & 0xFF; $tR = $red; $tG = $green; $tB = $blue; $R = array(255,255,0,0,0, 255,255,0,64,128,192,255,255,-1); $G = array(0,255,0,255,0,255, 0,255,64,128,192,200,175,-1); $B = array(0,255,0,0,255,0, 255,255,64,128,192,0,175,-1); $R[13]=$red; $G[13]=$green; $B[13]=$blue; for($j=0;$j<13;$j++){ for($k=$j+1;$k<14;$k++) { if($R[$j]<$R[$k]){ $aux=$R[$j];$R[$j]=$R[$k];$R[$k]=$aux;} if($G[$j]<$G[$k]){ $aux=$G[$j];$G[$j]=$G[$k];$G[$k]=$aux;} if($B[$j]<$B[$k]){ $aux=$B[$j];$B[$j]=$B[$k];$B[$k]=$aux;} } } for($j=0;$j<14;$j++){ if(($R[$j]==$tR)&&($j==0)){$xR=$R[$j+1];break;} if(($R[$j]==$tR)&&($j==8)){$xR=$R[$j-1];break;} if(($R[$j]==$tR)&&($j!=0)&&($j!=8)){ $xR=min(($tR-$R[$j-1]),($R[$j+1]-$tR)); break; } } for($j=0;$j<14;$j++){ if(($G[$j]==$tG)&&($j==0)){$xG=$G[$j+1];break;} if(($G[$j]==$tG)&&($j==8)){$xG=$G[$j-1];break;} if(($G[$j]==$tG)&&($j!=0)&&($j!=8)){ $xG=min(($tG-$G[$j-1]),($G[$j+1]-$tG)); break; } } for($j=0;$j<14;$j++){ if(($B[$j]==$tB)&&($j==0)){$xB=$B[$j+1];break;} if(($B[$j]==$tB)&&($j==8)){$xB=$B[$j-1];break;} if(($B[$j]==$tB)&&($j!=0)&&($j!=8)){ $xB=min(($tB-$B[$j-1]),($B[$j+1]-$tB)); break; } } $color = imagecolorallocate( $im, abs($xR), abs($xG), abs($xB)); imagesetpixel($im, $i, $m, $color); } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Altering Brightness, Hue, and Saturation
The next three filters modify the brightness, saturation, and hue of an image. To do that, you need to be able to convert between the Red-Green-Blue and Hue-Saturation-Brightness (HSB) forms of color representation, for which you can use the conversion functions RGBtoHSB and HSBtoRGB. Both conversions are based on very common algorithms so I won’t describe them here, but Listing 1 shows the RGBtoHSB function code while Listing 2 shows the code for the HSBtoRGB function:
Brightness Filter
![]() | |
Figure 14. Bright Filter: To increase brightness, raise the HSB brightness component of the image’s pixels. |
As you might expect, the brightness filter can make a dark image lighter or a light image darker. Figure 14 shows an example. First, you change the RGB color value to an HSB value, and then change the brightness portion of the HSB value.
// Listing brightness.php > 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $getArrayHSB = RGBtoHSB($r,$g,$b); $brightness = 1.5; //[0.0, 1.0] - darker, [1.0, 10.0] - brightner $getArrayHSB[2] = $brightness*$getArrayHSB[2]; $getArrayHSB[2] = max(0.0,min($getArrayHSB[2],255.0)); $getArrayRGB = HSBtoRGB( $getArrayHSB[0], $getArrayHSB[1], $getArrayHSB[2]); $hsbrgb = imagecolorallocate( $im, $getArrayRGB[0], $getArrayRGB[1], $getArrayRGB[2]); $result = (($rgb & 0xff000000)|($hsbrgb)); imagesetpixel($im, $i, $j, $result); } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Saturation Filter
![]() | |
Figure 15. Saturation Filter: Increasing saturation increases the color depth across the entire image. |
Modifying the saturation of an image changes the amount of color in its pixels. Figure 15 shows the tree image with increased saturation.
// Listing saturation.php > 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $getArrayHSB = RGBtoHSB($r,$g,$b); $saturation = 9; //[0,10] $getArrayHSB[1] = $saturation*$getArrayHSB[1]; $getArrayHSB[1] = max(0.0,min($getArrayHSB[1],1.0)); $getArrayRGB = HSBtoRGB($getArrayHSB[0], $getArrayHSB[1],$getArrayHSB[2]); $hsbrgb = imagecolorallocate($im, $getArrayRGB[0], $getArrayRGB[1], $getArrayRGB[2]); $result = (($rgb & 0xff000000)|($hsbrgb)); imagesetpixel($im, $i, $j, $result); } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Hue Filter
![]() | |
Figure 16. Hue Filter: Changing hue moves the overall image colors toward a specific color band. |
Changing the hue is a similar operation, programmatically, but changes the overall color or “hue” of the image (see Figure 16):
// Listing hue.php > 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $getArrayHSB = RGBtoHSB($r,$g,$b); $hue = 3; //[0,10] $getArrayHSB[0] = $hue*$getArrayHSB[0]; $getArrayHSB[0] = max(0.0,min($getArrayHSB[0],360.0)); $getArrayRGB = HSBtoRGB($getArrayHSB[0], $getArrayHSB[1],$getArrayHSB[2]); $hsbrgb = imagecolorallocate($im, $getArrayRGB[0], $getArrayRGB[1], $getArrayRGB[2]); $result = (($rgb & 0xff000000)|($hsbrgb)); imagesetpixel($im, $i, $j, $result); } } header("Content-type: image/jpeg"); imagejpeg($im); ?>
Predefined filters in PHP
PHP (through the GD library) includes a reasonably-sized set of predefined filters, some of which provide the same functionality as filters you’ve already seen. You use the imagefilter function to apply different image filters as follows:
bool imagefilter(resource $image, int $filtertype [, int $arg1 [, int $arg2 [, int $arg3 [, int $arg4 ]]]])
The imagefilter function applies the given filter to the given image. The $filtertype argument can be one of the following values (taken from the official PHP manual). The optional arguments $arg1, $arg2 and so forth apply only to some of the filters:
- IMG_FILTER_NEGATE: Reverses all colors of the image.
- IMG_FILTER_GRAYSCALE: Converts the image into grayscale.
- IMG_FILTER_BRIGHTNESS: Changes the brightness of the image. Use arg1 to set the level of brightness.
- IMG_FILTER_CONTRAST: Changes the contrast of the image. Use arg1 to set the level of contrast.
- IMG_FILTER_COLORIZE: Like IMG_FILTER_GRAYSCALE, except that you can specify the color. Use arg1, arg2 and arg3 as the red, blue, and green values, and arg4 for the alpha channel. The range for each is 0 to 255.
- IMG_FILTER_EDGEDETECT: Uses edge detection to highlight the edges in the image.
- IMG_FILTER_EMBOSS: Embosses the image.
- IMG_FILTER_GAUSSIAN_BLUR: Blurs the image using the Gaussian method.
- IMG_FILTER_SELECTIVE_BLUR: Blurs the image.
- IMG_FILTER_MEAN_REMOVAL: Uses mean removal to achieve a “sketchy” effect.
- IMG_FILTER_SMOOTH: Makes the image smoother. Use arg1 to set the level of smoothness.
I won’t show an example of each type, but here are three short representative applications that use the imagefilter() function to apply some of the filters: the Emboss Filter (see Figure 17), the Negate Filter (see Figure 18), which duplicates the Negate Filter results you saw earlier, and the Smooth Filter (see Figure 19), which smooths the edges in an image:
Emboss Filter
![]() | |
Figure 17. Emboss Filter: By enhancing edges and shadows, this filter produces an embossed 3D look. |
// Listing embossPredefFilter.php
Negate Filter
![]() | |
Figure 18. Negate Filter: This built-in filter functions identically to the custom Negate Filter. |
//Listing negatePredefFilter.php
Smooth Filter
![]() | |
Figure 19. Smooth Filter: This filter smooths edges and corners to soften an image. |
// Listing smoothPredefFilter.php
Developing Filters with the Convolution Technique
To implement filters such as embossing and blurring you use the “convolution” technique—a mathematical operation that replaces the value of a pixel with the well-balanced sum of the values that surround that pixel. The advantage of understanding how to create these filters is that you can use the knowledge to personalize the filters exactly as you need. Some of the predefined filters don’t offer you sufficient control to achieve special effects.
The convolution technique uses a matrix, known as the “mask of convolution” or “kernel.” Most kernels have 3×3 elements, but that’s not a hard-and-fast rule. Here’s the general equation that describes the convolution technique:
The equation contains the following notations:
- Id—Image destination (this image is the result of the filter)
- Is—Image source (this image supports the filter)
- a,b—Represents the coordinates of the central pixel
- K—Represents the kernel
![]() | |
Figure 20. Applying a 3×3 Matrix Convolution: Matrix convolutions work by averaging pixel colors with those of surrounding pixels using this process. |
The convolution technique takes pixels from left to right and from top to bottom. The convolution will fill the boundary of the image with zero values or it will leave them unchanged. Figure 20 illustrates how the convolution processes image pixels.
You use different kernels for different effects. Here’s a list showing the most common 3×3 kernels:
Blur kernel
Edge detection kernel
Sharpen kernel
Emboss kernel
Here are two applications that use the convolution technique. The first application implements an emboss filter (see Listing 3 and Figure 21), and the second, in Listing 4, implements a sharpen filter (see Figure 22). Note how this customized emboss filter differs from the built-in emboss filter shown in Figure 17—and that you can’t achieve this precise effects using the built-in filter. The sharpen filter provides a much-needed addition to the built-in filter effects.
|
|
Moving Chunks of Pixels
![]() | |
Figure 23. Puzzle Filter: Using the imagecopy function, you can move chunks of an image from one location to another. |
You’ve seen examples of creating image filters that work by modifying pixel color, hue, saturation, etc., or by using a matrix to determine a pixel’s value based on adjacent pixels. You can also create filters by moving pixels from one place to another without changing their values, which results in some interesting effects. For example, suppose that you want to develop a puzzle game using images provided by players. To do that, you have to implement an image filter that cuts any image into random puzzle pieces. This application shown in Listing 5 does exactly that, using the imagecopy function described near the beginning of this article:
By this time, you should have a good grasp of the underlying operations that create image filters and how you can develop customized versions in PHP. PHP offers good support for image processing, including several useful built-in filters—and as you have probably noticed—makes it very easy to extend modules by writing new filters from scratch.