AJAX image cropper with YUI and PHP

This post will show you how to build an AJAX crop image tool using the image cropper control from YUI library and PHP.

Demo
Download sample file

The ImageCropper Control from the YUI library gives you an interactive interface for getting the dimensions to crop an image and using these dimensions in PHP, we can do some cropping.

The script we are going to build will

  • allow users to upload an image via AJAX
  • then allow them to select an area for cropping
  • lastly, provide a download link for the cropped image.

There are 3 files we are going to use

  • index.php - will contain the form for image upload as well as the cropping interface
  • upload.php - provides uploading functionality
  • crop.php - provides cropping functionality

From a technical point of view, the flow will be like this :

  1. user uploads jpg image (index.php)
  2. index.php then posts the image asynchronously to upload.php which will do the upload on the server, returning JSON data containing the image file name, its width and its height.
  3. with the JSON data and innerHTML we put the image in our page
  4. initialize the javascript cropping tool
  5. generate a download link (crop.php)


Let's have a look at index.php

The index.php is our main file where users will be able upload images and then download the cropped ones.

We'll need the following components from the YUI library :

  • yahoo-dom-event.js - for DOM manipulation and Event handling
  • dragdrop - dependency for the image cropper control
  • element - dependency for the image cropper control
  • resize - dependency for the image cropper control
  • connection - for AJAX requests, in our case for image uploads via AJAX
  • json - for parsing JSON data
  • imagecropper - our most important control

Of course we'll use Yahoo combo handling and add the js to our page along with the CSS needed for the above controls :

 
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/resize/assets/skins/sam/resize.css" />
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/imagecropper/assets/skins/sam/imagecropper.css" />
<!-- js -->
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.5.2/build/yahoo-dom-event/yahoo-dom-event.js&2.5.2/build/dragdrop/dragdrop-min.js&2.5.2/build/element/element-beta-min.js&2.5.2/build/resize/resize-beta-min.js&2.5.2/build/imagecropper/imagecropper-beta-min.js&2.
5.2/build/connection/connection-min.js&2.5.2/build/json/json-min.js"></script>
 

Next users must be able to upload images via AJAX, so we add a form to our page:

 
<form action="upload.php" enctype="multipart/form-data" method="post" name="uploadForm" id="uploadForm">
	Image :
<input type="file" name="uploadImage" id="uploadImage" />
<input type="button" id="uploadButton" value="Upload"/>
</form>
 

We have an onclick event to the upload button to fire the uploading process.

 
// add listeners
YAHOO.util.Event.on('uploadButton', 'click', uploader.carry);
 

We'll also need 2 containers :

  • imageContainer - will contain our uploaded image
  • downloadLink - will contain the download link
 
<div id="imageContainer"></div>
<div id="downloadLink"></div>
 

Both containers will be updated via innerHTML afterwards.

AJAX upload
For the AJAX upload, Code Central

has an excellent tutorial which I highly recommend. I took the code sample and modified it a bit to fit my needs. Finally I came up with a nice JSON object called uploader which has one method, carry. The latter just posts form data to a specified URL.

 
uploader = {
	carry: function(){
		// set form
		YAHOO.util.Connect.setForm('uploadForm', true);
		// upload image
		YAHOO.util.Connect.asyncRequest('POST', 'upload.php', {
			upload: function(o){
				// parse our json data
				var jsonData = YAHOO.lang.JSON.parse(o.responseText);
 
				// put image in our image container
				YAHOO.util.Dom.get('imageContainer').innerHTML = '<img id="yuiImg" src="' + jsonData.image + '" width="' + jsonData.width + '" height="' + jsonData.height + '" alt="" />';
 
				// init our photoshop
				photoshop.init(jsonData.image); 
 
				// get first cropped image
				photoshop.getCroppedImage();
			}
		});
	}
};
 

When upload is complete, we get the JSON data we mentioned earlier on. For e.g :

 
{"image" : "images/myimage.jpg", "width" : "500", "height" : 400}
 

With this data and using innerHTML we update our imageContainer div to put our image which will have yuiImg as id :

 
YAHOO.util.Dom.get('imageContainer').innerHTML = '<img id="yuiImg" src="' + jsonData.image + '" width="' + jsonData.width + '" height="' + jsonData.height + '" alt="" />';
 

It's very important to specify the image width and height else the image cropper won't work.
Next we initialize another JSON object, photoshop which we'll have a look now.

Our photoshop object

 
photoshop = {
	image: null,
	crop: null,
 
	init: function(image){
		// set our image
		photoshop.image = image;
 
		// our image cropper from the uploaded image
		photoshop.crop = new YAHOO.widget.ImageCropper('yuiImg');
		photoshop.crop.on('moveEvent', function() {
			// get updated coordinates
			photoshop.getCroppedImage();
		});
	},
 
	getCroppedImage: function(){
		var coordinates = photoshop.getCoordinates();
		var url = 'crop.php?image=' + photoshop.image + '&cropStartX=' + coordinates.left +'&cropStartY=' + coordinates.top +'&cropWidth=' + coordinates.width +'&cropHeight=' + coordinates.height;
		YAHOO.util.Dom.get('downloadLink').innerHTML = '<a href="' + url + '">download cropped image</a>';		
 
	},
 
	getCoordinates: function(){
		return photoshop.crop.getCropCoords();
	}
};
 

The init function iniatializes the YUI image cropper from the uploaded image which has yuiImg as id.

 
photoshop.crop = new YAHOO.widget.ImageCropper('yuiImg');
 

We also subscribe to the moveEvent for the cropper since we'll need to update the download link for the cropped image. So whenever the image cropper is moved/resized, we call the getCroppedImage function.

 
photoshop.crop.on('moveEvent', function() {
	// get updated coordinates
	photoshop.getCroppedImage();
});
 

The getCroppedImage function will generate the download link for the cropped image. To do image cropping in PHP we'll need

  • the image we want to crop
  • the X,Y coordinates
  • height and width of the to be cropped area

Fortunately the YUI cropper utility has a function which will give us what we want, it's the getCropCoords() method. So, whenever the getCroppedImage function is called, we get the coordinates of the cropped area, build a URL and finally put the download link in our downloadLink container.

 
// get coordinates
var coordinates = photoshop.getCoordinates();
 
// build our url
var url = 'crop.php?image=' + photoshop.image + '&cropStartX=' + coordinates.left +'&cropStartY=' + coordinates.top +'&cropWidth=' + coordinates.width +'&cropHeight=' + coordinates.height;
 
// put download link in our page
YAHOO.util.Dom.get('downloadLink').innerHTML = '<a href="' + url + '">download cropped image</a>';
 

This is all we need for the index page.

upload.php

 
if(!empty($_FILES["uploadImage"])) {
  	// get file name
	$filename = basename($_FILES['uploadImage']['name']);
 
	// get extension
  	$ext = substr($filename, strrpos($filename, '.') + 1);
 
  	// check for jpg only
  	if ($ext == "jpg") {
      		// generate unique file name
  		$newName = 'images/'.time().'.'.$ext;
 
  		// upload files
        	if ((move_uploaded_file($_FILES['uploadImage']['tmp_name'], $newName))) {
 
        		// get height and width for image uploaded
        		list($width, $height) = getimagesize($newName);
 
        		// return json data
           		echo '{"image" : "'.$newName.'", "height" : "'.$height.'", "width" : "'.$width.'" }';
        	}
        	else {
           		echo '{"error" : "An error occurred while moving the files"}';
        	}
  	}
  	else {
     		echo '{"error" : "Invalid image format"}';
  	}
}
 

The upload.php file too is self explanatory, we check for a jpg image only, then generate an unique filename, put it in the images folder and finally build json data which we'll use for DOM manipulation. Of course the images folder must be writable by the web server.

crop.php

 
// get variables
$imgfile = $_GET['image'];
$cropStartX = $_GET['cropStartX'];
$cropStartY = $_GET['cropStartY'];
$cropW = $_GET['cropWidth'];
$cropH = $_GET['cropHeight'];
 
// Create two images
$origimg = imagecreatefromjpeg($imgfile);
$cropimg = imagecreatetruecolor($cropW,$cropH);
 
// Get the original size
list($width, $height) = getimagesize($imgfile);
 
// Crop
imagecopyresized($cropimg, $origimg, 0, 0, $cropStartX, $cropStartY, $width, $height, $width, $height);
 
// force download nes image
header("Content-type: image/jpeg");
header('Content-Disposition: attachment; filename="'.$imgfile.'"');
imagejpeg($cropimg);
 
// destroy the images
imagedestroy($cropimg);
imagedestroy($origimg);
 

Crop.php allows us to crop our uploaded image. First we get all the variables passed to us via the AJAX request,

 
// get variables
$imgfile = $_GET['image'];
$cropStartX = $_GET['cropStartX'];
$cropStartY = $_GET['cropStartY'];
$cropW = $_GET['cropWidth'];
$cropH = $_GET['cropHeight'];
 

Then we create 2 images, the original one and the cropped one, and use the imagecopyresized function to generate the cropped image. We add some header information to tell the world it's an image and prompt for a save dialog.

Demo
Download sample file

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
  • Mixx
  • Ma.gnolia
  • Technorati
  • Netvouz
  • Reddit
  • Propeller
  • Slashdot
  • DZone

39 Comments to “AJAX image cropper with YUI and PHP”

  1. [...] asvin Demo: http://htmlblog.net/demo/cropper/ Download: click here Source: http://www.htmlblog.net addthis_url = [...]

  2. Dav Glass 8 October 2008 at 11:01 pm #

    Nice example, I will have to link to it from the http://developer.yahoo.com/yui/imagecropper page ;)

  3. asvin 9 October 2008 at 1:42 pm #

    Cool, thanx Dave ;-)

  4. [...] Ballo has posted a tutorial that shows how to combine the YUI libraries with PHP to create a simple image [...]

  5. [...] The html blog | AJAX image cropper with YUI and PHP [...]

  6. rohit 21 October 2008 at 9:12 am #

    How can we disable resize of area that is to be crop???

  7. asvin 21 October 2008 at 9:28 am #

    Rohit, you mean you want to disable the image cropper control? Try this:
    photoshop.crop.destroy();

  8. [...] of DataTable with Tooltip. A single Tooltip is reused throughout the table to improve performance.AJAX Image Cropper with YUI and PHP: Asvin Balloo has written up a tutorial on using Dav Glass’s ImageCropper Control with a PHP [...]

  9. kovshenin 1 November 2008 at 11:29 am #

    the demo doesn’t work for me :( i get php errors…

  10. asvin 1 November 2008 at 11:51 am #

    Hi Kovshenin

    What are the errors exactly? Currently the PHP script caters only for JPG files.

  11. Josh 4 November 2008 at 2:00 am #

    Thanks for the great script!

    One question: can I set the aspect ratio of the crop? I would like all user-cropped images to be the same shape.

    Thanks again!

  12. Adel Mohame Ibrahiem 6 November 2008 at 4:00 pm #

    Can i add(insert) this photo in table in Mysql and retrieve it.
    Please help me

  13. asvin 6 November 2008 at 5:22 pm #

    Josh

    You can add the following options when creating the image cropper:
    initHeight
    initWidth

    like that:
    photoshop.crop = new YAHOO.widget.ImageCropper(‘yuiImg’, {initHeight:200, initWidth: 200});

    Check the doc
    http://developer.yahoo.com/yui/imagecropper/

    Adel,
    check my other blog post,
    http://htmlblog.net/pixidou-an-open-source-ajax-image-editor-php-and-yui-based/

    Maybe it’ll be easier for you. Let me know if you need help

  14. คลิป 7 November 2008 at 3:42 pm #

    Thank

  15. gajender 12 November 2008 at 1:51 pm #

    pls send script for save crop image

  16. asvin 13 November 2008 at 8:57 am #

    Gajender, check my blog post,
    http://htmlblog.net/pixidou-an-open-source-ajax-image-editor-php-and-yui-based/

    you can download the script there.

  17. rborn 14 November 2008 at 2:07 am #

    I always wanted a script that allows me to rotate images in realtime.
    Is a real pain to wait for the server to rotate and post back the image – in case you want an arbitrary angle. So I made myself a script, that allows you to rotate, zoom and reposition the image in realtime, then after you finish, you can crop the picture.

    here it is: http://kroppr.rborn.info

  18. Josh 21 November 2008 at 4:05 am #

    Asvin,

    I never thanked you for replying to my earlier post… Thank you! It was very helpful. Everything is working really well.

    Now I have a new question: I would like to give user’s the ability to crop an image that is already stored on the server.

    Here’s my methodology:
    1. Bypass “uploader” object.
    2. Add ” to the page.
    3. Initiate “photoshop” object.
    4. (Continue as normal)

    I’m just not sure how to initiate the “photoshop” object. Should I use an “OnLoad” event?

    Thanks again!

  19. Josh 21 November 2008 at 4:10 am #

    (the code that I included in Step 2 in the last comment was scrubbed… Here is the comment again)

    Asvin,

    I never thanked you for replying to my earlier post… Thank you! It was very helpful. Everything is working really well.

    Now I have a new question: I would like to give user’s the ability to crop an image that is already stored on the server.

    Here’s my methodology:
    1. Bypass “uploader” object.
    2. Add the image and what would have been JSON data for the image directly into the HTML.
    3. Initiate “photoshop” object.
    4. (Continue as normal)

    I’m just not sure how to initiate the “photoshop” object. Should I use an “OnLoad” event?

    Thanks again!

  20. Josh 21 November 2008 at 4:37 am #

    Asvin,

    Okay… so I think I just answered my own question and I have it working the way I want. Thanks :)

  21. Henning 14 December 2008 at 11:08 pm #

    Hello Asvin, thank you for an excelent post!
    I would like to know how you implement
    the code you mentioned above
    photoshop.crop = new YAHOO.widget.ImageCropper(’yuiImg’, {initHeight:200, initWidth: 200});

    Where does this code goes, I tried the doc but I couldn´t find it.

    To leave the user to be able to crop to any wanted size may produce strange results when fitting images into designated boxes. Is it possible to make presets the user can select from. Ex. 200px x 200px and 150x 100 px?

    Thank you again for a great post.

  22. Henning 15 December 2008 at 4:54 pm #

    I am trying to use the script for cropping two different images after each other from two different files. The first crop is stored on server and then the filename is inserted to MySQL, but when I redirect to the next page to crop the next image the script will not work, and I get an error message from the Browser developer console. Any ideas how to be able to use it multiple times after eachother? Can I clear the DOM objects or something?

    I figured out the question above ;-)

  23. asvin 15 December 2008 at 8:24 pm #

    Hi Henning,

    If I’ve understood your question, you want to reset the cropper? If so try this:
    photoshop.crop.reset();

    Let me know if it’s ok ;-)

  24. Arazmus 27 February 2009 at 3:49 pm #

    is it possible (i might have missed this) to make the cropped image save to a thumbnail directory instead of being downloaded to the user?

    IE
    User uploads
    User Crops
    Cropped image saved to folder

  25. Arazmus 27 February 2009 at 6:48 pm #

    nevermind.. I managed to sort it out, i had to edit the last section of the crop.php to not destroy and not link the pic, then added the following:

    imagejpeg($cropimg ,’images/thumbs/’.$imgfile

    this sorted it but had to make the dir’s first..

    thanks anyway

  26. Rachana 1 April 2009 at 4:58 am #

    Hi … this example is working fine with me .. but m facing wired problem of caching I guess. Every time i upload the photo … it shows me the previous photo I had uploaded on the base of the cropper. The cropper box also contains some previous photo image. But after I crop the image, the result is of the image i just upload… its wired.. May be its becoz of asyncRequest. Any idea ???

  27. Rachana 1 April 2009 at 9:11 pm #

    Hey another question: I want that cropper width and height cannot be changed only user can pull it corners to maintain the ratio. Is it possible ?

  28. asvin 1 April 2009 at 9:17 pm #

    @Rachana

    For the caching problem, I’ll have a look and let you know. As for fixed cropper, check out this link :
    http://tech.groups.yahoo.com/group/ydn-javascript/message/33692

    I’ve tried it, works like a charm ;-)

  29. Rachana 3 April 2009 at 12:58 am #

    Wow, Thanks asvin .. that worked great for me. I have one another problem.
    If the user uploades a huge image then it break my so I decided to set the width and height of the image to 500 X 500 but the cropper seems to take original image only.

    So, wht happen is that orginal image looks shrinked but the cropper takes the original big image.

    How to make cropper also fit as the shrinked image ??

    Donno whether you will be able to get the problem or not, but just try to fix the size of the image and then move the cropper over it.

  30. asvin 3 April 2009 at 11:39 am #

    Rachana, I suggest a quick fix, why don’t you resize the image upon uploading? I highly recommence verot upload class :
    http://www.verot.net/php_class_upload.htm

    You can do the upload more quickly and then resize big images to fit your needs.

  31. Rachana 12 April 2009 at 11:53 pm #

    Hi Asvin,

    Thanks for all your help and suggestion. My module is working great.

    I have one problem at last :)

    Components.classes['@rdfa.digitalbazaar.com/fuzzbot/xpcom;1'] is undefined [Break on this error] },_setBackgroundPosition:function(F,H){v…opper,{version:”2.5.2″,build:”1076″});/*

    I am getting this javascript error coz of 2.5.2 version of imagecropper. I tried 2.7.0 also but its not working too. Infact if I change the version, cropper itself stops working.

    Any clue whtz going wrong ???

  32. asvin 13 April 2009 at 12:44 pm #

    Hello again Rachana

    Hmm, do you have an URL you can give me so that I can have a look?

  33. Rachana 13 April 2009 at 10:43 pm #

    I wish I could but its again company policy.

  34. Rachana 22 April 2009 at 9:15 pm #

    Hi Asvin,

    Is there any way to hide the cropper handles instead of locking them??

  35. asvin 22 April 2009 at 9:22 pm #

    Rachana,

    This can be done via some CSS, (thanks Firebug ;-)) :

    .yui-resize-knob .yui-resize-handle {
    height:0;
    width:0;
    }

    .yui-skin-sam .yui-resize-knob .yui-resize-handle-l, .yui-skin-sam .yui-resize-knob .yui-resize-handle-r, .yui-skin-sam .yui-resize-knob .yui-resize-handle-l-active, .yui-skin-sam .yui-resize-knob .yui-resize-handle-r-active {
    height:0;
    width:0;
    }

  36. Rachana 24 April 2009 at 6:51 am #

    you rock :)

  37. [...] View Tutorial No Comment var addthis_pub=”izwan00″; BOOKMARK This entry was posted on Monday, June 8th, 2009 at 3:52 am and is filed under Javascript Tutorials. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site. [...]

  38. Carl 30 July 2009 at 3:31 am #

    How do you get the resized image to save to the server????

  39. images 24 September 2009 at 5:52 pm #

    Many many thanks, great that.


Leave a Reply