none
Create Thumbnail Image using Windows Azure Blob Storage

    Question

  • Hello,

    I posted this question on stackoverflow but nobody from Microsoft seem to be replying, so I thought I would post it here because I'm stuck and cant move forward with my Node.js application running on Windows Azure Websites.

    http://stackoverflow.com/questions/15450102/create-thumbnail-image-using-windows-azure-blob-storage

    Essentially I am trying to read an image from Facebook (video thumbnail) and uploading it and storing it in Windows Azure blob storage.

    Any help from any who knows Windows Azure storage and node.js would be great!

    Regards,
    Rob Kara

    Wednesday, March 20, 2013 2:05 AM

Answers

  • It took me a while but I got this working using this code (I borrowed a method to get the right base64 encoding and one to put it in the correct stream format).

    var http = require('http'),
    	util = require('util'),
    	azure = require('azure');
    
        MemoryStream = require('memorystream');
    
    var stream = require('stream')	
    
    var blobService = azure.createBlobService('valeryjacobs', 'w5kNlXuwyWbeQ/L3TGguPMViL/YOU WISHFWSkHBfnN/XYR5QoUT2b8ujcWcw==');
    
    
    var loadBase64Image = function (url, callback) {
        // Required 'request' module
        var request = require('request');
    
        // Make request to our image url
        request({url: url, encoding: null}, function (err, res, body) {
            if (!err && res.statusCode == 200) {
                // So as encoding set to null then request body became Buffer object
                var base64prefix = 'data:' + res.headers['content-type'] + ';base64,'
                    , image = body.toString('base64');
                if (typeof callback == 'function') {
                    callback(image, base64prefix);
                }
            } else {
                throw new Error('Can not download image');
            }
        });
    };
    
    loadBase64Image('http://vthumb.ak.fbcdn.net/hvthumb-ak-ash4/245861_10151489861249640_10151489859214640_51096_2171_t.jpg', function (image, prefix) {
        var fileBuffer = new Buffer(image, 'base64');
    	    //console.log(memStream.toString());
    		//console.log('pipe end');
    		blobService.createBlockBlobFromStream('node-demo-container', 'picture.jpg', new ReadableStreamBuffer(fileBuffer), fileBuffer.length, { contentTypeHeader:'image/jpg' },function(error)
    		{
    		//console.log('api result');
    			if(!error)
    			{
    		console.log('ok');
    			}
    			else
    			{
    			console.log(error);
    			}
    			
    		});
    });
    
    var ReadableStreamBuffer = function(fileBuffer) {
    
        var that = this;
        stream.Stream.call(this);
        this.readable = true;
        this.writable = false;
     
        var frequency = 50;
        var chunkSize = 1024;
        var size = fileBuffer.length;
        var position = 0;
     
        var buffer = new Buffer(fileBuffer.length);
        fileBuffer.copy(buffer);
     
        var sendData = function() {
            if(size === 0) {
                that.emit("end");
                return;
            }
    
            var amount = Math.min(chunkSize, size);
            var chunk = null;
            chunk = new Buffer(amount);
            buffer.copy(chunk, 0, position, position + amount);
                position += amount;
            size -= amount;
            
            that.emit("data", chunk);
        };
     
        this.size = function() {
            return size; 
        };
     
        this.maxSize = function() {
            return buffer.length;
        };
     
        this.pause = function() {
            if(sendData) {
                clearInterval(sendData.interval);
                delete sendData.interval;
            }
        };
     
        this.resume = function() {
            if(sendData && !sendData.interval) {
                sendData.interval = setInterval(sendData, frequency);
            }
        };
     
        this.destroy = function() {
            that.emit("end");
            clearTimeout(sendData.interval);
            sendData = null;
            that.readable = false;
            that.emit("close");
        };
     
        this.setEncoding = function(_encoding) {
        };
     
        this.resume();
    };
    util.inherits(ReadableStreamBuffer, stream.Stream);
    


    Never miss the latest Windows Azure news on http://blogs.msdn.com/b/windowsazure/

    • Marked as answer by paz224 Friday, March 22, 2013 1:14 PM
    Wednesday, March 20, 2013 10:28 PM

All replies

  • Did you try the 'azure' NPM package? It has a blob client build in.

    The code will like this:

    var blobService = azure.createBlobService('[STORAGEACCOUNTNAME]', '[ACCESSKEY]');
    
    blobService.createBlockBlobFromFile('[CONTAINERNAME]' , [BLOBNAME], [FILEPATH] , function(error)
    {
      if (!error) 
      {
        console.log("File uploaded to Azure.")
      }
    });
    Alternatively you can use createBlockBlobFromStream() if you don't want to use the filesystem on your server.

    Never miss the latest Windows Azure news on http://blogs.msdn.com/b/windowsazure/



    Wednesday, March 20, 2013 5:49 AM
  • Hi Valery,

    Yes thats installed, and in the example:

    var azure = require('azure');

    but its to do with using this module:

    var stream
    = require('stream');

    and calling this method of the azure module to store it in azure:

    bs.createBlockBlobFromStream(config.imageContainer, uuid().replace(/-/gi, "").toLowerCase() + '.jpg', imageStream, decodedImage.length, options, function(error, blobResult, response) {
        if (error)
            console.log('got error = ' + JSON.stringify(error) + '\n');

        if (blobResult)
            console.log('blobResult = ' + JSON.stringify(blobResult) + '\n');

        if (response)
            console.log('response = ' + JSON.stringify(response) + '\n');

        // now store in Azure blob storage
        callback();
    });

    this method requires an imageStream object but the code hangs and the image is not stored in azure.

    I'm not sure why the code is hanging but I am guessing it has something to do with how I've structured the events e.g. imageStream.end and having
    bs.createBlockBlobFromStream called after the imageStream.end event. I've tried putting the call to azure within the imageStream.end event but process still hung and no images were created on the server.

    If you could perhaps look at my code and give your input it would be much appreciated.

    Cheers
    Rob



    Wednesday, March 20, 2013 8:04 AM
  • Did you use the debugger to get to the exact point of failure?

    From the code you posted I can really tell the nesting level of functions involved. Does is look a bit like this?:

    var out  = fs.createWriteStream(uploadDir + resourceDir + '/images/' + className + '.png')
        , stream    = canvas.createPNGStream();
    
        stream.on('data', function(chunk){
          out.write(chunk);
        });
    
        stream.on('end', function(){
            
    //upload to azure here.
    
    
               });
    BTW Fiddler might give us some insight as to whether or not a request to storage is made.


    Never miss the latest Windows Azure news on http://blogs.msdn.com/b/windowsazure/


    Wednesday, March 20, 2013 8:38 AM
  • Thanks for replying Valery,

    In your code your making a call to canvas.createPNGStream();

    are you referring to the node canvas module located on github?

    https://github.com/LearnBoost/node-canvas

    or are you referring to another module that I should know about?

    I havent tried your code as yet still trying to figure out what you mean by canvas, I'm reading through the github documentation about canvas and will reply back shortly.

    Also I am not using the fs (file system) module as I am getting the image via GET from a web resource in this case Facebook with a url similar to:

    http://vthumb.ak.fbcdn.net/hvthumb-ak-ash4/245861_10151489861249640_10151489859214640_51096_2171_t.jpg

    The image is fetched and then using the stream object because bs.createBlockBlobFromStream requires the blob to be of type stream...
    • Edited by paz224 Wednesday, March 20, 2013 4:08 PM
    Wednesday, March 20, 2013 4:00 PM
  • Sorry if I confused you, I just picked a sample from somewhere that created an image stream. I wasn't suggesting to use this specific library to create the stream, assuming you already have a valid stream and are having difficulties uploading it to blob storage.

    I will try this a soon as I get my hands on my development machine.

    In the meanitime you might take a look at a demo app I made recently to showcase the upload of a file to Azure blob storage using the filesystem,  (and a package called 'formidable' that uploads files from the browser to the node server, after te upload to the node server the files are forwarded to Azure blobstorage). Maybe there is something wrong with you container, is it public?

    Sorry for the crappy code, it does work though.

    var azure = require('azure');
    var blobService = azure.createBlobService('[accountname]', 'w5kNlXuwyWbeQ/L3TGguPMViL YOU WHISH EXFFu5tqmjFWSkHBfnN/XYR5QoUT2b8ujcWcw==');
    var each = require('each');
    var http = require('http'),
        util = require('util'),
        formidable = require('formidable'),
        fs = require('fs'),
        server;
    var mysocket;
    
    blobService.createContainerIfNotExists('node-demo-container'
        , { publicAccessLevel: 'blob' }
        , function (error) {
            if (!error) {
                // Container exists and is public
            }
        });
    
        server = http.createServer(function (req, res) {
            if (req.url == '/') 
    		{
                fs.readFile('index.html',
    			function (err, data) 
    			{
    				  if (err) 
    				  {
    					  res.writeHead(500);
    					  return res.end('Error loading index.html');
    				  }
    
    				  res.writeHead(200);
    				  res.end(data);
    			});
            } 
            else if (req.url == '/upload') 
    		{
                var form = new formidable.IncomingForm(),
                files = [],
                fields = [],
                keepExtensions = false;
    
                form.uploadDir = '/temp';
    
                form.on('field', function (field, value) 
    			{
    				// console.log(field, value);
    				fields.push([field, value]);
                }).on('file', function (field, file) 
    			{
    			  // console.log(field, file);
    			  files.push([field, file]);
    			}).on('end', function () 	
    			{
    				// console.log('-> upload done');
    				res.writeHead(200, { 'content-type': 'text/plain' });
    				//res.write('received fields:\n\n '+util.inspect(fields));
    				res.write('\n\n');
    				//res.end('received files:\n\n '+util.inspect(files));
    
    				each(files).on('item', function (element, index, next) 
    				{
    					//mysocket.broadcast("uploading file to azure");
    					console.log('element: ', element.valueOf('path'));
    
    					blobService.createBlockBlobFromFile('node-demo-container'
    						 , element[1].name
    						 , element[1].path
    						 , function (error) {
    							 if (!error) {
    								 console.log("File uploaded to Azure.")
    								 // File has been uploaded
    							 }
    						 });
    
    					setTimeout(next, 500);
    				}).on('both', function (err) 
    				{
    					if (err) {
    						console.log(err.message);
    					} else {
    						console.log('Done');
    					}
    				});
    		  });
            form.parse(req);
            } else {
                res.writeHead(404, { 'content-type': 'text/plain' });
                res.end('404');
            }
        });
    
    var io = require('socket.io').listen(server);
    
    server.listen(8183);
    
    io.sockets.on('connection', function (socket) {
        mysocket = socket;
    
        mysocket.emit('news', { hello: 'world' });
        mysocket.on('my other event', function (data) {
            console.log(data);
        });
    });
    
    console.log('listening on http://localhost:' + 8183 + '/');
    
    
    p.s. Socket.io was put in there to have the client show upload progress info, but as you can see I never finished this.


    Never miss the latest Windows Azure news on http://blogs.msdn.com/b/windowsazure/


    Wednesday, March 20, 2013 4:25 PM
  • It took me a while but I got this working using this code (I borrowed a method to get the right base64 encoding and one to put it in the correct stream format).

    var http = require('http'),
    	util = require('util'),
    	azure = require('azure');
    
        MemoryStream = require('memorystream');
    
    var stream = require('stream')	
    
    var blobService = azure.createBlobService('valeryjacobs', 'w5kNlXuwyWbeQ/L3TGguPMViL/YOU WISHFWSkHBfnN/XYR5QoUT2b8ujcWcw==');
    
    
    var loadBase64Image = function (url, callback) {
        // Required 'request' module
        var request = require('request');
    
        // Make request to our image url
        request({url: url, encoding: null}, function (err, res, body) {
            if (!err && res.statusCode == 200) {
                // So as encoding set to null then request body became Buffer object
                var base64prefix = 'data:' + res.headers['content-type'] + ';base64,'
                    , image = body.toString('base64');
                if (typeof callback == 'function') {
                    callback(image, base64prefix);
                }
            } else {
                throw new Error('Can not download image');
            }
        });
    };
    
    loadBase64Image('http://vthumb.ak.fbcdn.net/hvthumb-ak-ash4/245861_10151489861249640_10151489859214640_51096_2171_t.jpg', function (image, prefix) {
        var fileBuffer = new Buffer(image, 'base64');
    	    //console.log(memStream.toString());
    		//console.log('pipe end');
    		blobService.createBlockBlobFromStream('node-demo-container', 'picture.jpg', new ReadableStreamBuffer(fileBuffer), fileBuffer.length, { contentTypeHeader:'image/jpg' },function(error)
    		{
    		//console.log('api result');
    			if(!error)
    			{
    		console.log('ok');
    			}
    			else
    			{
    			console.log(error);
    			}
    			
    		});
    });
    
    var ReadableStreamBuffer = function(fileBuffer) {
    
        var that = this;
        stream.Stream.call(this);
        this.readable = true;
        this.writable = false;
     
        var frequency = 50;
        var chunkSize = 1024;
        var size = fileBuffer.length;
        var position = 0;
     
        var buffer = new Buffer(fileBuffer.length);
        fileBuffer.copy(buffer);
     
        var sendData = function() {
            if(size === 0) {
                that.emit("end");
                return;
            }
    
            var amount = Math.min(chunkSize, size);
            var chunk = null;
            chunk = new Buffer(amount);
            buffer.copy(chunk, 0, position, position + amount);
                position += amount;
            size -= amount;
            
            that.emit("data", chunk);
        };
     
        this.size = function() {
            return size; 
        };
     
        this.maxSize = function() {
            return buffer.length;
        };
     
        this.pause = function() {
            if(sendData) {
                clearInterval(sendData.interval);
                delete sendData.interval;
            }
        };
     
        this.resume = function() {
            if(sendData && !sendData.interval) {
                sendData.interval = setInterval(sendData, frequency);
            }
        };
     
        this.destroy = function() {
            that.emit("end");
            clearTimeout(sendData.interval);
            sendData = null;
            that.readable = false;
            that.emit("close");
        };
     
        this.setEncoding = function(_encoding) {
        };
     
        this.resume();
    };
    util.inherits(ReadableStreamBuffer, stream.Stream);
    


    Never miss the latest Windows Azure news on http://blogs.msdn.com/b/windowsazure/

    • Marked as answer by paz224 Friday, March 22, 2013 1:14 PM
    Wednesday, March 20, 2013 10:28 PM