NodeJS base64 image encoding/decoding not quite working

Solution 1:

I think you are misunderstanding the usage of the encoding argument a bit. If you are going to specify encoding 'binary', then you need to do it consistently. But really you don't need it at all. You seem to be confusing the usage of Buffer vs binary strings.

// This tells node to load the file into a Buffer 'original_data' because you
// have not specified an encoding for the returned values. If you provided an
// encoding, then original_data would be a string with that encoding.
fs.readFile(image_origial, function(err, original_data){

    // This tells node to take that buffer, and write it to the new filename.
    // Again no encoding is provided, so it will assume a Buffer or utf8 string.
    fs.writeFile('image_orig.jpg', original_data, function(err) {});

    // This tells node to create a new buffer from the old buffer, which means
    // it will iterate over original_data copying the bytes one at a time. But
    // they will be identical buffers. It will ignore the 'binary' argument
    // since the object you are passing isn't a string.
    // Then it encodes the content of that Buffer to base64, which is fine.
    var base64Image = new Buffer(original_data, 'binary').toString('base64');

    // Here you decode the base64 to a buffer, which is fine, but then you
    // convert the buffer into a string with encoding 'binary'. This means that
    // it is a string object whose code points are bytes of the buffer.
    var decodedImage = new Buffer(base64Image, 'base64').toString('binary');

    // Here you try to write that String object to a file. Since the argument you
    // have given is a string and you have not given an encoding argument for the
    // write command, then it will assume that 'utf8' is the encoding. It will try to
    // decode your binary string into a utf8 encoded buffer, and write that buffer.
    // This will cause it to fail because that encoding conversion is wrong.
    // Really through, 'binary' is just wrong to use. Buffers are already binary.
    fs.writeFile('image_decoded.jpg', decodedImage, function(err) {});
});

This next example will work but is very inefficient because changing encodings all the time isn't needed, but I just want to show it to be clear. If you really DID want to have a specific encoding, you need to make sure you are consistent. Every one of those functions has an encoding argument.

fs.readFile(image_origial, 'binary', function(err, original_data){
    fs.writeFile('image_orig.jpg', original_data, 'binary', function(err) {});
    var base64Image = new Buffer(original_data, 'binary').toString('base64');
    var decodedImage = new Buffer(base64Image, 'base64').toString('binary');
    fs.writeFile('image_decoded.jpg', decodedImage, 'binary', function(err) {});
});

This is the right way to do it. Keep everything as a Buffer, except when you make it base64.

fs.readFile(image_origial, function(err, original_data){
    fs.writeFile('image_orig.jpg', original_data, function(err) {});
    var base64Image = original_data.toString('base64');
    var decodedImage = new Buffer(base64Image, 'base64');
    fs.writeFile('image_decoded.jpg', decodedImage, function(err) {});
});

Solution 2:

Slightly better solution will be to remove all mime types possible:

var buff = new Buffer(req.body.imageFile
    .replace(/^data:image\/(png|gif|jpeg);base64,/,''), 'base64');
fs.writeFile('/file/path/', buff, function (err) {
    console.log('done');
});

This is addition to the @Herve's answer.