Fun With the PHP GD Library: Part 2

In part one of our “Fun with PHP GD series,” we went over what exactly the GD library is and the basics of using it. We also had a look at some neat tricks and using the built in GD image filters. Today, we are going to dive further into the GD library and take an in depth look at more cool effects we can achieve. Servers up, GD installed, text editor ready, let’s go!

Download the Source Code

For the examples below, we will start off simple and get more advanced as we go on, eventually landing on a really neat gradient function! Most of the code will be well documented for easy understanding and then further discussed under the snippet. Feel free to use any of these in your personal projects.

Our Image Subject

We can’t edit or alter any image until we have an image to work with. Meet and introduce yourself to our image subject:

Insane Kitten

1. Find Total Colors

I’ll keep to my promise of starting off very simple. Let’s say that we want to find out the total number of colors in any given image. We could analyze each pixel in a methodical manner and store the results for further analyzation, but that is tedious and boring. We want to do things the lazy developer way, by using the tools we already have available to us. Introducing, the imagecolorstotal() function.

// Create image instance
$im = imagecreatefromgif('PHP.gif');
 
echo 'Total colors in image: ' . imagecolorstotal($im);//Bam! I told you it was easy fool!
 
// Free image
imagedestroy($im);

Simple enough and moving right along…

2. Emboss that kitty!

This is one that I forgot to mention in part one, and it definitely warrants a mention here. Embossing seems to be something that anyone who has PhotoShop seems to be able to do, to the dismay of many talented web designers. How many people can say they can emboss an image using only PHP and the original image? You can, that’s who! Remember our sweet and cute little imagefilter function. We can pass emboss to that function and see what we get.

header('content-type: image/jpeg');
$image = imagecreatefromjpeg('guido_the_kitten.jpg');
imagefilter($image, IMG_FILTER_EMBOSS);//You've just been embossed!
imagejpeg($image, '', 90);
imagedestroy($image);
Embossed Kitty

So, it’s, um, pretty huh? Ok, ok, it’s not the prettiest thing in the world, but it is a basic and relatively fast emboss. For those of you who feel a little more comfortable with PHP and some math, you can check out the imageconvultion function, which will give you much more control of the output. Want a quick demo with the kitty? Ok!

$image = imagecreatefromjpeg('guido_the_kitten.jpg');
$emboss = array(array(4, 0, 0), array(0, -2, 0), array(0, 0, -2));
imageconvolution($image, $emboss, 1, 200);
 
header('Content-Type: image/jpeg');
imagejpeg($image, null, 100);
Kitty Convolution

With more tweaking we can drastically change the results. Image convolution is a very in depth topic and discussion, so I won’t have time to go into the details of it in this article. If you are interested in working with programming languages and images, be sure to google image convolution!

3. Watermark that cat!

Now, we don’t just want people downloading pictures of our cute little kitty and claiming it as their own, so we need to protect the image. One way to discourage image theft is to watermark the image on the server side. This will require a few things. One, we will need a source image, which is our kitten. Next, we need a watermark image, I have chosen a simple transparent .gif with some ThemeForest text as the image. Lastly, we need to merge the watermark onto the image. In addition, we want to be able to specify the opacity as well as the padding and position of the watermark, relative to the image. Sound like a lot of work? It’s not!

ini_set("display_errors", "1");
error_reporting(E_ALL); 
 
//Set up some basic variables and locations 
$image_src = 'guido_the_kitten.jpg';
$watermark_src = 'watermark.gif';
$opacity = 30;
$padding = 20;
 
//Load our images 
$image = imagecreatefromjpeg($image_src);
$watermark = imagecreatefromgif($watermark_src);
 
//Grab and store the height and width of our images 
list($image_width, $image_height) = getimagesize($image_src);
list($watermark_width, $watermark_height) = getimagesize($watermark_src);
 
//Set the final location of our watermark depending on the padding and size 
$final_x = $image_width - $watermark_width - $padding;
$final_y = $image_height - $watermark_height - $padding;
 
//Copy our watermark onto the original image 
imagecopymerge($image, $watermark, $final_x, $final_y, 0, 0, $watermark_width, $watermark_height, $opacity);
 
//Set headers, print image, clear memory 
header("Content-type: image/jpeg");
imagejpeg($image, null, 100);
imagedestroy($image);
imagedestroy($watermark);

Explanation:

  • Setup some basic variables and image locations, such as our watermark and original image source.
  • Set the desired opacity and padding levels for our watermark. This could come from user input if you had some code setup to accept it.
  • Load the images into stream with the imagecreatefrom* functions.
  • Store the width and height of our image and watermark into some variables. Notice how the use of the list function allows us to cut back on the amount of code needed. This is because getimagesize returns an array which we can assign in one line with list.
  • Do some basic calculations to figure out the position of our watermark.
  • Copy the watermark onto the image with all of the preferences we have previously setup.
  • Set the header, output the new image, clear up the memory.

Notice how we passed null to the imagejpeg function as the second parameter. This is because, in this example, we are simply outputting the watermarked image instead of saving it. If we wanted to save it, we could replace that parameter with the new thumbnail name (more on saving new images later in this article). And thats all there is to it, we should end up with an image like below:

Watermarked Cat

4. Play him off thumbnail cat!

Ok, so up until now we have played around, had some fun, and performed some cool effects onto our image. What about the very commonly requested ‘thumbnail scripts’. How do we turn this kitten into a smaller thumbnail, while maintaning aspect ratio? Let’s take a look at the final code for creating a custom thumbnail, and then we will walk through it step by step.

 
ini_set("display_errors", "1");
error_reporting(E_ALL); 
 
$img_src = 'guido_the_kitten.jpg';
//Desired thumbnail width 
$width = 125;
 
//Ensure the image exists
if(file_exists($img_src)){
	//Create image stream 
	$image = imagecreatefromjpeg($img_src);
 
	//Gather and store the width and height
	list($image_width, $image_height) = getimagesize($img_src);
 
	//Calculate new height while maintaining aspect ratio 
	$height = (($width / $image_width) * $image_height);
 
	//Resample/resize the image 
	$tmp_img = imagecreatetruecolor($width, $height);
	imagecopyresampled($tmp_img, $image, 0, 0, 0, 0, $width, $height, $image_width, $image_height);
 
	//set header and output image 
	header('Content-type: image/jpeg');
	imagejpeg($tmp_img, null, 100);
 
	//Free memory 
	imagedestroy($tmp_img);
	imagedestroy($image);
}
else {
	echo 'File not found!';
}

Explanation:

  • As always, turn on error reporting for debugging purposes and declare some basic variables such as our image source and desired thumbnail width (125 pixels).
  • Check to ensure the file exists on the server, or echo an error.
  • Start our image stream using imagecreatefromjpeg
  • We store the width and height of the image in the appropriate variables.
  • Calculate the new height based on the new width while maintaining aspect ratio. We divide the desired width by the original image width, and then multiply this by the image height to get our new height.
  • Resample and resize the image, should be self explanatory with the functions above.
  • Set the header, output the new thumbnail image, clear up the memory. Voila!

Assuming the file is found and all went well, you should end up with a thumbnail like so:

Kitten Thumbnail

So, this works great at outputting thumbnails directly to the browser from the script, but what about saving thumbnails? How do we accomplish this?

5. Save that thumbnail!

Saving our new thumbnail requires a slight modification to our original code, enough so that I think it is best if we go over how to accomplish this step by step also. Basically, instead of outputting it to the browser, we want to save it with a desired file name on our server for later use. Code below.

 
	ini_set("display_errors", "1");
error_reporting(E_ALL); 
 
$img_src = 'guido_the_kitten.jpg';
//Desired thumbnail width 
$width = 125;
//Thumbnail name 
$thumb = 'kitten_thumbnail.jpg';
 
//Ensure the image exists
if(file_exists($img_src)){
	//Create image stream 
	$image = imagecreatefromjpeg($img_src);
 
	//Gather and store the width and height
	list($image_width, $image_height) = getimagesize($img_src);
 
	//Calculate new height while maintaining aspect ratio 
	$height = (($width / $image_width) * $image_height);
 
	//Resample/resize the image 
	$tmp_img = imagecreatetruecolor($width, $height);
	imagecopyresampled($tmp_img, $image, 0, 0, 0, 0, $width, $height, $image_width, $image_height);
 
	//Attempt to save the new thumbnail 
	if(is_writeable(dirname($thumb))){
		imagejpeg($tmp_img, $thumb, 100);
		echo 'Thumbnail saved as ' , $thumb;
	}
	else {
		echo 'Unable to save thumbnail, please check file and directory permissions.';
	}
 
	//clear memory 
	imagedestroy($tmp_img);
	imagedestroy($image);
}
else {
	echo 'File not found!';
}

Most of the code above should look familiar to the original thumbnail script. Notice we have also defined the desired thumbnail name towards the top of our script. The real work is done where we ‘Attempt to save the new thumbnail’. Basically, we check to make sure we have correct permissions to save the thumbnail. If we do, we save the image as ‘kitten_thumbnail.jpg’ and echo a success message. Go ahead and check your server afterwards, you should see that the thumbnail has been saved!

A fun bonus!

For the last script/snippet of this article, I would like to share with you the only script I didn’t personally write from scratch, this one comes from my buddy on the popular CodingForums. The script is a cool little PHP gradient script, that will return the colors for a full gradient, including the steps (length) from one hex color to another. The original can be found here if you’re interested. I have cleaned up the code some, added documentation and some basic explanation, and shown you some very basic sample usage at the bottom. Check it out first:

 
/**
 *Gradient function by http://codingforums.com/showthread.PHP?t=79463 Much thanks to user "Jak-s".
 *Documentation added by Drew Douglass
 *
 *@param string $hexstart is the hex color to start at 
 *@param string $hexend is the hex color to end at 
 *@param int steps is the number of steps (or length) of the gradient 
 *@return array $gradient returns an array of all the color values 
 *
 *See bottom for usage. 
 */
ini_set("display_errors", "1");
error_reporting(E_ALL); 
 
function gradient($hexstart, $hexend, $steps) {
 
	//Find the start red, green, and blue values
	//See http://us2.PHP.net/manual/en/function.hexdec.PHP for more info 
    $start['r'] = hexdec(substr($hexstart, 0, 2));
    $start['g'] = hexdec(substr($hexstart, 2, 2));
    $start['b'] = hexdec(substr($hexstart, 4, 2));
 
	//Find the end of the red, green, and blue values
    $end['r'] = hexdec(substr($hexend, 0, 2));
    $end['g'] = hexdec(substr($hexend, 2, 2));
    $end['b'] = hexdec(substr($hexend, 4, 2));
 
    //Calculate steps for each color value 
    $step['r'] = ($start['r'] - $end['r']) / ($steps - 1);
    $step['g'] = ($start['g'] - $end['g']) / ($steps - 1);
    $step['b'] = ($start['b'] - $end['b']) / ($steps - 1);
 
    $gradient = array();
 
    ///Loop through each color depending on steps 
    for($i = 0; $i <= $steps; $i++) {
 
        $rgb['r'] = floor($start['r'] - ($step['r'] * $i));
        $rgb['g'] = floor($start['g'] - ($step['g'] * $i));
        $rgb['b'] = floor($start['b'] - ($step['b'] * $i));
 
        $hex['r'] = sprintf('%02x', ($rgb['r']));
        $hex['g'] = sprintf('%02x', ($rgb['g']));
        $hex['b'] = sprintf('%02x', ($rgb['b']));
 
        $gradient[] = implode(NULL, $hex);
 
    }
 
    return $gradient;
 
}
 
/**
  *Example usage with a LOT of divs
  *Dont you ever do this on a clients website ;-) 
  */
$gradient = gradient('4096EE', 'C3D9FF', 50);
 
foreach($gradient as $color){
	echo '<div style="background-color:'.$color.';">&nbsp;</div>';
}
Gradient Demo

Go ahead and run it in your browse, it’s fun, I promise! The code is a little much to explain step by step, so I have gone ahead and added plenty of documentation within the code for you to read and have fun with. Of course, using this to fill with a bunch of divs is just a silly example, but you could use the arrays returned by the function to do all kinds of cool backend work with gradients. Perhaps in part three we should cover this?

Final Thoughts.

Hopefully, after our two part series you have become more aware of what is possible with the GD library, and you have also learned how to accomplish some neat tricks. I’d like to hear from all of you. What do you find most interesting? Would you like a part 3? Is there an effect or image trick I didn’t mention that you would like to know how to accomplish? Let me know in the comments below! Special thanks to my neighbor’s kitten for being such a good sport.

Download the Source Code


21

Comments