What can you learn from this post?

This post talks about how to generate a snapshot image from canvas and upload to Node.js, and then save to BOS. Since BOS has limit for file name, we first save it locally on Node.js server and then upload to BOS.

Generate Images from Canvas

canvas.toDataURL();

This generates a path starting with data:image/png;base64, and if you enters this path in Web Browsers, it gives the image generated.

Upload to Node.js Server

I use jQuery to post the data url to Node.js.

$.post('http://localhost/...', {
    img: canvas.toDataURL()
});

On the server side, we use req.body.img to get the posted parameter.

exports.upload = function(req, res) {
    var dataUrl = req.body.img;
};

Since Node.js has a limit for post data, we need to set the limit to be large enough in app.js.

var bodyParser = require('body-parser');

app.use(bodyParser.json({
    limit: '16mb'
}));

app.use(bodyParser.urlencoded({
    extended: false,
    limit: '16mb'
}));

Upload to BOS

BOS is a object storage service provided by Baidu. With npm baidubce-sdk, we can have an easy access to it with Node.js. Here is an example of uploading file to BOS.

var bce = require('baidubce-sdk');

var config = {
    credentials: {
        ak: '...',
        sk: '...'
    },
    endpoint: 'http://bj.bcebos.com'
};

var bucket = 'bucket-name-here';

exports.put = function (localName, remoteName, callback) {
    var client = new bce.BosClient(config);
    client.putObjectFromFile(bucket, remoteName, localName)
        .then(function() {
            return client.getObjectMetadata(bucket, remoteName);
        })
        .then(function(response) {
            if (callback) {
                callback(null, response);
            }
        })
        .catch(function(error) {
            console.error(error);
            if (callback) {
                callback(error);
            }
        });
};

Here, localName is the file name on Node.js server, while remoteName is the file name you want to store in the BOS bucket.

BOS has a limit for file name, so we can’t just use the generated base64 name data:image/png;base64,... as localName.

One approach is to save the image on Node.js server as temporary image with random name and upload to BOS, which will then be deleted from Node.js server afterwards.

exports.saveImage = function (dataUrl) {
    var matches = dataUrl.match(/^data:.+\/(.+);base64,(.*)$/);
    var buffer = new Buffer(matches[2], 'base64');

    var savePath = path.resolve(__dirname + '../../../tmp/'
        + Math.floor(Math.random() * 1000000) + '.png');
    fs.writeFileSync(savePath, buffer);
    return savePath;
};

exports.removeImage = function (savePath) {
    fs.unlinkSync(savePath);
};