Search code examples
node.jsgraphicsmagickthrough2

Pipe image through graphics magic only half complete


I am trying to set up a transform stream to pipe an image through with GM https://github.com/aheckmann/gm. So I can do something like:

readStream.pipe(resize()).pipe(writeStream);

I have used through2 along with gm to try and achieve this. It works but only parses half the image, leaving a large portion just grey.

'use strict';

var fs = require('fs')
  , gm = require('gm').subClass({imageMagick: true})
  , through2 = require('through2');



let readStream = fs.createReadStream('landscape.jpg');
let writeStream = fs.createWriteStream('landscape-out.jpg');


let resize = function(width, height) {

	return through2(function(chunk, enc, callback){
		gm(chunk)
			.resize(800)
			.gravity('Center')
			.crop(800, 500, 0, 0)
			.stream((err, stdout, stderr) => {
				
				stdout.on('data', chunk => {
					this.push(chunk);
				});

				stdout.on('end', () => {
					callback();
				});

		});
	});

} 



readStream.pipe(resize()).pipe(writeStream);

enter image description here


Solution

  • In

    through2(function(chunk, enc, callback){

    chunk is only a small part of the image.

    So the behavior you got seems normal, you are resizing the chunks of the image, not the image itself.

    This said, in the doc,

    // GOTCHA:
    // when working with input streams and any 'identify'
    // operation (size, format, etc), you must pass "{bufferStream: true}" if
    // you also need to convert (write() or stream()) the image afterwards
    // NOTE: this buffers the readStream in memory!
    var readStream = fs.createReadStream('/path/to/my/img.jpg');
    gm(readStream)
    .size({bufferStream: true}, function(err, size) {
      this.resize(size.width / 2, size.height / 2)
      this.write('/path/to/resized.jpg', function (err) {
        if (!err) console.log('done');
      });
    });
    

    but it s going to buffer the picture in memory, so it s not optimum.

    As you are using imagemagick, you shall just let it manage all that part of the processing. And later fs.readStream, the output.

    From the doc

    var writeStream = fs.createWriteStream('/path/to/my/reformatted.png');
    gm('/path/to/my/img.jpg')
    .stream('png')
    .pipe(writeStream);