mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
imagemagick-native now supports async and filter
This commit is contained in:
parent
328cda82c5
commit
94b47508c0
12
README.md
12
README.md
@ -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 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.
|
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.
|
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
|
### 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".
|
* [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.
|
* [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.
|
* sharp v0.6.2 - Caching within libvips disabled to ensure a fair comparison.
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"imagemagick": "^0.1.3",
|
"imagemagick": "^0.1.3",
|
||||||
"imagemagick-native": "^1.5.0",
|
"imagemagick-native": "^1.6.0",
|
||||||
"gm": "^1.17.0",
|
"gm": "^1.17.0",
|
||||||
"async": "^0.9.0",
|
"async": "^0.9.0",
|
||||||
"semver": "^4.1.0",
|
"semver": "^4.1.0",
|
||||||
|
@ -17,6 +17,9 @@ var fixtures = require('../fixtures');
|
|||||||
var width = 720;
|
var width = 720;
|
||||||
var height = 480;
|
var height = 480;
|
||||||
|
|
||||||
|
// Approximately equivalent to fast bilinear
|
||||||
|
var magickFilter = 'Triangle';
|
||||||
|
|
||||||
// Disable libvips cache to ensure tests are as fair as they can be
|
// Disable libvips cache to ensure tests are as fair as they can be
|
||||||
sharp.cache(0);
|
sharp.cache(0);
|
||||||
|
|
||||||
@ -31,7 +34,9 @@ async.series({
|
|||||||
dstPath: fixtures.outputJpg,
|
dstPath: fixtures.outputJpg,
|
||||||
quality: 0.8,
|
quality: 0.8,
|
||||||
width: width,
|
width: width,
|
||||||
height: height
|
height: height,
|
||||||
|
format: 'jpg',
|
||||||
|
filter: magickFilter
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
@ -48,14 +53,25 @@ async.series({
|
|||||||
quality: 80,
|
quality: 80,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
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', {
|
}).add('gm-buffer-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
gm(inputJpgBuffer).resize(width, height).quality(80).write(fixtures.outputJpg, function (err) {
|
gm(inputJpgBuffer)
|
||||||
|
.resize(width, height)
|
||||||
|
.filter(magickFilter)
|
||||||
|
.quality(80)
|
||||||
|
.write(fixtures.outputJpg, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
} else {
|
} else {
|
||||||
@ -66,7 +82,11 @@ async.series({
|
|||||||
}).add('gm-buffer-buffer', {
|
}).add('gm-buffer-buffer', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
gm(inputJpgBuffer).resize(width, height).quality(80).toBuffer(function (err, buffer) {
|
gm(inputJpgBuffer)
|
||||||
|
.resize(width, height)
|
||||||
|
.filter(magickFilter)
|
||||||
|
.quality(80)
|
||||||
|
.toBuffer(function (err, buffer) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
} else {
|
} else {
|
||||||
@ -78,7 +98,11 @@ async.series({
|
|||||||
}).add('gm-file-file', {
|
}).add('gm-file-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
gm(fixtures.inputJpg).resize(width, height).quality(80).write(fixtures.outputJpg, function (err) {
|
gm(fixtures.inputJpg)
|
||||||
|
.resize(width, height)
|
||||||
|
.filter(magickFilter)
|
||||||
|
.quality(80)
|
||||||
|
.write(fixtures.outputJpg, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
} else {
|
} else {
|
||||||
@ -89,7 +113,11 @@ async.series({
|
|||||||
}).add('gm-file-buffer', {
|
}).add('gm-file-buffer', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
gm(fixtures.inputJpg).resize(width, height).quality(80).toBuffer(function (err, buffer) {
|
gm(fixtures.inputJpg)
|
||||||
|
.resize(width, height)
|
||||||
|
.filter(magickFilter)
|
||||||
|
.quality(80)
|
||||||
|
.toBuffer(function (err, buffer) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
} else {
|
} else {
|
||||||
@ -359,7 +387,9 @@ async.series({
|
|||||||
srcPath: fixtures.inputPng,
|
srcPath: fixtures.inputPng,
|
||||||
dstPath: fixtures.outputPng,
|
dstPath: fixtures.outputPng,
|
||||||
width: width,
|
width: width,
|
||||||
height: height
|
height: height,
|
||||||
|
format: 'jpg',
|
||||||
|
filter: magickFilter
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
@ -375,14 +405,18 @@ async.series({
|
|||||||
srcData: inputPngBuffer,
|
srcData: inputPngBuffer,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
format: 'PNG'
|
format: 'PNG',
|
||||||
|
filter: magickFilter
|
||||||
});
|
});
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}
|
}
|
||||||
}).add('gm-file-file', {
|
}).add('gm-file-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
gm(fixtures.inputPng).resize(width, height).write(fixtures.outputPng, function (err) {
|
gm(fixtures.inputPng)
|
||||||
|
.resize(width, height)
|
||||||
|
.filter(magickFilter)
|
||||||
|
.write(fixtures.outputPng, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
} else {
|
} else {
|
||||||
@ -393,7 +427,10 @@ async.series({
|
|||||||
}).add('gm-file-buffer', {
|
}).add('gm-file-buffer', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
gm(fixtures.inputPng).resize(width, height).quality(80).toBuffer(function (err, buffer) {
|
gm(fixtures.inputPng)
|
||||||
|
.resize(width, height)
|
||||||
|
.filter(magickFilter)
|
||||||
|
.toBuffer(function (err, buffer) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user