7

so i've been tackling this one for a few days and got the point when i'm ready to ask for help.

I'm trying to generate an animated gif with in a node.js based app, using the graphicsmagic package.

I've generated several slides that look kinda like that

var slides = [];

for (var i=0; i < 10; i++) {
  var slide = gm(200, 200, '#000000')
    .fill('#ffffff')
    .drawText("Slide #"+ i);

  slides.push(slide);
}

I can convert them either into streams or buffers, i can save them as individual files on the hard drive and kinda works

But my problem is how to make an animated gif from those slides completely in memory, without saving the individual files on a hard drive?

I see gm has methods like #delay() and #page() and so technically i could craft a command like

convert -delay 200 -page slide1.gif -page slide2.gif output.gif

I just don't know how. I'm thinking it should looks something like that

var end_image = gm(200, 200, '#000000');

end_image.delay(500);

for (var i=0; i < slides.length; i++) {
  slides[i].toBuffer(function(err, buffer) {
    end_image.page(200, 200, ????);
  });
}

end_image.write("output.gif");

basically I don't know how to convert a buffer into an argument for gm

Have anyone done it before? Maybe there is another way?

PS: i tried to use the gifencoder package as well, and successfully fed the gm buffers as frames into a gifencoder's API, but the output was all broken.

Nikolay
  • 1,392
  • 1
  • 9
  • 15
  • Were you able to figure this out? I have tried both gifencoder (got as far as it sounds like you did, but get a segmentation fault on trying to use addFrame() with buffers) and the gif module (which seems to only work with older versions of node). – Gregir Dec 19 '14 at 20:20
  • @Gregir nope, did it through dumping a bunch of files in `/tmp` and shelling out – Nikolay Dec 20 '14 at 21:36
  • I have the code to do this with the JIMP library but i am trying to figure out how to do this with GM myself – PirateApp Mar 18 '17 at 07:16

3 Answers3

4

This may not be exactly the answer you were looking for, but I think the following does answer the question title: "how to generate an animated gif with GM in Node.js"

var Gm = require("gm");

Gm()
.in("image1.jpg")
.in("image2.jpg")
.delay(100)
.resize(600,600)
.write("animated.gif", function(err){
  if (err) throw err;
  console.log("animated.gif created");
});
anneb
  • 5,510
  • 2
  • 26
  • 26
2

There is the gif module lets you create static and animated gifs which may help you.

mscdex
  • 104,356
  • 15
  • 192
  • 153
  • 1
    yeah, i saw it, but as far as i understand it works with hard drive, it dumps everything in the `/tmp` folder. i need to process everything _in memory_ so i could host say on heroku and have no HDD io. (i'll need to generate a lot of those images and i don't want to save them on HDD) – Nikolay May 19 '14 at 04:28
  • You should be able to do it in-memory also. Take a look at [this example](https://github.com/pkrumins/node-gif/blob/master/tests/animated-gif/animated-gif.js). – mscdex May 19 '14 at 12:09
  • @Nikolay, You have local file system available to use on Heroku, and it's perfectly fine to write temporary files. You just can't rely on them being there across app restarts. – raine Dec 21 '14 at 06:44
  • @rane, yup that's what i did, i just thought maybe there is a way to make it work completely in memory – Nikolay Dec 22 '14 at 10:17
  • 1
    Also worth noting that node-gif only works on node <= 0.8, so it's quite outdated. – Josiah Nunemaker Oct 25 '20 at 18:42
0

For anyone looking for a JavaScript encoder (as opposed to a C++ Node module), gifencoder seems to be able to do the job. An example from their page:

const GIFEncoder = require('gifencoder');
const encoder = new GIFEncoder(854, 480);
const pngFileStream = require('png-file-stream');
const fs = require('fs');

const stream = pngFileStream('test/**/frame?.png')
  .pipe(encoder.createWriteStream({ repeat: -1, delay: 500, quality: 10 }))
  .pipe(fs.createWriteStream('myanimated.gif'));

stream.on('finish', function () {
  // Process generated GIF
});

// Alternately, you can wrap the "finish" event in a Promise
await new Promise((resolve, reject) => {
  stream.on('finish', resolve);
  stream.on('error', reject);
});
Tomáš Hübelbauer
  • 9,179
  • 14
  • 63
  • 125
  • Great. Any way possible - instead of writing the gif to a file, pass it back as a response? – avijendr Jul 01 '22 at 01:20
  • Instead of `.pipe(fs.createWriteStream('myanimated.gif'))` it is going to be something like `.pipe(response);` or maybe `response.body`. Ask a new question with details. – Tomáš Hübelbauer Jul 01 '22 at 06:35
  • 1
    Thank you - Sure, there is a question. Can you please answer this question I've asked please? - https://stackoverflow.com/questions/72823352/can-nodejs-gifencoder-directly-pipe-a-generated-gif-to-aws-lambda-response?noredirect=1#comment128628152_72823352 – avijendr Jul 01 '22 at 10:13