imagemagick-native now supports async and filter

This commit is contained in:
Lovell Fuller 2014-11-24 15:13:47 +00:00
parent 328cda82c5
commit 94b47508c0
3 changed files with 94 additions and 57 deletions

View File

@ -10,13 +10,13 @@
The typical use case for this high speed Node.js module is to convert large images of many formats to smaller, web-friendly JPEG, PNG and WebP images of varying dimensions.
The performance of JPEG resizing is typically 8x faster than ImageMagick and GraphicsMagick, based mainly on the number of CPU cores available.
Memory usage is kept to a minimum, no child processes are spawned, everything remains non-blocking thanks to _libuv_ and Promises/A+ are supported.
This module supports reading and writing JPEG, PNG and WebP images to and from Streams, Buffer objects and the filesystem. It also supports reading images of many other types from the filesystem via libmagick++ or libgraphicsmagick++ if present.
When generating JPEG output all metadata is removed and Huffman tables optimised without having to use separate command line tools like [jpegoptim](https://github.com/tjko/jpegoptim) and [jpegtran](http://jpegclub.org/jpegtran/).
Only small regions of uncompressed image data are held in memory and processed at a time, taking full advantage of multiple CPU cores and L1/L2/L3 cache. Resizing an image is typically 4x faster than using the quickest ImageMagick and GraphicsMagick settings.
Huffman tables are optimised when generating JPEG output images without having to use separate command line tools like [jpegoptim](https://github.com/tjko/jpegoptim) and [jpegtran](http://jpegclub.org/jpegtran/). PNG filtering can be disabled, which for diagrams and line art often produces the same result as [pngcrush](http://pmt.sourceforge.net/pngcrush/).
Everything remains non-blocking thanks to _libuv_, no child processes are spawned and Promises/A+ are supported.
Anyone who has used the Node.js bindings for [GraphicsMagick](https://github.com/aheckmann/gm) will find the API similarly fluent.
@ -548,7 +548,7 @@ sudo yum install -y --enablerepo=epel GraphicsMagick
### The contenders
* [imagemagick-native](https://github.com/mash/node-imagemagick-native) v1.2.2 - Supports Buffers only and blocks main V8 thread whilst processing.
* [imagemagick-native](https://github.com/mash/node-imagemagick-native) v1.2.2 - Supports Buffers only
* [imagemagick](https://github.com/yourdeveloper/node-imagemagick) v0.1.3 - Supports filesystem only and "has been unmaintained for a long time".
* [gm](https://github.com/aheckmann/gm) v1.16.0 - Fully featured wrapper around GraphicsMagick.
* sharp v0.6.2 - Caching within libvips disabled to ensure a fair comparison.

View File

@ -9,7 +9,7 @@
},
"devDependencies": {
"imagemagick": "^0.1.3",
"imagemagick-native": "^1.5.0",
"imagemagick-native": "^1.6.0",
"gm": "^1.17.0",
"async": "^0.9.0",
"semver": "^4.1.0",

View File

@ -17,6 +17,9 @@ var fixtures = require('../fixtures');
var width = 720;
var height = 480;
// Approximately equivalent to fast bilinear
var magickFilter = 'Triangle';
// Disable libvips cache to ensure tests are as fair as they can be
sharp.cache(0);
@ -31,7 +34,9 @@ async.series({
dstPath: fixtures.outputJpg,
quality: 0.8,
width: width,
height: height
height: height,
format: 'jpg',
filter: magickFilter
}, function(err) {
if (err) {
throw err;
@ -48,55 +53,78 @@ async.series({
quality: 80,
width: width,
height: height,
format: 'JPEG'
format: 'JPEG',
filter: magickFilter
}, function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
deferred.resolve();
}
}).add('gm-buffer-file', {
defer: true,
fn: function(deferred) {
gm(inputJpgBuffer).resize(width, height).quality(80).write(fixtures.outputJpg, function (err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
gm(inputJpgBuffer)
.resize(width, height)
.filter(magickFilter)
.quality(80)
.write(fixtures.outputJpg, function (err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('gm-buffer-buffer', {
defer: true,
fn: function(deferred) {
gm(inputJpgBuffer).resize(width, height).quality(80).toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
gm(inputJpgBuffer)
.resize(width, height)
.filter(magickFilter)
.quality(80)
.toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('gm-file-file', {
defer: true,
fn: function(deferred) {
gm(fixtures.inputJpg).resize(width, height).quality(80).write(fixtures.outputJpg, function (err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
gm(fixtures.inputJpg)
.resize(width, height)
.filter(magickFilter)
.quality(80)
.write(fixtures.outputJpg, function (err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('gm-file-buffer', {
defer: true,
fn: function(deferred) {
gm(fixtures.inputJpg).resize(width, height).quality(80).toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
gm(fixtures.inputJpg)
.resize(width, height)
.filter(magickFilter)
.quality(80)
.toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-buffer-file', {
defer: true,
@ -359,7 +387,9 @@ async.series({
srcPath: fixtures.inputPng,
dstPath: fixtures.outputPng,
width: width,
height: height
height: height,
format: 'jpg',
filter: magickFilter
}, function(err) {
if (err) {
throw err;
@ -375,32 +405,39 @@ async.series({
srcData: inputPngBuffer,
width: width,
height: height,
format: 'PNG'
format: 'PNG',
filter: magickFilter
});
deferred.resolve();
}
}).add('gm-file-file', {
defer: true,
fn: function(deferred) {
gm(fixtures.inputPng).resize(width, height).write(fixtures.outputPng, function (err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
gm(fixtures.inputPng)
.resize(width, height)
.filter(magickFilter)
.write(fixtures.outputPng, function (err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('gm-file-buffer', {
defer: true,
fn: function(deferred) {
gm(fixtures.inputPng).resize(width, height).quality(80).toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
gm(fixtures.inputPng)
.resize(width, height)
.filter(magickFilter)
.toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-buffer-file', {
defer: true,