I'm using this bit of code to call gm
in Node.js to overlay text on animated GIFs:
var gm = require('gm');
gm(infile)
.stroke("#000000")
.fill('#ffffff')
.font("./impact.ttf", 42)
.dither(false)
.drawText(0, 0, text, 'South')
.write(outfile, function (err) {
if (!err) {
console.log('Image processing done.');
}
else console.log(err);
});
It works fine, however a bit on the slow side. I think (or at least i hope) i can do better.
Now, that thing really translates to (i spied on gm
):
$ convert /tmp/input.gif -stroke "#000000" -fill "#ffffff" \
-pointsize 42 -font ./impact.ttf \
-draw "gravity south text 0,0 SOME TEXT" \
-dither None output.gif
This takes about 30 seconds to process.
I've tried a few things:
-colors 128
shaves off around 7 seconds (but if the original .gif is 256 colors, some quality is lost).-coalesce
adds 20 more seconds to the 30, no go.The text is overlay on every frame, here's the final product (NOT the .gif i'm testing with - just a sample):
Is there anything i can do to make this faster, other than throw more compute at it? I'm open to lowering image quality.. but you know.. sensibly.
How would i go about getting some progress indicator in my frontend? Can i listen for an event that has an approximate idea of how much data/time remains? An example would be fantastic.
Since all i'm doing is change a few pixels at the bottom on the input GIF, the live file size of input GIF vs resulting GIF is a pretty good indicator of how much time is left, but wondering if there's a better approach.
This is the GIF i'm testing with:
https://m.popkey.co/bca7ab/ygQJw.gif
$ identify -version
Version: ImageMagick 6.8.9-9 Q16 i686 2016-06-01 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2014 ImageMagick Studio LLC
Features: DPC Modules OpenMP
Delegates: bzlib cairo djvu fftw fontconfig freetype jbig jng jpeg lcms
lqr ltdl lzma openexr pangocairo png rsvg tiff wmf x xml zlib
I see you are running the Q16 version with 16-bit quantisation and that is probably overkill if you are happy with 128 colour GIFs anyway.
I got a 50% time reduction (albeit from 6s to 3s) on my desktop iMac by changing from the 16-bit to the 8-bit version. To get the 8-bit version, you need to rebuild using:
./configure --with-quantum-depth=8 ... your usual options...
Not only does that speed things up, but it also relieves "memory pressure" so it may help your application in other ways too by minimising paging.
You could also try adding in --enable-zero-configuration
to prevent ImageMagick reading lots of XML config files at startup.
Some things run faster without OpenMP, so you could also consider disabling that when you run ./configure
.
See also my comment about resources:
identify -list resource
and maybe increasing the memory available to ImageMagick using:
convert -limit memory 512MiB ....
As regards following progress, you could use -monitor
like this:
convert -monitor anim.gif -stroke "#000000" -fill "#ffffff" -pointsize 42 -draw "gravity south text 0,0 'SOME TEXT'" -dither None output.gif
Sample Output
load image[anim.gif]: 1 of 2, 100% complete
load image[anim.gif]: 2 of 3, 100% complete
load image[anim.gif]: 3 of 4, 100% complete
load image[anim.gif]: 4 of 5, 100% complete
load image[anim.gif]: 5 of 6, 100% complete
load image[anim.gif]: 6 of 7, 100% complete
load image[anim.gif]: 7 of 8, 100% complete
load image[anim.gif]: 8 of 9, 100% complete
load image[anim.gif]: 9 of 10, 100% complete
load image[anim.gif]: 10 of 11, 100% complete
load image[anim.gif]: 11 of 12, 100% complete
load image[anim.gif]: 12 of 13, 100% complete
load image[anim.gif]: 13 of 14, 100% complete
load image[anim.gif]: 14 of 15, 100% complete
load image[anim.gif]: 15 of 16, 100% complete
load image[anim.gif]: 16 of 17, 100% complete
load image[anim.gif]: 17 of 18, 100% complete
load image[anim.gif]: 18 of 19, 100% complete
load image[anim.gif]: 19 of 20, 100% complete
load image[anim.gif]: 20 of 21, 100% complete
load image[anim.gif]: 21 of 22, 100% complete
load image[anim.gif]: 22 of 23, 100% complete
load image[anim.gif]: 23 of 24, 100% complete
load image[anim.gif]: 24 of 25, 100% complete
load image[anim.gif]: 25 of 26, 100% complete
load image[anim.gif]: 26 of 27, 100% complete
load image[anim.gif]: 27 of 28, 100% complete
load image[anim.gif]: 28 of 29, 100% complete
load image[anim.gif]: 29 of 30, 100% complete
load image[anim.gif]: 30 of 31, 100% complete
load image[anim.gif]: 31 of 32, 100% complete
load image[anim.gif]: 32 of 33, 100% complete
load image[anim.gif]: 33 of 34, 100% complete
load image[anim.gif]: 34 of 35, 100% complete
load image[anim.gif]: 35 of 36, 100% complete
load image[anim.gif]: 36 of 37, 100% complete
load image[anim.gif]: 37 of 38, 100% complete
load image[anim.gif]: 38 of 39, 100% complete
load image[anim.gif]: 39 of 40, 100% complete
load image[anim.gif]: 40 of 41, 100% complete
load image[anim.gif]: 41 of 42, 100% complete
load image[anim.gif]: 42 of 43, 100% complete
load image[anim.gif]: 43 of 44, 100% complete
load image[anim.gif]: 44 of 45, 100% complete
load image[anim.gif]: 45 of 46, 100% complete
load image[anim.gif]: 46 of 47, 100% complete
load image[anim.gif]: 47 of 48, 100% complete
load image[anim.gif]: 48 of 49, 100% complete
load image[anim.gif]: 49 of 50, 100% complete
load image[anim.gif]: 50 of 51, 100% complete
load image[anim.gif]: 51 of 52, 100% complete
load image[anim.gif]: 52 of 53, 100% complete
load image[anim.gif]: 53 of 54, 100% complete
load image[anim.gif]: 54 of 55, 100% complete
load image[anim.gif]: 55 of 56, 100% complete
load image[anim.gif]: 56 of 57, 100% complete
load image[anim.gif]: 57 of 58, 100% complete
load image[anim.gif]: 58 of 59, 100% complete
load image[anim.gif]: 59 of 60, 100% complete
load image[anim.gif]: 60 of 61, 100% complete
load image[anim.gif]: 61 of 62, 100% complete
load image[anim.gif]: 62 of 63, 100% complete
load image[anim.gif]: 63 of 64, 100% complete
load image[anim.gif]: 64 of 65, 100% complete
load image[anim.gif]: 65 of 66, 100% complete
load image[anim.gif]: 66 of 67, 100% complete
load image[anim.gif]: 67 of 68, 100% complete
load image[anim.gif]: 68 of 69, 100% complete
load image[anim.gif]: 69 of 70, 100% complete
load image[anim.gif]: 70 of 71, 100% complete
load image[anim.gif]: 71 of 72, 100% complete
load image[anim.gif]: 72 of 73, 100% complete
load image[anim.gif]: 73 of 74, 100% complete
load image[anim.gif]: 74 of 75, 100% complete
load image[anim.gif]: 75 of 76, 100% complete
load image[anim.gif]: 76 of 77, 100% complete
load image[anim.gif]: 77 of 78, 100% complete
load image[anim.gif]: 78 of 79, 100% complete
load image[anim.gif]: 79 of 80, 100% complete
load image[anim.gif]: 80 of 81, 100% complete
load image[anim.gif]: 81 of 82, 100% complete
load image[anim.gif]: 82 of 83, 100% complete
load image[anim.gif]: 83 of 84, 100% complete
load image[anim.gif]: 84 of 85, 100% complete
load image[anim.gif]: 85 of 86, 100% complete
load image[anim.gif]: 86 of 87, 100% complete
load image[anim.gif]: 87 of 88, 100% complete
load image[anim.gif]: 88 of 89, 100% complete
load image[anim.gif]: 89 of 90, 100% complete
load image[anim.gif]: 90 of 91, 100% complete
load image[anim.gif]: 91 of 92, 100% complete
load image[anim.gif]: 92 of 93, 100% complete
load image[anim.gif]: 93 of 94, 100% complete
load image[anim.gif]: 94 of 95, 100% complete
load image[anim.gif]: 95 of 96, 100% complete
load image[anim.gif]: 96 of 97, 100% complete
load image[anim.gif]: 97 of 98, 100% complete
load image[anim.gif]: 98 of 99, 100% complete
load image[anim.gif]: 99 of 100, 100% complete
load image[anim.gif]: 100 of 101, 100% complete
load image[anim.gif]: 101 of 102, 100% complete
load image[anim.gif]: 102 of 103, 100% complete
load image[anim.gif]: 103 of 104, 100% complete
load image[anim.gif]: 104 of 105, 100% complete
load image[anim.gif]: 105 of 106, 100% complete
mogrify image[anim.gif]: 106 of 107, 100% complete
classify image colors[output.gif]: 313 of 314, 100% complete
assign image colors[output.gif]: 313 of 314, 100% complete
classify image colors[output.gif]: 313 of 314, 100% complete
...
...