53

I've got a data URL like this:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...

What's the easiest way to get this as binary data (say, a Buffer) so I can write it to a file?

a paid nerd
  • 30,702
  • 30
  • 134
  • 179

5 Answers5

82

Put the data into a Buffer using the 'base64' encoding, then write this to a file:

var fs = require('fs');
var string = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
var regex = /^data:.+\/(.+);base64,(.*)$/;

var matches = string.match(regex);
var ext = matches[1];
var data = matches[2];
var buffer = Buffer.from(data, 'base64');
fs.writeFileSync('data.' + ext, buffer);
Sandeep Patel
  • 4,815
  • 3
  • 21
  • 37
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • 1
    Substitute the appropriate file extension? This is just an example, the general solution is: (1) get the data part after the `data:whatever/whatever;base64,` part, (2) put it into a Buffer using 'base64', (3) write this to a file. If the mime type is different, use a different file extension/use a regex/etc. – Michelle Tilley Jul 04 '12 at 21:14
  • 3
    How about `var data = string.substr(string.indexOf('base64') + 7)` ? – a paid nerd Jul 04 '12 at 21:15
  • 12
    RegEx on a large data URI is very CPU Intensive/slow. Best avoided. – Nenad Vukicevic Aug 19 '14 at 19:59
  • 7
    While this approach works there can be a very large performance hit from the regex. On my machine it was about 192X slower with the regex than using splits (about 5200ms instead of 27ms). So if your data URL represents reasonably sized images (~300KB), this barely works. – yeerk May 26 '15 at 21:01
  • Then just apply the regex to the first 268 bytes to extract the mime type. The maximum length of a mime type is 255 bytes. Use split bert's answer to extract the data. – user1158559 Jan 07 '16 at 18:01
  • Or maybe try taking out the $ from the regex? – user1158559 Jan 07 '16 at 18:02
  • 2
    This is way too slow. Using splits is much better. – limoragni Oct 19 '16 at 08:34
  • 2
    The data content of a data URI may be **not** in base64. Can it handle `data:,`, which is a totally valid _data URI_? – Константин Ван Jun 27 '19 at 06:37
  • Really really slow - don't use this solution. – jbartolome Nov 29 '20 at 20:20
36

Try this

const dataUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
const buffer = Buffer.from(dataUrl.split(",")[1], 'base64');
Sebastian Kaczmarek
  • 8,120
  • 4
  • 20
  • 38
bert
  • 1,556
  • 13
  • 15
  • 11
    Seems like that approach is deprecated now. I had to use this instead: `buffer = Buffer.from(dataUrl.split(",")[1], 'base64')` –  Sep 27 '18 at 13:44
4

I was looking into the sources of Node.js and stumbled upon this code that decodes a data URL into a Buffer. Although the function is not public and exclusively intended to parse encoded ES modules, it sheds light on aspects of data URLs that are apparently not considered by some other answers: the content of data URLs must not be base64 encoded and may be URL encoded, and it may even be unencoded.

Essentially, the Node.js logic boils down to something like the code below plus error handling:

const parsed = new URL(url);
const match = /^[^/]+\/[^,;]+(?:[^,]*?)(;base64)?,([\s\S]*)$/.exec(parsed.pathname);
const { 1: base64, 2: body } = match;
const buffer = Buffer.from(decodeURIComponent(body), base64 ? 'base64' : 'utf8');

This will correctly handle different encodings of a Javascript file with the content console.log("Node.js");:

  • data:text/javascript,console.log("Node.js");
  • data:text/javascript,console.log(%22Node.js%22)%3B
  • data:text/javascript;base64,Y29uc29sZS5sb2coIk5vZGUuanMiKTs=

The resulting buffer can be converted into a string if required with buffer.toString().

GOTO 0
  • 42,323
  • 22
  • 125
  • 158
3

I also met such questions (parsing and validating data URL) recently and found the following workaround: https://gist.github.com/bgrins/6194623

I created 2 packages to make working with data URL easier in the code. Here they are: https://github.com/killmenot/valid-data-url
https://github.com/killmenot/parse-data-url

Check out examples

Alexey Kucherenko
  • 885
  • 1
  • 8
  • 11
1

This method works for me




function dataURItoBlob(dataURI) {
  // convert base64 to raw binary data held in a string
  var data = dataURI.split(',')[1]; 
  var byteString = Buffer.from(data, "base64");

  // separate out the mime component
  var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];

  // write the ArrayBuffer to a blob, and you're done
  var blob = new Blob([byteString], { type: mimeString  });
  return blob;
}

to use

var uri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='; 
dataURItoBlob(uri)

Majid Hojati
  • 1,740
  • 4
  • 29
  • 61