105

I'm trying to fetch an image from the web and encode it with base64.

What I have so far is this:

var request = require('request');
var BufferList = require('bufferlist').BufferList;

bl = new BufferList(),

request({uri:'http://tinypng.org/images/example-shrunk-8cadd4c7.png',responseBodyStream: bl}, function (error, response, body) 
{
    if (!error && response.statusCode == 200) 
    {
        var type = response.headers["content-type"];
        var prefix = "data:" + type + ";base64,";
        var base64 = new Buffer(bl.toString(), 'binary').toString('base64');
        var data = prefix + base64;
        console.log(data);
    }
});

This seems to be pretty close to the solution, but I can't quite get it to work. It recognizes the data type and gives out this output:

data:image/png;base64

However, the bufferlist 'bl' seems to be empty.

starball
  • 20,030
  • 7
  • 43
  • 238
Aleksr9
  • 1,233
  • 2
  • 9
  • 7

11 Answers11

185

BufferList is obsolete, as its functionality is now in Node core. The only tricky part here is setting request not to use any encoding:

var request = require('request').defaults({ encoding: null });

request.get('http://tinypng.org/images/example-shrunk-8cadd4c7.png', function (error, response, body) {
    if (!error && response.statusCode == 200) {
        data = "data:" + response.headers["content-type"] + ";base64," + Buffer.from(body).toString('base64');
        console.log(data);
    }
});
Rus
  • 47
  • 10
Dan Kohn
  • 33,811
  • 9
  • 84
  • 100
  • Great it worked, thanks!. One question though, why does request not be set to any encoding? I still get some sort of result if i skip the .defaults({ encoding: null }) part. – Aleksr9 Jun 16 '13 at 16:29
  • 27
    `encoding: null` tells request that you want a buffer, not a string. A string gives you unusably garbled data, as the whole point of base64 is to encode binary. I got the answer about encoding in my own StackOverflow question http://stackoverflow.com/questions/16619980/failing-mocha-test-on-hash-of-favicon-static-image, so I'm happy to pay it forward. – Dan Kohn Jun 16 '13 at 18:33
  • Works fine on localhost but getting ECONNREFUSED in production. Any ideas? – Omar Meky Oct 11 '14 at 15:54
  • 1
    Solution: Run production from localhost – SouvikMaji May 05 '19 at 03:46
  • 2
    May all Gods bless you... I knew it was an encoding problem, but I was struggling to find how to disable it on request library... – Dimas Crocco May 14 '19 at 01:59
  • 1
    @DanKohn `new Buffer` is now deprecated. https://nodejs.org/api/buffer.html – Nagendra Rao Nov 19 '19 at 09:23
  • request is also deprecated – kibuikaCodes Apr 05 '22 at 14:20
58

If anyone encounter the same issue while using axios as the http client, the solution is to add the responseType property to the request options with the value of 'arraybuffer':

let image = await axios.get('http://aaa.bbb/image.png', {responseType: 'arraybuffer'});
let returnedB64 = Buffer.from(image.data).toString('base64');

Hope this helps

Yehuda
  • 979
  • 7
  • 11
43

LATEST, AS OF 2017 ENDING

Well, after reading above answers and a bit research, I got to know a new way which doesn't require any package installation, http module(which is built-in) is enough!

NOTE: I have used it in node version 6.x, so I guess its also applicable to above versions.

var http = require('http');

http.get('http://tinypng.org/images/example-shrunk-8cadd4c7.png', (resp) => {
    resp.setEncoding('base64');
    body = "data:" + resp.headers["content-type"] + ";base64,";
    resp.on('data', (data) => { body += data});
    resp.on('end', () => {
        console.log(body);
        //return res.json({result: body, status: 'success'});
    });
}).on('error', (e) => {
    console.log(`Got error: ${e.message}`);
});

I hope it helps!

Also, check more about the http.get(...) here !

Ankur Shah
  • 801
  • 1
  • 12
  • 26
  • 5
    This works. I had to use both the http and https modules in my solution since most resources are https today. Unfortunately, you'll need to check manually which module to use. See https://stackoverflow.com/a/45215071/4978821. – l p Dec 18 '17 at 18:54
  • 1
    Best answer for me! – Valfar Developer Dec 30 '17 at 23:11
23

Another way of using node fetch, which breaks down the steps per variable:

const fetch = require('node-fetch');

const imageUrl = "Your URL here";
const imageUrlData = await fetch(imageUrl);
const buffer = await imageUrlData.arrayBuffer();
const stringifiedBuffer = Buffer.from(buffer).toString('base64');
const contentType = imageUrlData.headers.get('content-type');
const imageBase64 = 
`data:${contentType};base64,${stringifiedBuffer}`;
Poyoman
  • 1,652
  • 1
  • 20
  • 28
Nick Taras
  • 696
  • 8
  • 15
16

If you know the image type, it's a one-liner with the node-fetch package. Might not suit everyone, but I already had node-fetch as a dependency, so in case others are in a similar boat:

await fetch(url).then(r => r.buffer()).then(buf => `data:image/${type};base64,`+buf.toString('base64'));
  • Nice and concise! – Janosh Jan 11 '21 at 14:02
  • 1
    Works well! `.buffer` has been deprecated. This is the new way: `const blob = await response.arrayBuffer(); return \`data:${response.headers.get("content-type")};base64,${Buffer.from(blob).toString("base64")}\`;` – Gus Feb 10 '22 at 19:17
12

If you are using axios then you can follow below steps

var axios = require('axios');
const url ="put your url here";
const image = await axios.get(url, {responseType: 'arraybuffer'});
const raw = Buffer.from(image.data).toString('base64');
const base64Image = "data:" + image.headers["content-type"] + ";base64,"+raw;

you can check with decode base64.

Vishwa
  • 251
  • 3
  • 6
9

You can use the base64-stream Node.js module, which is a streaming Base64 encoder / decoder. The benefit of this method is that you can convert the image without having to buffer the whole thing into memory, and without using the request module.

var http = require('http');
var base64encode = require('base64-stream').Encode;

http.get('http://tinypng.org/images/example-shrunk-8cadd4c7.png', function(res) {
    if (res.statusCode === 200)
        res.pipe(base64encode()).pipe(process.stdout);
});
Ross J
  • 91
  • 1
  • 2
3

I use for load and encode image into base64 string node-base64-image npm module.

Download and encode an image:

var base64 = require('node-base64-image');

var options = {string: true};
base64.base64encoder('www.someurl.com/image.jpg', options, function (err, image) {
    if (err) {
        console.log(err);
    }
    console.log(image);
});

Encode a local image:

var base64 = require('node-base64-image');

var path = __dirname + '/../test.jpg',
options = {localFile: true, string: true};
base64.base64encoder(path, options, function (err, image) {  
    if (err) { console.log(err); }  
    console.log(image);  
}); 
webmato
  • 2,121
  • 1
  • 10
  • 6
2

Oneliner:

Buffer.from(
    (
      await axios.get(image, {
      responseType: "arraybuffer",
    })
  ).data,
  "utf-8"
).toString("base64")
Dmytro Soltusyuk
  • 360
  • 2
  • 10
1

Old post but could help someone. On the basis of Dmytro response that help me.

const base64FromUrl = async (url: string) => {
  try {
    return Buffer.from((await axios.get(url, { responseType: "arraybuffer", })).data, "utf-8").toString("base64")
  } catch (error) {
    return ""
  }
}

I've just add error handling.

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
samloba
  • 13
  • 4
0

You can use image-to-base64 Node.js module

The benefit of using this module is that you convert your image hassle-free

const imageToBase64 = require('image-to-base64');

const imageLink = 'Your image link'
imageToBase64(imageLink);
.then((response) => {
    const base64Image = `data:image/png;base64,${response}`
    console.log(base64Image);
  })
  .catch((error) => {
    console.log(error);
  })