Manipulating images is a tool that more and more web programmers are having to add to their repertoire due to the growth of Web 2.0 and the requirement to make sites more social with thumbnails, avatars and so on.
author : cahya dsn
,
published on : March 3rd, 2014
updated on : April 10th, 2014
Using just a web server and the PHP scripting language, it's easy to build a simple image editor with many of the features of top photo editing packages.
Manipulating images is a tool that more and more web programmers are having to add to their repertoire due to the growth of Web 2.0 and the requirement to make sites more social with thumbnails, avatars and so on.
Websites for freelancers, for example, often need to support image uploads of photos of the freelancers themselves as well as of their work. Likewise auction, classifieds and other sites that sell products on behalf of the surfer need a way to accept an upload of the products for sale.
But it's not sufficient to simply support http file upload, because images will be posted to you of all sizes and dimensions. Many of the latest digital cameras offer in excess of ten megapixels and the default file sizes are very high resolution (thousands by thousands of pixels) and take up several megabytes of space.
Therefore you need to be able to take uploaded images and resize them to suitable dimensions for the website in question, and also save them in the file format of your choice. Along the way you may well need to either offer your users the opportunity to adjust the final image, or automatically do so yourself. This is particularly necessary when you have resized an image down substantially to a thumbnail, as you will almost certainly have to sharpen it.
Before you start, though, you must ensure that your web (or development) server has the GD Lib compiled into PHP as that is the only way these functions will work.
For the purposes of this article I have limited the supported file types to GIF, PNG and JPG. In practice you will probably find these three are sufficient for most purposes anyway.
The following code snippet is the first part of the complete program file which should be saved as picproc.php. It contains the opening code to tell the web server to process PHP, and then the main html used by the program is output:
<?php echo <<<_END <font face='Courier New' size='4'><pre> <ul> <b><u>PHP PICTURE PROCESSOR</u> <form method='post' action='picproc.php' enctype='multipart/form-data'> UPLOAD : <input type='file' name='p' size='1'> ACTION : <select name='a'> <option value=0>No Action <option value=1>Sharpen <option value=2>Blur <option value=3>Brighten <option value=4>Darken <option value=5>More Contrast <option value=6>Less Contrast <option value=7>Greyscale <option value=8>Invert <option value=9>Reder <option value=10>Greener <option value=11>Bluer <option value=12>Edge Detect <option value=13>Emboss <option value=14>Sketchify </select> RESIZE : W <input type='text' name='w' size='1'> H <input type='text' name='h' size='1'> <input type='submit'></form></pre> </ul> _END;
Working through this code sequentially, what it does is start off by setting the font face to a suitable sized monospaced one to aid with simple formatting. Then the <pre> and <ul> tags are issued to force all following output to appear exactly as shown and indented from the left margin. Then a heading is printed.
After this single-line page set up we get to the nitty gritty code where a form is started which will send its input as multipart data to picproc.php (the file itself).
Next the inputs are defined which include the file to be sent (a browse button will automatically appear when the program is run), and the action to perform. This includes 14 items, whose actions you can tell from the code.
Finally an option to also resize the uploaded file is given by offering the input of two fields, W and H for width and height. Then, once it's all done, the submit button is added and the form is closed.
The above code displays the html form required to upload an image, perform one of 14 actions on it and/or resize the image. So you have a few things to do once the image arrives at the server, the first of which is to populate the variables you will be using:
$p = $_FILES['p']['name']; $a = $_POST['a']; $w = $_POST['w']; $h = $_POST['h']; $t = "pic.jpg"; $rn = rand(0, 65535);
If a file has been uploaded, $p will be the file's contents. $a will be the action to perform on the file or "No action" if it is set to 0. If set, $w and $h contain the new width and height to apply to the image. $t is a simple string variable containing the name of the file as saved to the server, while $rn is a random number whose use you will see later.
But the variable that concerns you immediately is $p because, if it is set, an image has been uploaded and you must deal with it as below:
if ($p) { move_uploaded_file($_FILES['p']['tmp_name'], $t); switch($_FILES['p']['type']) { case "image/gif": $s = imagecreatefromgif($t); break; case "image/jpeg": $s = imagecreatefromjpeg($t); break; case "image/png": $s = imagecreatefrompng($t); break; } @imagejpeg($s, $t); } else $s = @imagecreatefromjpeg($t);
The first thing to do after detecting that an image was uploaded is to save it as a file on the server using the value stored in $t ("pic.jpg"). The reason the .jpg extension is used here is because that is the format the image will be saved as for our internal use.
To ensure this, the next few lines of code determine the type of image that was actually uploaded and then convert from that format to the PHP internal image format, before then re-saving the image as a JPG file. Note that there is no error checking here for any other mime types being uploaded. That is beyond the scope of this article and something you will need to take into account.
Anyway, on exit from this routine there is an else statement which will run if no image was uploaded. If this is the case, an attempt is made to load in a previously saved image for further manipulation. This is because you don't want to keep re-uploading the main image to try different effects unless you wish to revert to the original one.
Note the use of the @ sign prefixed to the function call. This suppresses any error messages if no image has been uploaded yet. Because there is no room in this tutorial to build in all the possible error checking you might need, this technique has been used in many places to ensure the program output is clean. If you intend other people to use any of this code you should first remove all the @ signs in order to catch error messages and decide how to handle them.
At this point you should now have an original image stored on the server as pic.jpg, and loaded into PHP's image workspace, ready to manipulate with the code below:
switch($a) { case 1: @imageconvolution($s, array(array(-1, -1, -1), array(-1, 16, -1), array(-1, -1, -1)), 8, 0); break; case 2: @imagefilter($s, IMG_FILTER_GAUSSIAN_BLUR); break; case 3: @imagefilter($s, IMG_FILTER_BRIGHTNESS, 20); break; case 4: @imagefilter($s, IMG_FILTER_BRIGHTNESS, -20); break; case 5: @imagefilter($s, IMG_FILTER_CONTRAST, -20); break; case 6: @imagefilter($s, IMG_FILTER_CONTRAST, 20); break; case 7: @imagefilter($s, IMG_FILTER_GRAYSCALE); break; case 8: @imagefilter($s, IMG_FILTER_NEGATE); break; case 9: @imagefilter($s, IMG_FILTER_COLORIZE, 128, 0, 0, 50); break; case 10: @imagefilter($s, IMG_FILTER_COLORIZE, 0, 128, 0, 50); break; case 11: @imagefilter($s, IMG_FILTER_COLORIZE, 0, 0, 128, 50); break; case 12: @imagefilter($s, IMG_FILTER_EDGEDETECT); break; case 13: @imagefilter($s, IMG_FILTER_EMBOSS); break; case 14: @imagefilter($s, IMG_FILTER_MEAN_REMOVAL); break; }
As you can see, many of the actions supported by our program are implemented using the imagefilter() function. This is built into the GD library used by PHP and offers a wide range of transforms, of which this article only covers a few examples.
The function takes the image to be manipulated, and an integer filter type and parameters which are sometimes optional and sometimes mandatory, depending on the filter type.
As a basic start point I have chosen values for these actions that seem reasonable and which can be applied several times to achieve further changes. You may wish to experiment with the values to obtain results more to your liking. Further details are in the appendixes entitled "Using imagefilter() and imageconvolution()".
The one exception is the use of the imageconvolution() function to obtain a sharpening effect. This has been used as there is no sharpen filter type available for imagefilter(). There are many other effects you can achieve with this function so it is also worth investigating further.
Once execution of this code segment completes you should have an image in memory ready to save back to the server. But first, there's a final test to make because the user may have chosen to resize the image.
Simply dropping or adding vertical or horizontal lines to change an image's dimensions is very messy to say the least. To best resize an image it needs to be resampled so that, whether you are adding or removing data, it retains as much of its integrity as possible:
if ($w) { list($tw, $th) = getimagesize($t); $s1 = imagecreatetruecolor($w, $h); imagecopyresampled($s1, $s, 0, 0, 0, 0, $w, $h, $tw, $th); imagejpeg($s1, $t); imagedestroy($s1); } else @imagejpeg($s, $t); @imagedestroy($s);
To do this, the image's current dimensions are looked up and stored in $tw and $th. Then a new workspace is created in $s1 with the width and height specified in the input.
Given that data, the original image is then resampled to fill the new workspace and saved back to the server using the imagejpeg() function. To return temporary memory back to the server imagedestroy() is also called.
You'll notice that this code is only executed if $w has been defined. Again, this is a quick and dirty way to assume that a redimensioning is in order. No check is made to see whether $w is sensible, and whether $h even exists, so garbage inputs will return garbage results without suitable error checking being added.
Finally, you are ready to display the image if it exists:
@imagedestroy($s); if (file_exists($t)) echo "<img src=$t?rn=$rn>";
First the temporary workspace used for the image is returned to the server, then if the file pic.jpg exists on the server it is displayed using the html <img> tag.
And now you can see the purpose of the $rn random variable that was defined earlier. It is attached to the image URL in the form pic.jpg?rn=123 to ensure that the web browser downloads and displays the image directly from the server each time the program is run, rather than from its cache which is what it would otherwise do.
And if you string those segments together in sequence and save them as the program picproc.php, you will have a basic image editor in just a few lines of PHP. Using the program's structure, you should easily be able to add plenty of additional functionality and new features.
There are many ways you can improve this program. Obviously, the first of which has been covered and that is to provide adequate error checking. When receiving uploads to a public web server it's essential that you remove any possibility of being hacked and for users to create strange and unwanted results.
Features you could add include enlarging only parts of an image. For example you could use an image map of the picture as part of the input, and then the area surrounding the mouse click would be enlarged to fill the whole image. This is a technique often used to help users select thumbnails from larger images.
Or you could just take parts of the project, many of which are handy in their own right. For example you could write a function to automatically resize an uploaded image to no more than either 100 pixels wide or high, whichever is the larger (or any amount you choose), and then sharpen the result (because the resampling usually has a blurring effect on thumbnails). To get you started, the piece of code below will do just that for you:
$max = 100; $tw = $w; $th = $h; if ($w > $h && $max < $w) { $th = $max / $w * $h; $tw = $max; } elseif ($h > $w && $max < $h) { $tw = $max / $h * $w; $th = $max; } elseif ($max < $w) $tw = $th = $max;
Just set $max to your preferred value, and ensure $w and $h are the current width and height of your image. This code will then set $tw and $th to the correct proportional values required to ensure that, whether the image is portrait, landscape or square, the resulting thumbnail will be no greater than $max pixels in its largest dimension. Just insert this code into the appropriate place in the program file.
Or at the very least, if you've never used it before, you could just take the file upload section and make use of it when CVs, databases or other files need to be uploaded to your server.
The imagefilter() function provides a powerful set of ready-made transformations you can use on images. The format of the function call is:
imagefilter($image, filtertype [, $arg1, ... $arg4])
$image should be an image resource, there can be up to four arguments in $arg1 through $arg4, and filtertype can be any of the following:
Sometimes imagefilter() will not have the exact transform you require but that's OK because you can create your own using imageconvolution(). For example, the following two function calls in turn emboss and sharpen an image based on a three by three matrix, which is applied across the whole image. Try changing the parameters to see what effects you can create - here are some examples.
imageconvolution($image, array( array(2, 0, 0), array(0, -1, 0), array(0, 0, -1) ), 1, 127); imageconvolution($image, array( array(-1, -1, -1), array(-1, 16, -1), array(-1, -1, -1) ), 8, 0);
Everything you could want to know about the GD Image functions can be found on php.net.