Search code examples
node.jsstreamimagemagickgraphicsmagick

Pipe multiple image streams into ImageMagick/GraphicsMagick child process


I'm able to pipe one image stream into a ImageMagick child process. I based my code off of Pipe stream to graphicsmagick/imagemagick child process

I want to composite multiple image streams and pipe the composited image as a response. Here is my Node.js code, in which it retrieves image from my AWS S3 bucket and then pipes that out as a response:

app.get('/composite_images', function(req, res){    
    res.writeHead(200, {'Content-Type' : 'image/png'});

    s3.get("/" + "fronttop.png").on("response", function(s3Res) {
      // '-'' means standard in or stdin
      var args = ['-', '-page', '+0+0', '-mosaic', '-'];
      var convert = spawn("convert", args);

      // This worked!
      s3Res.pipe(convert.stdin);

      convert.stdout.pipe(res);
      convert.stderr.pipe(process.stderr);
    }).end();
})

Official documentation says

"At this time IM does not allow you to just read one image from such a stream, process it, and then read another single image. All IM commands will always read the whole stream, and then close it. This is being fixed as part of IMv7 scripted processing."

Is it possible using GraphicsMagick/ImageMagick to composite multiple image streams?


Solution

  • Not sure if this is what you mean, but have a look. ImageMagick does have a streaming format, it is called MIFF or Magick Image File Format. It allows images to be streamed one after the other through a pipe. I don't speak node but here is how it looks at the command line:

    { convert -size 50x50 xc:red miff:- ; convert -size 50x50 xc:blue miff:- ; } | convert miff:- +append result.png
    

    Basically, the {} is a compound statement that contains 2 ImageMagick convert processes, the first writes a red square image to its standard out in MIFF format and the second writes a blue square to its standard out, also in MIFF format. Then the two images are streamed through a pipe and picked up by a third convert that reads both the red and blue squares from its standard input and joins them up side by side.

    enter image description here

    Here is how you might use it in a loop. Be careful not to put any debugging statements on stdout in the middle of this process - says the man who once did and spent ages trying to work out why that broke things!

    #!/bin/bash
    for c in red green blue cyan magenta yellow; do 
      convert -size 50x50 xc:$c miff:-
    done | convert miff:- +append result.png
    

    enter image description here

    Maybe you can see how to do what you want now...