62

My NodeJS-Server receives a picture base64 encoded.

data:image/jpeg;base64,/9j/4QCcRXhpZgAASUkqAAgAAAA ... CiiigD//Z

The received data should be saved as jpg. Therefore I use a Buffer and the FileSystemWriter:

var imageBuffer = new Buffer(data, 'base64'); //console = <Buffer 75 ab 5a 8a ...
fs.writeFile("test.jpg", imageBuffer, function(err) { //... });

the fs.writeFile doesn't throw an error. A jpeg-file is saved, but I can't open it. Image-Viewer says:

File is damaged or too big.

The original file is 6kb large and the new file 7kb.

marcel
  • 3,231
  • 8
  • 43
  • 76
  • 10
    Did you cut of the leading `data:image/jpeg;base64,` before trying to base64-decode the data? – CBroe Nov 28 '13 at 14:00
  • 1
    no, do i have to? I thought this information were required by the imageBuffer – marcel Nov 28 '13 at 14:06
  • 1
    No it is not, it is required for img, video tags in HTML, the base64 part is the part after, which holds actual the content – Mustafa Nov 28 '13 at 14:15

5 Answers5

120

You have to strip the url meta information from it, the data:image/jpeg part. (Reiterating what @CBroe said) Here is a small function to return the correct information from the input string.

var data = 'data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAA..kJggg==';

function decodeBase64Image(dataString) {
  var matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/),
    response = {};

  if (matches.length !== 3) {
    return new Error('Invalid input string');
  }

  response.type = matches[1];
  response.data = new Buffer(matches[2], 'base64');

  return response;
}

var imageBuffer = decodeBase64Image(data);
console.log(imageBuffer);
// { type: 'image/jpeg',
//   data: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 b4 00 00 00 2b 08 06 00 00 00 d1 fd a2 a4 00 00 00 04 67 41 4d 41 00 00 af c8 37 05 8a e9 00 00 ...> }

Then you can save the buffer using your above method.

fs.writeFile('test.jpg', imageBuffer.data, function(err) { ... });
Julian Lannigan
  • 6,492
  • 3
  • 18
  • 12
  • 1
    Thanks for this Julian, I noticed you are putting in a png base64 string and outputting a jpg. Does that work? Will the buffer automatically re-encode itself to the new filetype? I am doing something similar on my app, and it seems to be working, but I just wonder if I'm still storing a png with a .jpg extension... – newshorts Jun 14 '14 at 02:29
  • 2
    Normally the file extension doesn't effect the parsing of the image. The OS will normally do various things to autocorrect the "file type". I have corrected the answer to reduce any confusion. – Julian Lannigan Nov 15 '14 at 22:09
  • hi, it worked for me but what If I want to save it to the database because I tried to log data but did not print anything – K.S Oct 29 '19 at 10:57
  • 1
    This works but my image viewer throws an error when trying to open the image. I get "Could not load file, premature end-of-file encountered". I've read somewhere it has something to do with the decoding not being url-safe. What are you suggesting? – Grogu Jun 22 '21 at 19:54
  • 3
    Since `new Buffer` is Depreciated You Can use `Buffer.from(matches[2], 'base64');` – Aditya Nov 24 '21 at 14:09
45

Another way is to use fs.writeFile with encoding option base64 after stripping out the meta information.

var image = 'data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAA..kJggg==';

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

fs.writeFile(fileName, data, {encoding: 'base64'}, function(err){
  //Finished
});
Achu
  • 355
  • 6
  • 19
rolnn
  • 928
  • 9
  • 16
3

I made a few little changes and used this approach:

var imgData = req.body.image; // coming from client request
var base64Data = imgData.split(",")[1]; // split with `,`

require("fs").writeFile(
  Date.now() + "filename.jpeg",
  base64Data,
  "base64",
  function (err, data) {
    if (err) {
      console.log("err", err);
    }
    console.log(data, "data");
  }
);

Your file will look like 1572341624757filename.jpeg.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
K.S
  • 443
  • 10
  • 29
1

Try this simple way:

var imgData =
  "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA..kJggg==";
var base64Data = imgData.replace(/^data:image\/png;base64,/, "");

require("fs").writeFile(
  "out.png",
  base64Data,
  "base64",
  function (err, data) {
    if (err) {
      console.log("err", err);
    }
    console.log("success");
  }
);

Focus on:

  1. In data:image/png;base there is png
  2. In replace(/^data:image\/png;, here too png and
  3. name must saved with writeFile("out.png png
ggorlen
  • 44,755
  • 7
  • 76
  • 106
kumbhani bhavesh
  • 2,189
  • 1
  • 15
  • 26
0

These days, you can make this pretty clean with promises (condensing the best ideas together from a few different answers):

const fs = require("node:fs/promises");

(async () => {
  // sample (very small) base64 image
  const b64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII";
  await fs.writeFile("test.png", b64.split(",")[1], "base64");
})();
ggorlen
  • 44,755
  • 7
  • 76
  • 106