Preview and crop before upload

DEMO

Further to our earlier post about drag and drop uploads, we have managed to add some additional features to this. HTML5 allows a user to preview an image before it is uploaded to the server. In a typical web environment, the image needs to adhere to a certain width to height ratio to fit in a particular slot. This becomes a necessity in slideshows, galleries or tightly designed pages. The script below, allows you to crop an image to a given prescribed width to height ratio. The beauty of the script is that it allows you to crop only part of the original image. For example, if you need an image of 400 px width and 200 px height and your original uploaded image is 1000 px wide and 1000 px in height, it will allow you to choose a part of the image and resize it to 400 x 200. This effectively means you can choose an area of 400 x 200 of the original image or 800 x 400 of the original (which is scaled to 400 x 200 post resize) and so on. It will never allow a crop which doesn’t satisfy the above width to height ratio. Similarly it will not allow you to choose a part of the image lesser than 400 x 200.

Click here to view a demo of drag and drop file upload. Once the files are in queue, you have the option of cropping the image before uploading. The files that you upload will show up from the server once the upload is finished. A brief explanation on how we have tackled this.

For the demo, we shall be using Andrew Valums’ Ajax Upload which can be found at http://valums.com/ajax-upload/ and imgAreaSelect which can be found at http://odyniec.net/projects/imgareaselect/.

We added a few more parameters to be used by the Drag and Drop upload script which is used for cropping the queued images.

$(document).ready(function () {
	uploader = new qq.FileUploader({
		element: document.getElementById('fileuploader'),
		folderName: 'uploads',
		action: 'upload.php',
		//Files with following extensions are only allowed
		allowedExtensions: ['gif','jpg','jpeg','png','txt'],
		showCropTool: 1,
		sizeLimit: 10737418240, // Maximum filesize limit which works without any problems is 30MB. Current limit is set to 10MB = 10 * 1024 * 1024
		params: {
			'uploadedBy': 'Sapnagroup',
			'x1': '0',	// x coordinates of the image
			'y1': '0',		// x coordinates of the image
			'x2': '300',	// x coordinates of the image
			'y2': '150',	// y coordinates of the image
			'cWidth': '300',		// required crop width
			'cHeight': '150',		// required crop heignt
			'oWidth': '800',		// width of the crop preview image
			'oHeight': '600',		// height of the crop preview image
			'rWidth': '300',		// resize width
			'rHeight': '150'		// resize height
		},
		onSubmit: function(id, fileName){

		},
		onComplete: function(id, fileName, responseJSON){ // Customize the output sent to responseJSON in demo.php
			resetParams();

			switch(responseJSON.ext){
				case 'gif':
				case 'jpg':
				case 'jpeg':
				case 'png':
				var imageHTML = '
' + fileName + ' uploaded by ' + responseJSON.uploadedBy + '
'; document.getElementById('imageThumbnails').innerHTML = document.getElementById('imageThumbnails').innerHTML + imageHTML; break; default: // Do nothing break; } if(uploader._filesInProgress < 1){ document.getElementById('message').innerHTML = "All files have been uploaded. The page will refresh itself in 10 seconds." // var t = setTimeout('location.href = location.href;', 10000) } } }); }); var uploader; // Function to update the parameters once a crop region is selected function updateParams(img, selection){ uploader.setParams({ 'x1': selection.x1, 'y1': selection.y1, 'x2': selection.x2, 'y2': selection.y2, 'cWidth': selection.width, 'cHeight': selection.height, 'oWidth': img.width, 'oHeight': img.height, 'rWidth': '300', 'rHeight': '150' }); } // Function to reset all parameters function resetParams(){ uploader.setParams({ 'x1': '0', 'y1': '0', 'x2': '300', 'y2': '150', 'cWidth': '300', 'cHeight': '150', 'oWidth': '800', 'oHeight': '600', 'rWidth': '300', 'rHeight': '150' }); }

We also made a few changes to fileuploader.js, which you can find in the source which is available for download at the end of this post. Particularly important is line number 811. We initialize the crop tool for each image that has been queued for upload and when a crop selection is made we just update the crop selection to used in our server side script using the ‘updateParams’ function.

$('#img_' + item.qqFileId).imgAreaSelect({ parent: '#cropDiv_' + item.qqFileId, x1: self._options.params.x1, y1: self._options.params.y1, x2: self._options.params.x2, y2: self._options.params.y2, persistent: true, resizable: true, onSelectChange: updateParams, parent : self._options.params.parent, minWidth: self._options.params.cWidth, minHeight: self._options.params.cHeight, aspectRatio: self._options.params.cWidth + ':' + self._options.params.cHeight, handles: true, zIndex: 1 });

On the server side we can use the parameters to crop and resize the image. Below is the code used in PHP:

// Get dimensions of the original image
list($currentWidth, $currentHeight) = getimagesize($result['path']);

// The x and y coordinates on the original image where we will begin cropping the image
$left = $_GET['x1'] * ($currentWidth / $_GET['oWidth']);
$top = $_GET['y1'] * ($currentHeight / $_GET['oHeight']);

// This will be the final size of the image (e.g. how many pixels left and down we will be going)
$cropWidth = $_GET['cWidth'] * ($currentWidth / $_GET['oWidth']);
$cropHeight = $_GET['cHeight'] * ($currentHeight / $_GET['oHeight']);

// Crop the image
$canvas = imagecreatetruecolor($cropWidth, $cropHeight);
$currentImage = imagecreatefromjpeg($result['path']);
imagecopy($canvas, $currentImage, 0, 0, $left, $top, $currentWidth, $currentHeight);
imagejpeg($canvas, $result['path'], 100);

// Get dimensions of the cropped image
list($currentWidth, $currentHeight) = getimagesize($result['path']);

// Resize the image
$canvas = imagecreatetruecolor($_GET['rWidth'], $_GET['rHeight']);
$currentImage = imagecreatefromjpeg($result['path']);
imagecopyresampled($canvas, $currentImage, 0, 0, 0, 0, $_GET['rWidth'], $_GET['rHeight'], $currentWidth, $currentHeight);
imagejpeg($canvas, $result['path'], 100);

Download the full source here.

Leave a comment

22 Comments.

  1. I’m currently trying to implement this in one of my project. I’m trying to limit the maximum number of image being upload to just 1. I set multiple: false read it in the fileuploader.js manual to the script but it stills allows me to drag and drop and upload many images…

    Also how do I go about changing the names and directory into a variable I can control say a hidden $_POST on which line is the one can i change the name and directory? I been trying to get an understanding on the whole system but I’m a still new at this so it’s taking sometime.

    I had a look at the demo at http://fineuploader.com/ and it looks like you can initiate multiple instance of the upload script on the same page with different attribute one being the file path.

    Anyways Thanks Alot for making this public!! :razz:

    • I forgot to mentioned, I am storing the image path into a database with the recordid.jpg being it’s name. Image should be overwritten if a new one has been uploaded..

      • Hi,

        Sorry for the delayed response. We will try to answer your question. Give us a day or two.

        Regards

        sapnagroup

        • Hi Andrew,

          I think restricting it to one file and also sending path is feasible and we have done it in our projects. But the programmer who did this is on leave and back only on 3rd November or so. If you can wait till then, we could possibly show you how to go about.

          Regards

          sapnagroup

  2. Everything works well but, the demo doesn’t run properly in Internet Explorer is there a fix for this? the Crop menu doesn’t appear.

    • Hi,

      Internet Explorer 8 and below definitely will not work as they have no support for html5. We are not sure if it will work Internet Explorer 9 will work. You can check that out. But it definitely works on Firefox and Chrome.

      Regards

      sapnagroup

  3. How to fix this so I can store the files in mysql?

    • Hi,

      You can do 2 things.
      - Do an fopen of that file and save the binary content in a blob field in Mysql.
      - Put an entry into Mysql and append the id to the file name. You can then move the renamed file to the desired directory.

      Hope that helps

      sapnagroup

  4. I get errors to increase upload size but I already have. I don’t see any thumbnails.
    Safari 6.0 Mac

    • Hi,

      Please can you check if the folders on the server have appropriate permissions and have enough space on the server.

      sapnagroup

  5. Is there a way to get the crop Div to show automatically, as soon as an image file is chosen, instead of clicking the crop button?

    • Hi,

      You can try calling these lines of code at the end of ‘_cropImage’.

      resetParams();
      $('#cropDiv_' + fileId).show();
      $('#img_' + fileId).imgAreaSelect({ parent: '#cropDiv_' + fileId, x1: self._options.params.x1, y1: self._options.params.y1, x2: self._options.params.x2, y2: self._options.params.y2, persistent: true, resizable: true, onSelectChange: updateParams, parent : self._options.params.parent, minWidth: self._options.params.cWidth, minHeight: self._options.params.cHeight, aspectRatio: self._options.params.cWidth + ':' + self._options.params.cHeight, handles: true, zIndex: 1 });

      A warning though; if you upload multiple images at one go, then you’ll have multiple crop DIVs showing all at the same time. A little bit of inginutiy and you’ll be able to overcome this problem. :)

      Hope this helps.

  6. how can i render the crop area right after push upload button without crop link fileTemplate
    thanks

  7. I cannot find any line in any of the files with “_cropImage”. What file is that located in to append?

    By default, when I view the index page, I get this:

    “; echo “”; echo “”; echo “”.$file.”"; $dir = ‘uploads/’.session_id(); $path = $dir.’/’.$file; echo

    Additionally images in that string are red x’s named /%22images/icons/%22.$img.%22.png/%22

    The “Download” url is /%22%22.$path.%22/%22

    When I try to upload any file, I get the error:

    increase post_max_size and upload_max_filesize to 10M

    My server is running PHP Version 5.3.6, thanks.

    • Hi Jeffery,

      It’s line 406 in ‘fileuploader.js’.

      Not sure about the other errors you are encountering. Please can you give us some more information.

      For the errors, add these lines to you .htaccess file:

      SecFilterScanPOST Off
      php_value register_globals 1
      php_value memory_limit 128M
      php_value post_max_size 500M
      php_value upload_max_filesize 500M
      php_value max_execution_time 500
      php_value max_file_uploads 50
      php_value max_input_time 500

      Regards,
      sapnagroup

  8. Hi,

    How can we get the image as per selected area. In upload.php file, you have given static width(75). when we are cropping the image its making the thumbnail as per static width(75). can we make this dynamic( as per selected area) ?

    thanks

    • Hi Rock,

      You can pass the dimension as the response at the end of upload.php and get the value back in the onComplete event as responseJSON.yourVariable. This can then be used for the dimensions in the thumbnail.

      Please let us know if this help

      Regards,
      sapnagroup

      • Hi,

        thanks for your help. I have another issue, I am getting this message when refreshing the page without cropping the image: “This page is asking you to confirm that you want to leave – data you have entered may not be saved.” How can i remove this message. I don’t want to show this message.

        thanks

        • Hi Rock,

          This is a standard message that appears when any process are in process and the user tries to exit the page. Not sure if we can remove this.

          Regards,
          sapnagroup

  9. Hi,

    I want to save image and crop image by post method instead of ajax. So please suggest me how I can do this.

    thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

*


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>