8

I have recently been using a jQuery plugin called imgAreaSelect, which allows you to crop images. I wanted to use it with my PHP site so that thumbnails could be cropped and created.

GD Library is a PHP library that allows manipulation of images, in particular it can create new images.  It may need to be installed on some servers, but I found it already installed on my host and on MAMP (my local server). Combining this with imgAreaSelect and we can feed the coordinates that are cropped to create the new thumbnail.  So here’s how

Firstly, attach all the jQuery and plugin scripts in the head tags:

<head>
        <script type="text/javascript" src="js/jquery.min.js">
        </script>
        <script type="text/javascript" src="js/jquery.imgareaselect.js">
        </script>

Now still in the head tags, the plugin needs to be called, here I am pointing it to an image with an id of ‘crop’. I am also selecting the aspect ratio as 1:1 (to keep the thumbnail a square).

<script type='text/javascript'> 
    $(function () {
        $('#crop').imgAreaSelect({ aspectRatio: '1:1', 
onInit: preview, onSelectChange: preview });
    });

The other thing I have done here is called a function named ‘preview’ onInit (on initialisation, when the plugin is first loaded) and onSelectChange (whenever the crop area is changed). This preview function is created below and allows the thumbnail to be previewed live on the same page. It’s not 100% necessary but quite useful:

	function preview(img, selection) {
	    if (!selection.width || !selection.height)
	        return;
 
	    var scaleX = 100 / selection.width;
	    var scaleY = 100 / selection.height;
 
	    $('#preview img').css({
	        width: Math.round(scaleX * ".$width." ),
	        height: Math.round(scaleY * ".$height." ),
	        marginLeft: -Math.round(scaleX * selection.x1),
	        marginTop: -Math.round(scaleY * selection.y1)
	    });

If doing this preview function, you need to give it the width and height of the original image. I have done this by putting each in variables $width and height, using the getImageSize PHP function. This means that you have to echo the JavaScript after declaring the variables.

I have pointed the preview function to a img contained within an element that has the id: ‘preview’. So somewhere on my page I need to insert the following html:

<div id="preview">
<img src="image.jpg" />
<!--This is the same image file as what is being cropped, the javascript
we inserted before will resize it-->
</div>

Now the important part, we need to pass the selection into a form so when it’s submitted we can retrieve the coordinates from the $_POST array. So (continued straight after the code before, still in the head tags), we insert this:

    	$('#x1').val(selection.x1);
    	$('#y1').val(selection.y1);
    	$('#x2').val(selection.x2);
    	$('#y2').val(selection.y2);
    	$('#w').val(selection.width);
    	$('#h').val(selection.height);  
    }
    $(document).ready(function(){
        $('#saveThumb').click(function(){
            var x1 = $('#x1').val();
            var y1 = $('#y1').val();
            var x2 = $('#x2').val();
            var y2 = $('#y2').val();
            var w = $('#w').val();
            var h = $('#h').val();
            if (x1 == "" || y1 == "" || x2 == "" || y2 == "" || w == "" || h == "") {
                alert("You must make a selection first");
                return false;
            }
            else {
                return true;
            }
        });
    });
</script>
</head>

This also includes validation to insure an crop area has been selected.
Now this goes into the body of the page:

<img id='crop' src='image.jpg' />
<p><div id='preview'>
<img src='image.jpg' /></div>
<form name='uploadThumbnail' action='thispage.php' method='post'>
<input type='hidden' name='x1' value='' id='x1' />
<input type='hidden' name='y1' value='' id='y1' />
<input type='hidden' name='w' value='' id='w' />
<input type='hidden' name='h' value='' id='h' />
<input type='hidden' name='extension'  value='jpg' />
<input type='hidden' name='filename'  value='image.jpg' />
<input type='hidden' name='width'  value='$width' />
<input type='hidden' name='height'  value='$height' />
<input type='submit' name='uploadThumbnail' value='Save Thumbnail' id='saveThumb' />";

The image crop page is now complete, we use all these hidden fields to pass the details of the image to the next page, where we will use this data to resize the image correctly.
Here’s how I created the thumbnail using the gd library.

$thumbWidth = 100;
$thumbHeight = 100;
$newFilename = 'newfilename.jpg';
extract($_POST); // Extract the $x1, $y1, $w, $h, $extension, 
//$filename, $width, $height variables
 
//Now lets create the thumbnail
 
    // GD Function List
    $gdExtensions = array (
    'jpg'=>'JPEG',
    'gif'=>'GIF',
    'bmp'=>'WBMP',
    'png'=>'PNG'
    );
 
    $check = false;
 
    $gdExtension = $gdExtensions[$extension];
    $function_to_read = "ImageCreateFrom".$gdExtension;
    $function_to_write = "Image".$gdExtension
 
    // Read the source file
    $source_handle = $function_to_read($filename);
 
    if ($source)
    {
        // Create a blank image
        $destination_handle = ImageCreateTrueColor($thumbWidth, $thumbHeight);
 
        // Put the cropped area onto the blank image
        $check = ImageCopyResampled($destination_handle, $source_handle, 0, 0, $x1, $y1, $thumbWidth, $thumbHeight, $w, $h);
    }
 
    // Save the image
    $function_to_write($destination_handle, $newFilename);
    ImageDestroy($destination_handle);
 
    // Check for any errors
    if ($check)
    {
        echo "Thumbnail created";
    } else
    {
        echo "Thumbnail failed to create";
    }

So that should be thumbnail created, the important part of the PHP is the ImageCopyResampled($destination_handle, $source_handle, 0, 0, $x1, $y1, $thumbWidth, $thumbHeight, $w, $h); function, which writes to the image. The correct way to pass through the data from imgAreaSelect is the way shown here.

If you have enjoyed this entry. Please feel free to bookmark it using your favorite social bookmarking site

8 Responses so far

  1. Matt H says:

    Not sure if I missed it here…but is there somewhere which defines the $destination_handle and the $source_handle in your code or is that part of the GD library?

  2. admin says:

    $source_handle and $destination handle are variables that contain the return values of imagecreatefromjpeg (which can also be imagecreatefrompng, gif, etc.) and ImageCreateTrueColor function.

    Both of these functions are from gd library and return an image resource, which is then used in later gd library functions.

    Both variables are defined in the last part of the code.

    thanks

  3. Can I use this code in asp.net………….

  4. Jeff H says:

    I’m receiving the following errors on your last code:

    Warning: imagejpeg(): supplied argument is not a valid Image resource in /home/bathroo2/public_html/admin/crop_image.php on line 156

    Warning: imagedestroy(): supplied argument is not a valid Image resource in /home/bathroo2/public_html/admin/crop_image.php on line 157

  5. admin says:

    Having a quick look over the code I posted, there’s quite an obvious error:

    if ($source) should be changed to if ($source_handle)

    That should sort the problem.

    Thanks.

  6. Jeff H says:

    Oh wow, I can’t believe I didn’t see that! Alright, thanks, it works perfectly now. Also, after going through the code, there needs to be a semicolon after:

    $function_to_write = “Image”.$gdExtension

    Nothing big, just thought I should point that out.

  7. Cute animals says:

    Hi,

    Thanks for the article, it was helpful. The only thing I’d like to mention is that these two lines are not used in the code and could be removed:

    $(’#x2′).val(selection.x2);
    $(’#y2′).val(selection.y2);

    Thank you once more.

  8. phpfreak says:

    Today I implemented image area select in projectpier. One thing that is absolutely crucial is that the style of the preview div has overflow:hidden and a width and height. It is there in your css but not mentioned. Drives you crazy when they are missing :D
    With the following options added after onSelectChange:, preview the selection is shown upon load:

    show: true,
    x1: 0,
    y1: 0,
    x2: 50,
    y2: 50