Mark
Mark

Reputation: 5088

Respond to GET request with image created by Node

I have a simple Node Api which takes a GET request, constructs a canvas using node canvas, saves it as a PNG, and sends it back to the server. I'm able to save it, but I cannot return it to the server. The router is:

router.get('/canvas', function(req, res) {

    var callback = function(data){

         res.writeHead(200, {'Content-Type': 'text/html'});
          res.write('<img src="data:image/jpeg;base64,')
          res.write(new Buffer(data).toString('base64'));
          res.end('"/>');
    };

    canvas.getCanvas(callback);

});

And the Node model is:

  var getCanvas = function(callback){

    var Canvas = require('canvas'),
    canvas = new Canvas(150, 150),
    ctx = canvas.getContext('2d'),
    fs = require('fs');


    ctx.font = '30px Impact';
    ctx.rotate(.1);
    ctx.fillText("Awesome!", 50, 100);

    var te = ctx.measureText('Awesome!');
    ctx.strokeStyle = 'rgba(0,0,0,0.5)';
    ctx.beginPath();
    ctx.lineTo(50, 102);
    ctx.lineTo(50 + te.width, 102);
    ctx.stroke();


    var out = fs.createWriteStream(__dirname + '/text2.png'),
        stream = canvas.pngStream();


    stream.on('data', function(chunk){
      out.write(chunk);
    });

    stream.on('end', function(){
      console.log('saved png');
      fs.readFile(__dirname +'/text2.png', function(err, data) {

          if (err) throw err; // Fail if the file can't be read.

            callback(data);
        });
    });

  }

module.exports.getCanvas = getCanvas;

The PNG gets saved to the filesystem, but in the browser response to the GET request i just see:

<img src="data:image/jpeg;base64,iVBORw0KGgo="/>

And the size is only 370 bytes, so the browser is obviously not receiving the image. How can I send this image back as a response to the GET request? And a related question, do I need to save it to the file system or can I somehow stream the image back after it's been created?

Upvotes: 0

Views: 474

Answers (1)

Epicblood
Epicblood

Reputation: 1177

Instead of writing to a file, then reading said file, add the chunks to an array and then concat that into a buffer, so change:

stream.on('data', function(chunk){
  out.write(chunk);
});

to be

var chunks = [];
stream.on('data', function(chunk){
  out.write(chunk); //remove this if you have no need to keep file local
  chunks.push(chunk);
});

then change your on end to be:

stream.on('end', function(){
  console.log('saved png');
  callback(Buffer.concat(chunks));
});

and since your callback now accepts a buffer, change this bit as well:

var callback = function(data){

     res.writeHead(200, {'Content-Type': 'text/html'});
      res.write('<img src="data:image/jpeg;base64,')
      res.write(data.toString('base64'));
      res.end('"/>');
};

Upvotes: 1

Related Questions