UK Web Hosting Services
WebMotionUK Rss

PHP & jQuery image upload and crop

Posted in Ajax, Jquery, PHP | Posted on 15-05-2008

NOTE: This script has been updated please see the following link PHP & jQuery image upload and crop v1.1

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

Comments

  1. Thanks for the interesting script!
    However, it should be amended to read:
    line # 240 ($(’# thumbnail ‘). imgAreaSelect)
    should be changed to:
    $(’#thumbnail’).imgAreaSelect({ aspectRatio: ‘1:’, onSelectChange: preview });

  2. text was cut off. correct change:
    $(’#thumbnail’).imgAreaSelect({ aspectRatio: ‘1:<?php echo $thumb_height/$thumb_width;?>’, onSelectChange: preview });

  3. @long, thats correct, your addition makes it that much more dynamic.

  4. This plugin does not work if the img element was previously hidden and then displayed again via js. Seems to be a bug thats needs to be addressed

  5. @chris, why are you hiding the image in the first place? you may need to use livequery to pick up new elements introduced via JS. There is further information on the “image area select” plugin on the creators home page, see the link at the top of this page.

    Or give us a more detailed explanation of what you are trying to achieve, and if its relevant we can include it in the download.

  6. Here is the description of the problem

    http://www.nabble.com/imageAreaSelect-bug-td17861390s27240.html

    Im also experiencing problems if the img element does not have a width and height initially set. Why you might ask? Becasue I am loading content dynamically via AJAX calls

  7. @chris,
    This is the original code:

    $(document).ready(function(){
    $('#asdf').slideDown('slow');
    });

    $(window).load(function () {
    $('#asdf img').imgAreaSelect({ maxWidth: 20, maxHeight: 20 });
    });

    Try this instead:


    $(document).ready(function(){
    $('#asdf').slideDown('slow');
    $('#asdf img').imgAreaSelect({ maxWidth: 20, maxHeight: 20 });
    });

    The imageareaselect will be called after the image is loaded, You could even put this into a click function as follows:

    $(document).ready(function(){
    $('#button').click(function() {
    $('#asdf').slideDown('slow');
    $('#asdf img').imgAreaSelect({ maxWidth: 20, maxHeight: 20 });
    });
    });

    Let us know how you get on.

  8. Thanks, that did the trick. The problem was having “$(window).load(function () {”

  9. Nice compilation, thanks, especially for JS part.
    As for PHP part, i wonder why not use php native imagesx() and imagesy() instead of writing new getWidth() and getHeight().

  10. I was thinking about having an image up load feature. Learning how to implement the upload feature was the fun part.

  11. Looks cool. Thanks :)

  12. It is not trivial where you’ve got scaleX * 200 and scaleX * 300 when the Ferrari demo pic is 500 x 375. I figured that the proportions are the same, but couln’t you simplify it?

  13. Can you mod it to let users pick the cropping size from a drop down menu?

    thanks

  14. I think you meant

    (($file_ext != "jpg") || ($userfile_size > $max_file))

    rather than

    (($file_ext != "jpg") && ($userfile_size > $max_file))

    Cheers

  15. Opps - too quick with the click button.

    I also wanted to say - great job. This is an excellent piece of work. :)

    Cheers

  16. great job! Looking forvard for resize and rotate image functionality)

  17. Great work.. thanks.

  18. Great stuff \o/
    Does anyone know how to make it works with Thinkbox jQuery ?
    That would be a way to use the crop when you do not have enough space on your page.

  19. Your blog is interesting!

    Keep up the good work!

  20. I appreciate this… it is exactly what I was looking for!

  21. The http://www.webmotionuk.co.uk is cool site, good job

  22. Thanks for your work, thats a really nice image facility. I am going to use this for our website for sure. keep up the great tutes and work!

  23. This is an amazing script =) I love it… i had to change some few thing in it but i didnt get it to work with a random_key for the pic file name, so i just emailed the creator of the script…
    and then after 12hours the answer where in my inbox… and now it works perfecly finr!
    Thanks for a GREAT script, i be back for more =P

    //Fredrik, Sweden

  24. great script! but it just dont work well on explorer 7. you need to hit refresh to see new image :( is there any solution for this issue? thank you

  25. […] to write a tutorial on it. But, it seems someone already did this — WebMotionUK has a good article on building a simple tool that allows you to upload an image and crop it, with PHP and […]

  26. This is great, worked first time, and Long’s snippet is great too.

    Regarding the caching of images, just throw a random querystring on the image [ I just use ?t= ], and it won’t cache.

  27. a question, as I do so that the thumbnail is a rectangle rather than a square thanks

  28. Hello, how can I add a random(); to generate the name of the uploaded file…?
    Please emalil me someone at erisone(a)gmail.com, thanks!

  29. EXACTLY what I was looking for, wonderful, perfect!

  30. Really great script!
    Could you post the solution for a random filename that you mailed Frederik? I’ve been trying but I can’t get it to work. For example: How can I add a timestamp to the filename?

  31. This is a beautifully written script. I placed it on my website as a profile picture uploader. I was also wondering the same thing as Fredrik: how do I get this to work with a random image name?

Post a comment

  1. (required)
  2. (valid email required)
  3. (required)
  4. Send
  5. Captcha