NOTE: Please update your browser. We recommend using IE 7 or FireFox 3.

PHP & jQuery image upload and crop

May 15th, 2008 | Posted in Ajax, Articles, Jquery, PHP | 122 Comments »
Tags: , , , , ,

NOTE: This script has been updated please see the following link PHP & jQuery image upload and crop v1.2 AND the new fully jquery’d version of it Jquery image upload and crop for PHP. Both new scripts handle JPG, GIF and PNG upload and crop!

We needed a PHP and jQuery image upload and crop tool and came up with the following. Hope it helps!

Before you start, ensure you have the following:

Our Requirement

What we needed was a way to upload a JPG image, resize it if required then crop it to given height and width.

1. Firstly we created a form to allow us to upload an image. Pretty basic, nothing flashy there.

Photo

2. Capture, rename and resize the uploaded file. (We also provided a set name for the uploaded file.)

if (isset($_POST["upload"])) {
	//Get the file information
	$userfile_name = $_FILES["image"]["name"];
	$userfile_tmp = $_FILES["image"]["tmp_name"];
	$userfile_size = $_FILES["image"]["size"];
	$filename = basename($_FILES["image"]["name"]);
	$file_ext = substr($filename, strrpos($filename, ".") + 1);

	//Only process if the file is a JPG and below the allowed limit
	if((!empty($_FILES["image"])) && ($_FILES["image"]["error"] == 0)) {
		if (($file_ext!="jpg") && ($userfile_size > $max_file)) {
			$error= "ONLY jpeg images under 1MB are accepted for upload";
		}
	}else{
		$error= "Select a jpeg image for upload";
	}
	//Everything is ok, so we can upload the image.
	if (strlen($error)==0){

		if (isset($_FILES["image"]["name"])){

			move_uploaded_file($userfile_tmp, $large_image_location);
			chmod ($large_image_location, 0777);

			$width = getWidth($large_image_location);
			$height = getHeight($large_image_location);
			//Scale the image if it is greater than the width set above
			if ($width > $max_width){
				$scale = $max_width/$width;
				$uploaded = resizeImage($large_image_location,$width,$height,$scale);
			}else{
				$scale = 1;
				$uploaded = resizeImage($large_image_location,$width,$height,$scale);
			}
			//Delete the thumbnail file so the user can create a new one
			if (file_exists($thumb_image_location)) {
				unlink($thumb_image_location);
			}
		}
		//Refresh the page to show the new uploaded image
		header("location:".$_SERVER["PHP_SELF"]);
		exit();
	}
}

3. Now that the image has been uploaded and saved to our folder we can use the “Image Area Select” plugin to crop our image.

It basically provides the coordinates to the server to handle the crop.

  • x1, y1 = coordinates of the top left corner of the initial selection area
  • x2, y2 = coordinates of the bottom right corner of the initial selection area
  • width = crop selection width
  • height = crop selection height

There are a number of options with this plugin which you can see using the link above. We opted for an aspect ratio of 1:1 (height and width of 100px) along with a preview of what we are actually going to crop.

Lets break it down, we first set the imgAreaSelect function to the image we want to crop, i.e. the one we just uploaded. As you can see, the aspect ration is set to 1:1, which means we are going to get a square selection. The “onSelectChange” is a callback function which runs the preview function when a change is made to the crop.

$(window).load(function () {
	$("#thumbnail").imgAreaSelect({ aspectRatio: "1:1", onSelectChange: preview });
});

The preview function below, is run as soon as you create your selection. This places the right part of the image into the preview window. The second part of the function populates hidden fields which are later passed to the server.

function preview(img, selection) {
	var scaleX = 100 / selection.width;
	var scaleY = 100 / selection.height; 

	$("#thumbnail + div > img").css({
		width: Math.round(scaleX * 200) + "px",
		height: Math.round(scaleY * 300) + "px",
		marginLeft: "-" + Math.round(scaleX * selection.x1) + "px",
		marginTop: "-" + Math.round(scaleY * selection.y1) + "px"
	});
	$("#x1").val(selection.x1);
	$("#y1").val(selection.y1);
	$("#x2").val(selection.x2);
	$("#y2").val(selection.y2);
	$("#w").val(selection.width);
	$("#h").val(selection.height);
}

This function is not really required, but helps by checking to see if the user has made a crop selection. In our case it is a required step. The form is submitted if the values exist, i.e. a selection has been made.

$(document).ready(function () {
	$("#save_thumb").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;
		}
	});
});

4. Finally it’s time to handle these new coordinates and generate our new cropped thumbnail.

if (isset($_POST["upload_thumbnail"])) {
	//Get the new coordinates to crop the image.
	$x1 = $_POST["x1"];
	$y1 = $_POST["y1"];
	$x2 = $_POST["x2"]; // not really required
	$y2 = $_POST["y2"]; // not really required
	$w = $_POST["w"];
	$h = $_POST["h"];
	//Scale the image to the 100px by 100px
	$scale = 100/$w;
	$cropped = resizeThumbnailImage($thumb_image_location, $large_image_location,$w,$h,$x1,$y1,$scale);
	//Reload the page again to view the thumbnail
	header("location:".$_SERVER["PHP_SELF"]);
	exit();
}

That is pretty much it, and all it took was 2 javascript files! Take a look at the demo and download a copy to see the full working code.

So far we have tested it in FireFox v2, Internet Explorer 6 and 7 with pretty good results. (Let us know if you find any issues with other browsers.)

The demo

Click here to see it in action

Download

Click here to download


Found this article useful? Did it save you time?



Tags: , , , , ,

Blogsphere: TechnoratiFeedsterBloglines
Bookmark: Del.icio.usSpurlFurlSimpyBlinkDigg
RSS feed for comments on this post
 |  TrackBack URI for this post

122 Comments to “PHP & jQuery image upload and crop”

  • Oya says:

    This is a pretty nice script. But what I don’t understand is why you don’t use the original uploaded image when you make the thumbnail. If the previewimage and the thumbnail are the same width, you get bad quality if you decrease the width of the crop.

  • webmotionuk says:

    @Oya, the reason we haven’t used the original image is because we wanted it to fit within our site’s width. So if a user uploads an image which is 1000pixels wide and our site only has say 600px of space, its not really going to work…The whole look and feel of the site will be broken because of that large image being displayed.

    There is no reason why you cannot edit the script to have it the way you want i.e. using the original image, the script is pretty well commented, and shouldn’t be difficult to achieve. There are also options to restrict the width of the original image (you can set this to as big as you want), so its fairly configurable. Although saying that, uploading very large images causes memory issues, so beware. (http://www.webmotionuk.co.uk/jquery-image-upload-and-crop-for-php/#comment-677)

  • Oya says:

    As I was trying to write:

    The width of the original image is easy to edit.

    I think it would be a nice improvement of the script to implement this function, at least as an option. In my case, loadingtime of the image is no problem.

    If you add a variable for the maximum width of the original image (the witdh of the availible space in your site).

    And (as far as i can reckon) edit the coordinatecalculation in this function: function preview(img, selection).

    it should work.

    Unfortunately my skills in javascriptprogramming is pretty low, so i was not successful in editing the function.

    If anyone has a tips for this, it would be most appreciated, by me and most likely a lot of other users :)

    Ps. Check out my link to see it in action (You see the problem with the previewimage)

  • Oya says:

    Well, I tried a bit more, and I now have managed to get the savingprocess right. But I still have problems with the preview of the cropped image.

    I think I have two solutions:

    1. Learn how css crop works, then edit $(‘#thumbnail + div > img’).css({ in function preview(img, selection)

    2. When the image is uploaded, keep the fullsize and make a smaller picture with the width you use for the site. Then I use the smaller for the previewimage. I think this should work well.

    Anyone want to help me with either two?

    What i have done so far to get the script to save a correct crop of the fullsizeimage shown with a widthconstraint:

    Add a variable called $showwidth = 500; (500px in my case)

    above function preview(img, selection) i have added this: $forhold = $current_large_image_width / $showwidth ;?> (forhold is the norwegian word for proportion or something like that

    In function preview(img, selection):
    $(‘#x1′).val(selection.x1 * );
    $(‘#y1′).val(selection.y1* );
    $(‘#x2′).val(selection.x2 / );
    $(‘#y2′).val(selection.y2 / );
    $(‘#w’).val(selection.width * );
    $(‘#h’).val(selection.height * );

  • webmotionuk says:

    @Oya, the reason the preview is not working as required, is because of the scaling. We’ve uploaded an image of 2000×1500, which is being scaled (not resized as in our script) to 500px, so now the preview is 4 times bigger width wise and 3 times bigger height wise.

    in the javascript function find the following
    $(‘#thumbnail + div > img’).css({
    width: Math.round(scaleX * 2000) + ‘px’,
    height: Math.round(scaleY * 1500) + ‘px’,

    and replace is with this this
    $(‘#thumbnail + div > img’).css({
    width: Math.round(scaleX * (2000/500)) + ‘px’,
    height: Math.round(scaleY * (1500/500)) + ‘px’,

    The 2000 and 1500 should be coming from php variables, so divide them by your $showwidth variable.

  • Oya says:

    Thx, I got it working, but i had to rewrite your code a bit.

    $(’#thumbnail + div > img’).css({
    width: Math.round(scaleX * 2000 / (2000/500)) + ‘px’,
    height: Math.round(scaleY * 1500 / (2000/500)) + ‘px’,

  • Thiet ke website says:

    Thanks for your plugin!

  • flashsplat says:

    I havn’t been able to try this yet (at work), but i believe this is exactly what i’ve been looking for…

    If it is.. i’m pretty sure i’m going to name my first child after you..

    Lol Thanks!

    P.S. – My son/daughter will probably hate you, but i’m okay with that ;)

  • flashsplat says:

    Is there a way to make this keep the original file name and then just add a “_thumb” to the thumbnail?

    Thanks..

  • foxprox says:

    Hi, just a small question,
    when the picture is uploaded, i acces the page where i can resize it.

    Then i get the page where the resized pic is displayed and i can either delete it or uploaded another pic.

    On that page the full-size image and the resized image is show too.

    Is it possible to remove it on that page?
    I would like to replace the photographs by a message.
    for example: “your photo was added, thank you”

    thanks for your reply

  • webmotionuk says:

    Look at lines 355 to 362,

    if(strlen($large_photo_exists)>0 && strlen($thumb_photo_exists)>0){
    echo $large_photo_exists.” ”.$thumb_photo_exists;
    echo “< p >< a href=\"".$_SERVER["PHP_SELF"]."?a=delete&t=".$_SESSION['random_key'].$_SESSION['user_file_ext']."\" rel="nofollow">Delete images“;
    echo “< p >< a href=\"".$_SERVER["PHP_SELF"]."\" rel="nofollow">Upload another< / a >< / p >“;
    //Clear the time stamp session and user file extension
    $_SESSION['random_key']= “”;
    $_SESSION['user_file_ext']= “”;
    }else{

    replace with

    if(strlen($large_photo_exists)>0 && strlen($thumb_photo_exists)>0){
    echo “your photo was added, thank you”;
    //Clear the time stamp session and user file extension
    $_SESSION['random_key']= “”;
    $_SESSION['user_file_ext']= “”;
    }else{

  • foxprox says:

    it ’s ok! thank you very much!

  • rudi says:

    Hi,

    Love this script, exactly what I need for a little web project. But… I have an odd problem. It doesn’t work unless I am logged on using my “root” user on my MacBook. I changed Apache2’s httpd.conf to refer to my own user, which got it to half work. The first page opens, allows me to select a pic to try to upload, but then I get a blank page without any error messages. Any idea what else would need to be changed for the script to run even when not logged in as root?? (this is on Mac OSX, Leopard)

  • WhiteKnight says:

    Hey,

    Nice script here, I havent tested it yet but I will soon.

    I know the feature saves the thumbnail etc but how could I get this to save into a users profile. Like have it intergrated with wordpress.

    So the user logs in > Uploads image > Crops image and hits save, then the thumbnail is saved for them in there user area?

    Can this be done?

    Thanks

    WhiteKnight

  • webmotionuk says:

    @whiteknight, to get that sort of functionality you would need to write the code into a wordpress plugin.

  • adrian says:

    Hi, really nice piece of code you’ve written, thanks for sharing with us all!

    I’m having a problem with it however when integrating it into a CMS I have put together. Creating new thumbnails (and other assorted meta and publish infos) are straightforward enough, however I’m coming unstuck when I try to allow administrators the ability to update the thumbnail selection. I have managed to get the selection box to display correctly on my larger image, but I need this selection to be shown in the RHS thumb.

    However to do this, I need to fire some kind of onInit call to perform the same task as onSelectChange, (as currently it only fires after a mouse interaction, which of course moves the current selection).

    Is there any current way to do this?

    Thanks,
    Adrian

  • ian says:

    with reguards to the hitting refresh to update the picture because of old cache not being updated i would recommend the following code:

    <img src=”"

    where $upload_file (for example) is “myimage.gif”. as mentioned above adding a random query string at the end of a image works, but only if the query is dynamic. this is why i opted for adding time() into the query above.

    hope this helps someone as the previous post about query string cache and this amazing code snippet from webmotionuk helped me. :)

  • ian says:

    whoops the above should say:

    <img src="" ...

  • ian says:

    argh. i removed the < in front of the ?php because it doesn’t show up correctly. it should say this:

  • ian says:

    <img src=”myimage.gif?t=” . time()

  • ton says:

    Hi,

    i want to save the imagename to a mysql database. I get the id from my record from the URL. so far so good. But after the upload, i lose the id.

    can anybody help me?

    i just started learning php.

  • Ravi says:

    Hi,

    Very good post. I have a small question regrarding the image crop selection. Can you provide a default crop area at the time of page load only. Which could be more use fill.

    I am asking because as i am in need of it. I want to have a default selected crop area.

    Thanks

  • xav says:

    great script!

    Is it possible to have 3 pre-defined crop dimensions to crop an image? I’ve tried with 3 submit buttons, but got ‘Headers already set error’ and no empty PHP vars POSTED on UPLOAD form POST.

    tnx in advance

  • webmotionuk says:

    @Ravi, please see the following comment

    Pre-defined crop area

  • Rariti says:

    Excellent Script. I am a designer and was working on my portfolio site. This script came in very handy. I no longer have to use Photoshop to resize tons of images.
    I successfully managed to make alot of tweaks to get it to integrate with my custom CMS. I added dynamic widths, heights that are pulled from the db. Works beautifully. Very well done, and was quite fun tinkering around with it.

    I do have two questions.
    1. How would I go about keeping a constant width and have the height be fluid, if the height is not set.
    2. On page load, how do I display the cropping area. Currently it does not show until you click the original.

    Thanks and again, wonderful script.

  • webmotionuk says:

    @Rariti the answers to your questions are as follows:
    1. Use a set width, along with the max-height variable. The max-height can be the actual height of the image, therefore should allow it to stretch in the way you need it to. However you will need to update the imgareaselect js file to the latest version which is available from the authors website. We unfortunately have not had time to update it in our package but will do soon.
    2. Please see the following comment Display cropping area on load

  • nico says:

    After having resized my picture, how could I avoid the sending of the original
    picture on the server?
    (I only need to save the resized picture)

    Thank you

  • Colin the Pom says:

    Great script. I’m very new to this and have one question. My application is allowing users to add a profile picture so they click in from profile page and a variable (ID number) is brought in. I want the thumbnail to be saved with the ID number as the filename. Which bit of the code do I need to modify to make this work??
    Thanks!!

  • webmotionuk says:

    @Colin, please find the $thumb_image_name and replace the value of this with your ID, you may want to echo this to the page so that you can ensure it is the carrying the correct ID throughout the process of upload and crop.
    $thumb_image_name = $thumb_image_prefix.$_SESSION['random_key'];
    to
    $thumb_image_name = $ID;

  • Colin the Pom says:

    Thanks for answering so promptly! I must be a bit thick though as I can’t find the line of code that you suggest replacing in the “upload_crop.php” file I downloaded (I am trying to use version 1.2 as I only want users to be able to upload a jpeg)…

  • Andrew says:

    Hi , I have a question like Vega ….

    How to add a rand() to name , to upload non’stop the pictures…..
    If a have a portal and want to upload an image there is more images… so i need a random value be add’et to the name of file…
    when I make that in

    $large_image_name = “resized_pic.jpg”; // New name of the large image
    $thumb_image_name = “thumbnail_pic.jpg”; // New name of the thumbnail image

    and put :

    $large_image_name = rand().”resized_pic.jpg”; // New name of the large image
    $thumb_image_name = rand().”thumbnail_pic.jpg”; // New name of the thumbnail image

    The screen after upload no change… but the 1 file is Uploading ….
    so , how to make all work OK?
    Pleace help!

    P.S. Sorry my english is not so good, but I’m traing.

  • LP80 says:

    Hi,
    great work!!
    but i have a little problem…

    when i change $max_file value to 5, it should accept the files with a size<= 5Mb… but it doesn’t work

    and display the error message on line 200.

    the condition on line 182 isn’t filled ($_FILES["image"] is empty), but i can’t explain the reason.
    the file size is lower than 5Mb, is a JPEG.

    Maybe the image size??

    can you help me?
    thank’s

  • webmotionuk says:

    @LP80 if the image size is greater than 2000px across php runs out of memory and crashes, try set the php memory limit higher than what you currently have? If you are still having trouble please contact us through our contact page.

  • LP80 says:

    I’ve changed the max_upload on php.ini and it work greatly.

    Thank’s.

  • Rolf says:

    hey everone,

    great script thanks for that! I’m trying to implement it to my homepage. I have just one big issue: Can maybe someone help me to implement a “uploadbar” for the first image upload?

    I’m trying around since weeks without any success… if someone can help me out it would be really fantastic!

    Cheers,
    Rolf

  • Arif says:

    Thanks for your post

  • Cindy Longleg says:

    I tried it by unzipping the files and putting them on a Web server.

    I changed the permissions so the file could be saved.

    It accepts the upload (I can see it in the directory).

    But after that it tries to download the PHP file instead of running the scripts to render a page for resizing.

    How to make the script actually work on your own server?

  • joel says:

    this is a great script, thanks, only one problem, it is not working with the latest version of firefox, 3.0.12 on mac, it does work in Safari, and Opera however.

  • Sergio says:

    It’s a beautiful tool indeed. Now, I’d like to know if there is a way for:

    1) Save the thumb with the original image name.
    2) Delete the large image.

    The second task is easy for me to figure out how to achieve it, but the first one is beyond my actual skills.

    I’ll appreciate any idea.

    Cheers,

    Sergio

  • jim says:

    Really nice plugin… but it seems the final crop is always square….?!
    What is the sum of 0 and 4? Answer: 40!

  • Ian says:

    I love this plugin but the problem I have had is when I use it on my live server the resize image has the file extension twice, this wasn’t happening on my local machine.

    For example I end up with resize_0123456789.jpg.jpg this means the image then doesn’t get displayed for the user to select a thumbnail area.

    Does anyone have any ideas why this could be happening?

    Thanks again for a great plugin

  • webmotionuk says:

    @Ian, try clearing your cache and cookies, seems the session variable that holds the suffix of the image is not being overwritten.
    @Jim, you can adust the size of the crop by changing the thumbnail width and height.

  • Saket says:

    Well Script is good ..but i notice one problem :(

    Upload first image then drag mouse over main image..you will see crop image preview..now do not save it! just click again to upload another image and this time there will be a crop line on new image and javascript just stop working :(

    I am trying to reset everything before new image appear but didn’t get solution..

    Anyone can suggest solution ????

    Thanks,
    Saket

  • Rob says:

    Pages do not load or refresh after a button click in IE. any work around for this?

  • Oren Yomtov says:

    Thank you very much for the code, a donation has been sent.

  • hueblack says:

    thank u ^ ^

  • Amit Chavda says:

    Hi,

    Its been really nice script and I used it with CakePHP framework. But I face one small but major issue with IE browser. When ever I upload new image, the page shows me the previous one as both main and thumbnail image. It seems come from cache as it show real image once i refresh the browser.

    I know there was below notice in your initial version.
    echo “NOTE: If the thumbnail image looks the same as the previous one, just hit refresh a couple of times.”;
    But its not in the latest on 1.2. I implement that too but still not succeed in resolving the problem

    Can you help me to resolve this issue?

  • vaibhav says:

    hi , really liked this script, but i want to modify this and use it in my project, i just wanna save the croped image at last but not both image , so plese help me

  • Makita says:

    Hello!

    I love your script, ‘cos it very greatful not some than my knowlage :D
    I try to change the $_SESSION['random_key'] to my id, what i post it from GET variable, so i call the file like that: upload.php?imagename=xyz , but it doesn’t work if the page is reload. because the GET will be unset. After that i try change the header with $url = “upload.php?kepnev=”.$_GET['imgename'];
    header(“location:”.$url);
    but the variable did not exist here already.
    If you can please help me!

    Ahead thank you for the answers! (sorry for my poor english)

  • Niladri says:

    in the upload_crop.php page please write as the Top of the Page another chunk of codes
    as below:

    ini_set(“memory_limit”, ‘-1′);

    It will create no problem when uploading a big image may be of 3.5 MB

Post comment