Search code examples
node.jsimagemagickgm

node.js: gm throws spawn E2BIG error when passed too much data


The following code throws an error:

const COUNT = 2528; // 2527 works, 2528 errors

const gm = require('gm').subClass({ imageMagick: true });

const brokenData = [];

for (let i = 0; i < COUNT; i++) {
  brokenData.push([
    Math.random() * 500, Math.random() * 500
  ]);
}

const tile = gm('./blank-tile.png')
  .resize(500, 500)
  .fill("red");

brokenData.forEach((point) => {
  tile.drawCircle(point[0], point[1], point[0] + 4, point[1]);
});

tile.write(__dirname + '/test.png', (err) => {
  if (err) {
    throw err;
  }

  console.log('success');
});

As per the comment, it's fine when drawing 2527 circles, but throws the error at 2528 circles. It's the same every time, at least on my machine.

Here's the error:

Error: spawn E2BIG
    at ChildProcess.spawn (internal/child_process.js:358:11)
    at Object.spawn (child_process.js:533:9)
    at spawn (/Users/callumacrae/Sites/testing-gm/node_modules/cross-spawn/index.js:17:18)
    at gm._spawn (/Users/callumacrae/Sites/testing-gm/node_modules/gm/lib/command.js:224:14)
    at /Users/callumacrae/Sites/testing-gm/node_modules/gm/lib/command.js:101:12
    at series (/Users/callumacrae/Sites/testing-gm/node_modules/array-series/index.js:11:36)
    at gm._preprocess (/Users/callumacrae/Sites/testing-gm/node_modules/gm/lib/command.js:177:5)
    at gm.write (/Users/callumacrae/Sites/testing-gm/node_modules/gm/lib/command.js:99:10)
    at Object.<anonymous> (/Users/callumacrae/Sites/testing-gm/test.js:21:6)
    at Module._compile (internal/modules/cjs/loader.js:688:30)

I'm assuming it's coming from somewhere within gm, as I haven't provided any long argument lists!

The same thing happens whether I use imagemagick or graphicsmagick. Node version 10.13.0.

Any ideas?


Solution

  • I'm not really familiar with node-gm, but I have a feeling that .drawCircle(x1, y1, x2, y2) method just appends a command-line argument -draw "circle x1,y1 x2,y2". So after 2527 draw commands you exceed the argument buffer.

    With ImageMagick, if you have a large list of draw commands, you would write to a file & tell the draw command to read from it.

    The file would looks something like...

    # circles.txt
    circle x1,y1 x2,y2
    circle x1,y1 x2,y2
    circle x1,y1 x2,y2
    circle x1,y1 x2,y2
    

    And reference the file with an at-symbol (@) prefix.

    convert ... -draw @cicles.txt ...
    

    So as an alternative, you may be able to create a temp file, write your draw commands, then call..

    const tile = gm('./blank-tile.png')
      .resize(500, 500)
      .fill("red")
      .draw("@circles.txt");
    

    However I'm not sure if node-gm supports this, and/or many modern systems disable MVG & TXT with default security protocols. Worth investigating.