Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cropping images in the browser BEFORE the upload [closed]

Many libraries I have found, like Jcrop, do not actually do the cropping, it only creates an image cropping UI. It then depends on the server doing the actual cropping.

How can I make the image cropping client-side by using some HTML5 feature without using any server-side code.

If yes, are there some examples or hints?

like image 596
Lorraine Bernard Avatar asked Oct 04 '12 13:10

Lorraine Bernard


People also ask

What is the process of trimming away unwanted areas of the image called?

Cropping is the removal of unwanted outer areas from a photographic or illustrated image.

How do I crop a picture without losing it size?

With Photoshop, you can resize an image without losing quality by using the "Image Size" dialog box. A screenshot of Photoshop's Image Size dialog box, taken from Adobe's official documentation. In the "Image Size" dialog box, you can change the width and height of the image. You can also change the resolution.


2 Answers

Yes, it can be done.
It is based on the new html5 "download" attribute of anchor tags.
The flow should be something like this :

  1. load the image
  2. draw the image into a canvas with the crop boundaries specified
  3. get the image data from the canvas and make it a href attribute for an anchor tag in the dom
  4. add the download attribute (download="desired-file-name") to that a element That's it. all the user has to do is click your "download link" and the image will be downloaded to his pc.

I'll come back with a demo when I get the chance.

Update
Here's the live demo as I promised. It takes the jsfiddle logo and crops 5px of each margin.
The code looks like this :

var img = new Image(); img.onload = function(){     var cropMarginWidth = 5,         canvas = $('<canvas/>')                     .attr({                          width: img.width - 2 * cropMarginWidth,                          height: img.height - 2 * cropMarginWidth                      })                     .hide()                     .appendTo('body'),         ctx = canvas.get(0).getContext('2d'),         a = $('<a download="cropped-image" title="click to download the image" />'),         cropCoords = {             topLeft : {                 x : cropMarginWidth,                 y : cropMarginWidth              },             bottomRight :{                 x : img.width - cropMarginWidth,                 y : img.height - cropMarginWidth             }         };      ctx.drawImage(img, cropCoords.topLeft.x, cropCoords.topLeft.y, cropCoords.bottomRight.x, cropCoords.bottomRight.y, 0, 0, img.width, img.height);     var base64ImageData = canvas.get(0).toDataURL();       a         .attr('href', base64ImageData)         .text('cropped image')         .appendTo('body');      a         .clone()         .attr('href', img.src)         .text('original image')         .attr('download','original-image')         .appendTo('body');      canvas.remove(); } img.src = 'some-image-src'; 

Update II
Forgot to mention : of course there is a downside :(.
Because of the same-origin policy that is applied to images too, if you want to access an image's data (through the canvas method toDataUrl).
So you would still need a server-side proxy that would serve your image as if it were hosted on your domain.

Update III Although I can't provide a live demo for this (for security reasons), here is a php sample code that solves the same-origin policy :

file proxy.php :

$imgData = getimagesize($_GET['img']); header("Content-type: " . $imgData['mime']); echo file_get_contents($_GET['img']);   

This way, instead of loading the external image direct from it's origin :

img.src = 'http://some-domain.com/imagefile.png'; 

You can load it through your proxy :

img.src = 'proxy.php?img=' + encodeURIComponent('http://some-domain.com/imagefile.png');   

And here's a sample php code for saving the image data (base64) into an actual image :

file save-image.php :

$data = preg_replace('/data:image\/(png|jpg|jpeg|gif|bmp);base64/','',$_POST['data']); $data = base64_decode($data); $img = imagecreatefromstring($data);  $path = 'path-to-saved-images/'; // generate random name $name  = substr(md5(time()),10); $ext = 'png'; $imageName = $path.$name.'.'.$ext;  // write the image to disk imagepng($img,  $imageName); imagedestroy($img); // return the image path echo $imageName; 

All you have to do then is post the image data to this file and it will save the image to disc and return you the existing image filename.

Of course all this might feel a bit complicated, but I wanted to show you that what you're trying to achieve is possible.

like image 50
gion_13 Avatar answered Oct 05 '22 18:10

gion_13


The Pixastic library does exactly what you want. However, it will only work on browsers that have canvas support. For those older browsers, you'll either need to:

  1. supply a server-side fallback, or
  2. tell the user that you're very sorry, but he'll need to get a more modern browser.

Of course, option #2 isn't very user-friendly. However, if your intent is to provide a pure client-only tool and/or you can't support a fallback back-end cropper (e.g. maybe you're writing a browser extension or offline Chrome app, or maybe you can't afford a decent hosting provider that provides image manipulation libraries), then it's probably fair to limit your user base to modern browsers.

EDIT: If you don't want to learn Pixastic, I have added a very simple cropper on jsFiddle here. It should be possible to modify and integrate and use the drawCroppedImage function with Jcrop.

like image 21
apsillers Avatar answered Oct 05 '22 18:10

apsillers