Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write binary data to a file using node.js?

I am trying to do toDataUrl() of canvas, and it gives base64 data. I want to store it as a png. I can get the converted binary data from base64, but I cant write it to a file using NodeJs service.

If I write base64 data directly to the file, all data can be written, but it cannot be a png right?. I want to store the binary data to be stored. How to do it?

Code snippet:

var strData = this.drawingCanvas.getContext().canvas.toDataURL();

var data = strData.replace(/^data:image\/\w+;base64,/, "");

var imgData = this.decode(data); // decode(data) is DEFINED BELOW

this.call({filePath:'<path>/image.png', data: imgData}, 
            {method:"writeFile"});`

`utf8decode : function (utftext) {
    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;

    while ( i < utftext.length ) {

        c = utftext.charCodeAt(i);

        if (c < 128) {
            string += String.fromCharCode(c);
            i++;
        }
        else if((c > 191) && (c < 224)) {
            c2 = utftext.charCodeAt(i+1);
            string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
            i += 2;
        }
        else {
            c2 = utftext.charCodeAt(i+1);
            c3 = utftext.charCodeAt(i+2);
            string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }

    }

    return string;
},`

`_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

decode : function (input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

    while (i < input.length) {

        enc1 = this._keyStr.indexOf(input.charAt(i++));
        enc2 = this._keyStr.indexOf(input.charAt(i++));
        enc3 = this._keyStr.indexOf(input.charAt(i++));
        enc4 = this._keyStr.indexOf(input.charAt(i++));

        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;

        output = output + String.fromCharCode(chr1);

        if (enc3 != 64) {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
            output = output + String.fromCharCode(chr3);
        }

    }

    output = this.utf8decode(output);

    return output;

},`

/**************************************************
wRITEfILEaaSSISTANT.JS
***************************************************/

var WriteFileAssistant = function(){};

WriteFileAssistant.prototype.run = function(future, subscription) {

var fs = IMPORTS.require('fs');
var filePath = this.controller.args.filePath;

var f = subscription.get();
f.result = {reply: data};

var fd =  fs.openSync('<path>/image.png', 'a+');
//var data = fs.writeSync(fd, g, null, encoding='utf8');

//this.controller.args.data - Image data (binary)
var buff = new Buffer(this.controller.args.data, 'binary');
//tried also with 'base64'

fs.write(fd, buff, 0, buff.length, 0, function(err,written){

});

var f = subscription.get();
f.result = {reply: data};
like image 872
Kantesh Avatar asked Sep 07 '11 05:09

Kantesh


1 Answers

You are making things much harder than they need to be. The node Buffer object takes base64 as input and does all of that decoding for you.

You can just strip the data:image... part from the base64 string and pass that data to your WriteFileAssistant.

var strData = this.drawingCanvas.getContext().canvas.toDataURL();
var imgData = strData.replace(/^data:image\/\w+;base64,/, "");
this.call(
  {
    filePath:'/media/internal/Collage/image.png',
    data: imgData
  },
  {
    method:"writeFile"
  }
);

The the WriteFileAssistant just needs to take the base64 string and pass that as an argument to the Buffer constructor. Also, having 'a+' on the openSync call will break things too.

var WriteFileAssistant = function(){};

WriteFileAssistant.prototype.run = function(future, subscription) {

  var fs = IMPORTS.require('fs');
  var filePath = this.controller.args.filePath;

  var fd =  fs.openSync('<path>/image.png', 'w');

  var buff = new Buffer(this.controller.args.data, 'base64');

  fs.write(fd, buff, 0, buff.length, 0, function(err,written){

  });
}

Buffer takes a string and an encoding, then it uses the encoding value to process the string into a series of bytes, so when you tell it that the string is base64, it will decode the base64 for you and create the proper decoded array of bytes to write to the file.

like image 72
loganfsmyth Avatar answered Sep 20 '22 00:09

loganfsmyth