Using GraphicsMagick for Image Manipulation in Node.js

on

GraphicsMagick is a free and open-source command-line utility for manipulating images. It is a fork of ImageMagick, but it is faster and uses fewer resources.

If you’re planning on using GraphicsMagick within Node.js, there are several wrappers available in npm from which to choose from. However, there are cases (e.g. you don’t want to depend on third-party modules) where you want to run the utility directly.

For those cases, I’ll show you how to launch GraphicsMagick in a new process, using the child_process Node.js module.

Start by installing GraphicsMagick:

sudo apt install graphicsmagick

Create your custom GraphicsMagick wrapper in a new file named gm.js:

var GM_PATH = "/usr/bin/gm"; // Path to the GraphicsMagick binary
var TIMEOUT = 60000; // Kill process after N milliseconds

var childProcess = require("child_process");

function spawn(stdin, args, callback) {
  var stdout = [];
  var stderr = [];
  var p = childProcess.spawn(GM_PATH, args);

  var timeoutID = setTimeout(function () {
    p.kill("SIGKILL");
    stderr.push(new Buffer("SIGKILL"));
  }, 60000);

  p.stdout.on("data", function (data) {
    stdout.push(data);
  });

  p.stderr.on("data", function (data) {
    stderr.push(data);
  });

  p.on("close", function (code) {
    clearTimeout(timeoutID);
    if (code || stderr.length) {
      console.log("code:", code, "stderr", Buffer.concat(stderr).toString());
      return callback();
    }
    callback(Buffer.concat(stdout));
  });

  p.stdin.write(stdin);
  p.stdin.end();
}

// GraphicsMagick 'convert' command
function convert(image, opt, callback) {
  opt = opt ? opt : {};

  spawn(
    image,
    [
      "convert",
      opt.srcFormat ? opt.srcFormat + ":-" : "-",
      "-resize",
      (opt.width ? opt.width : "") + "x" + (opt.height ? opt.height : ""),
      "-quality",
      opt.quality ? opt.quality : "100",
      opt.format ? opt.format + ":-" : "PNG:-",
    ],
    callback
  );
}

module.exports = {
  convert: convert,
};

To test your module, copy paste the code below in a file called test.js:

var request = require("request");
var gm = require("./gm"); // Import your module

var url =
  "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/553px-Tour_Eiffel_Wikimedia_Commons.jpg";
var out = "/tmp/test.jpg"; // Output file

request(
  {
    method: "GET",
    url: url,
    encoding: null,
  },
  function (error, response, body) {
    if (!error && response.statusCode == 200) {
      gm.convert(
        body,
        {
          srcFormat: null,
          width: null,
          height: 500,
          quality: 90,
          format: "JPEG",
        },
        function (image) {
          require("fs").writeFile(out, image, function (err) {
            console.log(err ? err : "Success!");
          });
        }
      );
    }
  }
);

The above program will download a large image from the web, resize it to 500px, and save the new image to /tmp/test.jpg.

Make sure to install the request module before running test.js:

npm install request
node test.js
Success!

For more information on GraphicsMagick, you can have a look at the manual here.