Loading Images with websockets in nodejs

Reading a lot recently about mobile optimization, I have started doing some HTML5 prototyping using non-traditional methods to build mobile web apps.

One of the big bottle necks when loading websites is loading multiple images over HTTP, both the HTTP overhead and the browser connection limits make this process slow.

One of the optimization methods used in mobile apps is inline the images in the CSS file base64 encoded. I extended this concept and using node.js server, I get the images, encode them into base64, and via client side javascript inject into the dom. ... adding another spin and inject them into the HTML5 canvas element.

What actually took me the longest was figuring out how to load the image server-side and and encode it into base64. A lot of people seen to have issues with that, so here is the working solution:

var http = require('http');

// HTTP content getter.
exports.get = function (settings) {

  if (!settings.port) {
    port = 80;
  }

  try {

    var request = http.request({
      host: settings.host,
      port: settings.port,
      method: 'GET',
      path: settings.path
    });

    request.on('response', function (response) {
      response.setEncoding('binary');
      var body = '';

      response.on('data', function (chunk) {
        body += chunk;
      });

      response.on('end', function () {

        var base64 = new Buffer(body, 'binary').toString('base64');

        var data_uri_prefix = "data:" + response.headers["content-type"] + ";base64,";

        try {
          settings.callBack({
            isSucessful: true,
            body: data_uri_prefix + base64
          });
        } catch (ex) {
          settings.callBack({
            isSucessful: false,
            ex: ex
          });
        }
      });
    });

    request.end();
  } catch (ex) {
    settings.callBack({
      isSucessful: false,
      ex: ex
    });
  }
};

And here is how you can use the code:

loader.get({
  host: 'webcam.novy-jicin.cz',
  path: '/record/current.jpg',
  callBack: function (image) {

  }
});

The next piece is using the websocekts to push it to the client. This is fairly simple, just set up a listener, with the "on" and return the encoded string.

socket.on('imageRequest', function (obj, callBack) {
  loader.get({
    host: 'webcam.novy-jicin.cz',
    path: '/record/current.jpg',
    callBack: callBack
  });
});

And now the client:

var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();

imageObj.onload = function() {
  context.drawImage(imageObj, 0, 0);
};

var refreshImage = function () {
  socket.emit('imageRequest', '', function (data) {
    imageObj.src = data;
    refreshImage();
  });
};

// Start refresher.
refreshImage();

In my example, I am hitting a webcam in a loop of my home town, so that it's simulating a video stream.