Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crop and upload image on client-side without server-side code involve

As title said. The requirement is to be able to crop an image before uploading the cropped image to the server. All the work should be done on the client-side. I have heard of the method to crop the image on the server and save it altogether.

But as i use Parse.com service. There is no supported for image manipulation on the server-side so i need to process it locally and upload the finished image directly to Parse.com service.

Example code would be very helpful. Thanks.

like image 899
Ken Avatar asked Jul 01 '13 11:07

Ken


2 Answers

The solution i used:

First I use a 3rd party javascript library to select the crop area like jCrop. Once i got the coordinates (x1,x2,y1,y2), i draw a copy of an image to a canvas.

          var canvas = document.getElementById('drawcanvas'); 
          var context = canvas.getContext('2d');
          canvas.width = canvas.width; // clear canvas
          var imageObj = new Image();
          imageObj.onload = function() {
            // draw cropped image
            // ...

            context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, sourceWidth, sourceHeight);

            var dataURL = canvas.toDataURL();
          };
          imageObj.src = // image url

After i drew the canvas, i converted the canvas to a DataURL which is in base64 format. Once i've got the DataURL, i use this function i found from the internet where it converts the DataURL to raw binary data.

DataURLConverter: function(data) {
        // convert base64 to raw binary data held in a string
        // doesn't handle URLEncoded DataURIs
        var byteString = atob(data.split(',')[1]);

        // separate out the mime component
        var mimeString = data.split(',')[0].split(':')[1].split(';')[0]

        // write the bytes of the string to an ArrayBuffer
        var ab = new ArrayBuffer(byteString.length);
        var ia = new Uint8Array(ab);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
            return ia;
}

When we got the binary data, we then upload this directly to Parse.com. Upload to parse with 'ia' as a data

 var serverUrl = 'https://api.parse.com/1/files/' + fileName;
      $.ajax({
        type: "POST",
        beforeSend: function(request) {
          request.setRequestHeader("X-Parse-Application-Id", "App id");
          request.setRequestHeader("X-Parse-REST-API-Key", "API Key");
          request.setRequestHeader("Content-Type", "File type");
        },
        url: serverUrl,
        data: ia,
        processData: false,
        contentType: false,
        success: function(data) {

        },
        error: function(data) {

        }
      });
like image 125
Ken Avatar answered Nov 03 '22 23:11

Ken


OK, I finally made it!!! after searching for a whole day!! Even now parse propose server side cropping, it's still interesting to have client side resizing.

Check this: HTML5 Pre-resize images before uploading

Justin Levene's correction works really good! But to work with Parse.com, you need to use

new Parse.File(name, {base64: somebase64string});

These codes works for me (for exemple, I uploaded a 2M photo, the re-sized photo would be like 150k):

var dataurl = canvas.toDataURL("image/jpeg");

            var name = "image.jpg";
            var parseFile = new Parse.File(name, {base64: dataurl.substring(23)});

            parseFile.save().then(function() { ....

the "23" is all the letters before the real base64 string. the result of dataurl is "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2......", we just need the part begin by "/9j/"

Good luck!

like image 34
feng Avatar answered Nov 03 '22 23:11

feng