Resizing Image Taken Using Camera in Cordova/PhoneGap App

| | 3 min read

One of our app utilize photographs taken using device camera. It was required to resize the taken image. After searching, it is realized that there is no native cordova plugin for image manipulations on different mobile platforms. It is also realized that canvas element of HTML can be utilized for image manipulations. There are numerous libraries that makes manipulations possible using canvas, all of them were supposed use from UI or required user facing canvas. But it was not the case in our app.

I implemented logic for resizing of image from camera completely as background operation. Following is that logic used to resize an image.

  • Create HTMLImageElement object using the simple constructor Image() and set image URL from the file path we have.
  • Once image is loaded, create a canvas object using document.createElement('canvas') with size we are going to resize image to.
  • Get 2D rendering context object for the canvas.
  • Draw the image on canvas using 2D context object to fill the canvas.
  • Get image data as data URL.
  • Convert data URL to binary data and write to a file.

After invoking camera app, we get file URI to the image file as shown below:


navigator.camera.getPicture(
  function(imageURI) {

  },
  function(err) {

  }
);

We can use imageURI to create the image object. And perform the resize logic to get resized image data. Here is the function receiving image URI and giving resized image data.


function resizeImage(longSideMax, url, callback) {
  var tempImg = new Image();
  tempImg.src = url;
  tempImg.onload = function() {
    // Get image size and aspect ratio.
    var targetWidth = tempImg.width;
    var targetHeight = tempImg.height;
    var aspect = tempImg.width / tempImg.height;

    // Calculate shorter side length, keeping aspect ratio on image.
    // If source image size is less than given longSideMax, then it need to be
    // considered instead.
    if (tempImg.width > tempImg.height) {
      longSideMax = Math.min(tempImg.width, longSideMax);
      targetWidth = longSideMax;
      targetHeight = longSideMax / aspect;
    }
    else {
      longSideMax = Math.min(tempImg.height, longSideMax);
      targetHeight = longSideMax;
      targetWidth = longSideMax * aspect;
    }

    // Create canvas of required size.
    var canvas = document.createElement('canvas');
    canvas.width = targetWidth;
    canvas.height = targetHeight;

    var ctx = canvas.getContext("2d");
    // Take image from top left corner to bottom right corner and draw the image
    // on canvas to completely fill into.
    ctx.drawImage(this, 0, 0, tempImg.width, tempImg.height, 0, 0, targetWidth, targetHeight);

    callback(canvas.toDataURL("image/jpeg"));
  };
}

First parameter is the maximum length of longer size. For example, if given 1000, then image will have either width or height of 1000 pixels, depending on longer side of source image.
If longer side of source image is less than given longSizeMax then long side length of original image will considered instead. Other side length will be calculated to keep the aspect ratio. The callback will be called with data URL as parameter.

To know more about data URL you can refer Wikipedia article https://en.wikipedia.org/wiki/Data_URI_scheme

Once we have data URL, we can convert it to binary or store directly on database table fields as they are strings.

Here is the function that can be used to convert data URL string to binary object.


/**
 * Credit: http://stackoverflow.com/a/5100158/499137
 */
function dataURItoBlob(dataURI) {
    // convert base64/URLEncoded data component to raw binary data held in a string
    var byteString;
    if (dataURI.split(',')[0].indexOf('base64') >= 0)
        byteString = atob(dataURI.split(',')[1]);
    else
        byteString = unescape(dataURI.split(',')[1]);

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

    // write the bytes of the string to a typed array
    var ia = new Uint8Array(byteString.length);
    for (var i = 0; i  byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ia], {type:mimeString});
}

You can write binary object directly to file to create the final resized image file.

If you face any doubts, please feel free to get in touch with us.