13

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.

Ken
  • 323
  • 1
  • 3
  • 13
  • 1
    It should be possible with HTML5. http://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/ – Nisd Jul 01 '13 at 11:08

3 Answers3

10

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) {

        }
      });
Ken
  • 323
  • 1
  • 3
  • 13
  • Just out of curiosity, a standard HTTP/POST using a form with a (hidden) field containing the base64 data of the image didn't work ? – Alex Aug 30 '13 at 12:45
3

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!

Community
  • 1
  • 1
feng
  • 27
  • 2
1

This might be an old post but if you found this answer (like me), you might want to know that Parse allows now to crop images server side.

For the latest code you should refer to their documentation: https://www.parse.com/docs/cloud_modules_guide#images

Parse Image Object (from Parse documentation):

var Image = require("parse-image");

Parse.Cloud.httpRequest({
  url: object.get("profilePhoto").url(),
  success: function(response) {
    // The file contents are in response.buffer.
    var image = new Image();
    return image.setData(response.buffer, {
      success: function() {
        console.log("Image is " + image.width() + "x" + image.height() + ".");
      },
      error: function(error) {
        // The image data was invalid.
      }
    })
  },
  error: function(error) {
    // The networking request failed.
  }
});

Crop Image (from Parse documentation):

// Crop the image to the rectangle from (10, 10) to (30, 20).
image.crop({
  left: 10,
  top: 10,
  right: 30,
  bottom: 20,
  success: function(image) {
    // The image was cropped.
  },
  error: function(error) {
    // The image could not be cropped.
  }
});

You can also scale, change image format, and create thumbnails.

Lex L.
  • 603
  • 6
  • 7