Appcelerator Titanium: Scaling and cropping images

At the time of writing Titanium is at: 3.3.0 GA

In the project I'm supporting we juggle with camera shots like crazy. One of the recent requests from the client was to show square thumbnails in the list of taken pictures. While the requirement itself is pretty reasonable, Titanium doesn't make our life easier.

It's easy to hack resizing with ImageView that is given the image and set to the known width / height. You then save it to the blob and off you go.

The harder it was to make it actually crop the image with unknown dimensions (thanks to device resolution diversity) to 96x96 thumbnail. Here's how I did it.

I've started with nesting image views inside other views, but that led nowhere. Finally I came across one old module -- ti.imagefactory -- stuck somewhere in the August of 2013 in its development. Even though it's quite old, it still has got everything we need -- resizing and cropping.

Here's how the end result looks:

// Target image dimensions
var w = 96, h = 96;

// Loading the module
var IF = require('ti.imagefactory');

// Getting file name like "UUID-<width>x<height>" and
// matching it to grab the width / height
var id       = photo.imageId,
    match    = /^.*-(\d+)x(\d+)$/.exec(id);

// Reading the file from the storage
var file     = FileStorage.getFile(id),
    img      = file.read(),
    finished = null;

// We are storing image dimensions in the file name
// since Ti doesn't recognize loaded Blobs as images
// all too well.
if (match != null) {
  var iw = parseInt(match[1]),
      ih = parseInt(match[2]),
      tw = iw < ih ? w : iw * h / ih,
      th = iw < ih ? ih * w / iw : h,
      resized = IF.imageAsResized(img, { width: tw, height: th });

  finished = IF.imageAsCropped(resized, { width: w, height: h });      
} else {
  finished = img;
}

Here, if we don't have image sizes in the file name or they are "0" for some reason, we just let the image stretch itself. Ugly, but yet better than nothing. Normally, we don't have this issue. It's just a safety net.

Another note, that imageAsCropped isn't given the x/y offset and so it will automatically gravitate towards the center of the image. Sweet.

I saw a ton of discussions on the subject and figured I'd share. Hope you enjoyed this bit.

comments powered by Disqus