Bytes in the Cloud

We launched Cloud Code earlier to help you write backend logic more easily. Since then, we have added features to enable more use cases. Today, we are adding support for a JavaScript Buffer Cloud Module for manipulating bytes in Cloud Code, performing string encoding, and Base64-encoding binary data. This API is a subset of the Node.js buffer API. The following example converts a Base64-encoded string to binary bytes, appends a unicode smiley character, and then interprets the resulting bytes as a UTF-8 encoded string.

var Buffer = require('buffer').Buffer;

Parse.Cloud.define('smile', function(request, response) {
  var base64String = 'UGFyc2U=';
  var buffer1 = new Buffer(base64String, 'base64');
  var buffer2 = new Buffer(' \u263A', 'utf8');
  var buffer3 = Buffer.concat([buffer1, buffer2]);
  response.success(buffer3.toString('utf8'));
});

Calling this Cloud Function returns the following JSON: {"result":"Parse ☺"}

Parse engineer Bryan Klimt decided to do something even more fun with the Buffer Cloud Module. He wrote a Cloud Function to construct a gradient sphere image, and displayed the image using the Parse JavaScript SDK. The Cloud Function manipulates bytes in Buffer objects to construct the gif image, and then returns the image as a Base64-encoded string.

var _ = require('underscore');
var Buffer = require('buffer').Buffer;

Parse.Cloud.define('gif', function(request, response) {
  var fgcolor = request.params.fgcolor || [0, 0, 0];
  var bgcolor = request.params.bgcolor || [255, 255, 255];

  var magic = new Buffer('GIF89a', 'utf8');
  var logicalScreenDescriptor = new Buffer([64, 0, 64, 0, 0xF6, 0, 0]);

  var palette = new Buffer(128 * 3);
  _.times(128, function(i) {
    var red = Math.floor((i/127) * fgcolor[0] + (1 - i/127) * bgcolor[0]);
    var green = Math.floor((i/127) * fgcolor[1] + (1 - i/127) * bgcolor[1]);
    var blue = Math.floor((i/127) * fgcolor[2] + (1 - i/127) * bgcolor[2]);
    palette.writeUInt8(red, i * 3);
    palette.writeUInt8(green, i * 3 + 1);
    palette.writeUInt8(blue, i * 3 + 2);
  });

  var imageDescriptor = new Buffer([0x2C, 0, 0, 0, 0, 64, 0, 64, 0, 0, 7]);

  var pixels = new Buffer(64 * 66);
  _.times(64, function(row) {
    pixels.writeUInt8(65, row * 66);  // 65 bytes per row.
    pixels.writeUInt8(0x80, row * 66 + 1);  // Clear compression table.
    _.times(64, function(column) {
      var distance = Math.sqrt((row - 32) * (row - 32) + (column - 32) * (column - 32));
      var color = Math.max(0, 127 - Math.floor((distance / 32) * 127));
      pixels.writeUInt8(color, row * 66 + column + 2);
    });
  });

  var trailer = new Buffer([0x3B]);
  var data = Buffer.concat([magic, logicalScreenDescriptor, palette, imageDescriptor, pixels, trailer]);

  response.success(data.toString('base64'));
});

The client browser code uses the Parse JavaScript SDK to call the Cloud Function, and show the Base64-encoded image on the web page.

<html>
  <head>
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://www.parsecdn.com/js/parse-1.2.1.min.js"></script>
    <script>
      $(function() {
        Parse.initialize("APP_ID", "JS_API_KEY");
        Parse.Cloud.run("gif", {
          fgcolor: [0, 0, 255],
          bgcolor: [255, 255, 255]
        }, {
          success: function(result) {
            var url = "data:image/gif;base64," + result;
            $("#image").html('<img src="' + url + '" />')
          },
          error: function(error) {
            console.error(error);
          }
        });
      });
    </script>
  </head>
  <body>
    <div id="image"></div>
  </body>
</html>

Opening the web page shows the image generated by Bryan’s Cloud Function, as shown below.

sphere

Stanley Wang
February 22, 2013
blog comments powered by Disqus

Comments are closed.

Archives

Categories

RSS Feed Follow us Like us