Comparing version
12
index.js
var sharp = require("./build/Release/sharp"); | ||
module.exports.crop = function(input, output, width, height, callback) { | ||
sharp.resize(input, output, width, height, "c", callback) | ||
} | ||
sharp.resize(input, output, width, height, "c", callback); | ||
}; | ||
module.exports.embedWhite = function(input, output, width, height, callback) { | ||
sharp.resize(input, output, width, height, "w", callback) | ||
} | ||
sharp.resize(input, output, width, height, "w", callback); | ||
}; | ||
module.exports.embedBlack = function(input, output, width, height, callback) { | ||
sharp.resize(input, output, width, height, "b", callback) | ||
} | ||
sharp.resize(input, output, width, height, "b", callback); | ||
}; |
{ | ||
"name": "sharp", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"author": "Lovell Fuller", | ||
"description": "High performance module to resize JPEG and PNG images using the libvips image processing library", | ||
"scripts": { | ||
"test": "node tests/perf.js" | ||
}, | ||
"main": "index.js", | ||
"description": "High performance Node.js module to resize JPEG images using the libvips image processing library", | ||
"repository": { | ||
@@ -10,16 +14,5 @@ "type": "git", | ||
}, | ||
"devDependencies": { | ||
"imagemagick": "*", | ||
"gm": "*", | ||
"epeg": "*", | ||
"benchmark": "*" | ||
}, | ||
"scripts": { | ||
"test": "node tests/perf.js" | ||
}, | ||
"engines": { | ||
"node": ">=0.8" | ||
}, | ||
"keywords": [ | ||
"jpeg", | ||
"png", | ||
"resize", | ||
@@ -33,4 +26,13 @@ "thumbnail", | ||
], | ||
"author": "Lovell Fuller", | ||
"license": "Apache 2.0" | ||
"devDependencies": { | ||
"imagemagick": "*", | ||
"gm": "*", | ||
"epeg": "*", | ||
"async": "*", | ||
"benchmark": "*" | ||
}, | ||
"license": "Apache 2.0", | ||
"engines": { | ||
"node": ">=0.8" | ||
} | ||
} |
@@ -10,5 +10,5 @@ # sharp | ||
The typical use case for this high speed Node.js module is to convert a large JPEG image to smaller JPEG images of varying dimensions. | ||
The typical use case for this high speed Node.js module is to convert large JPEG and PNG images to smaller JPEG and PNG images of varying dimensions. | ||
It is somewhat opinionated in that it only deals with JPEG images, always obeys the requested dimensions by either cropping or embedding and insists on a mild sharpen of the resulting image. | ||
It is somewhat opinionated in that it only deals with JPEG and PNG images, always obeys the requested dimensions by either cropping or embedding and insists on a mild sharpen of the resulting image. | ||
@@ -23,3 +23,3 @@ Under the hood you'll find the blazingly fast [libvips](https://github.com/jcupitt/libvips) image processing library, originally created in 1989 at Birkbeck College and currently maintained by the University of Southampton. | ||
* node-gyp | ||
* libvips-dev 7.28+ | ||
* libvips-dev 7.28+ (7.36+ for optimal JPEG Huffman coding) | ||
@@ -45,3 +45,3 @@ ``` | ||
Scale and crop JPEG `inputPath` to `width` x `height` and write JPEG to `outputPath` calling `callback` when complete. | ||
Scale and crop `inputPath` to `width` x `height` and write to `outputPath` calling `callback` when complete. | ||
@@ -62,6 +62,6 @@ Example: | ||
Scale and embed JPEG `inputPath` to `width` x `height` using a white canvas and write JPEG to `outputPath` calling `callback` when complete. | ||
Scale and embed `inputPath` to `width` x `height` using a white canvas and write to `outputPath` calling `callback` when complete. | ||
```javascript | ||
sharp.embedWhite("input.jpg", "output.jpg", 200, 300, function(err) { | ||
sharp.embedWhite("input.jpg", "output.png", 200, 300, function(err) { | ||
if (err) { | ||
@@ -71,3 +71,3 @@ throw err; | ||
// output.jpg is a 200 pixels wide and 300 pixels high image | ||
// containing a scaled version of input.jpg embedded on a white canvas | ||
// containing a scaled version of input.png embedded on a white canvas | ||
}); | ||
@@ -78,11 +78,11 @@ ``` | ||
Scale and embed JPEG `inputPath` to `width` x `height` using a black canvas and write JPEG to `outputPath` calling `callback` when complete. | ||
Scale and embed `inputPath` to `width` x `height` using a black canvas and write to `outputPath` calling `callback` when complete. | ||
```javascript | ||
sharp.embedBlack("input.jpg", "output.jpg", 200, 300, function(err) { | ||
sharp.embedBlack("input.png", "output.png", 200, 300, function(err) { | ||
if (err) { | ||
throw err; | ||
} | ||
// output.jpg is a 200 pixels wide and 300 pixels high image | ||
// containing a scaled version of input.jpg embedded on a black canvas | ||
// output.png is a 200 pixels wide and 300 pixels high image | ||
// containing a scaled version of input.png embedded on a black canvas | ||
}); | ||
@@ -98,27 +98,35 @@ ``` | ||
### AMD Athlon 4x core 3.3GHz 512KB L2 | ||
Test environment: | ||
* imagemagick x 5.55 ops/sec ±0.45% (31 runs sampled) | ||
* gm x 10.31 ops/sec ±3.57% (53 runs sampled) | ||
* epeg x 27.79 ops/sec ±0.12% (69 runs sampled) | ||
* sharp x 31.52 ops/sec ±8.74% (80 runs sampled) | ||
* AMD Athlon 4 core 3.3GHz 512KB L2 CPU 1333 DDR3 | ||
* libvips 7.36 | ||
* libjpeg-turbo8 1.2.1 | ||
* libpng 1.6.6 | ||
* zlib1g 1.2.7 | ||
### AWS t1.micro | ||
#### JPEG | ||
* imagemagick x 1.36 ops/sec ±0.96% (11 runs sampled) | ||
* sharp x 12.42 ops/sec ±5.84% (64 runs sampled) | ||
* imagemagick x 5.53 ops/sec ±0.55% (31 runs sampled) | ||
* gm x 10.86 ops/sec ±0.43% (56 runs sampled) | ||
* epeg x 28.07 ops/sec ±0.07% (70 runs sampled) | ||
* sharp x 31.60 ops/sec ±8.80% (80 runs sampled) | ||
### AWS m1.medium | ||
#### PNG | ||
* imagemagick x 1.38 ops/sec ±0.45% (11 runs sampled) | ||
* sharp x 12.66 ops/sec ±5.54% (65 runs sampled) | ||
* imagemagick x 4.65 ops/sec ±0.37% (27 runs sampled) | ||
* gm x 21.65 ops/sec ±0.18% (56 runs sampled) | ||
* sharp x 39.47 ops/sec ±6.78% (68 runs sampled) | ||
### AWS c1.medium | ||
## Licence | ||
* imagemagick x 2.10 ops/sec ±0.67% (15 runs sampled) | ||
* sharp x 18.97 ops/sec ±10.54% (52 runs sampled) | ||
Copyright 2013 Lovell Fuller | ||
### AWS m3.xlarge | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0.html) | ||
* imagemagick x 4.46 ops/sec ±0.33% (26 runs sampled) | ||
* sharp x 28.89 ops/sec ±7.75% (74 runs sampled) | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. |
@@ -5,61 +5,118 @@ var sharp = require("../index"); | ||
var epeg = require("epeg"); | ||
var async = require("async"); | ||
var assert = require("assert"); | ||
var Benchmark = require("benchmark"); | ||
var input = __dirname + "/2569067123_aca715a2ee_o.jpg"; // http://www.flickr.com/photos/grizdave/2569067123/ | ||
var output = __dirname + "/output.jpg"; | ||
var inputJpg = __dirname + "/2569067123_aca715a2ee_o.jpg"; // http://www.flickr.com/photos/grizdave/2569067123/ | ||
var outputJpg = __dirname + "/output.jpg"; | ||
var inputPng = __dirname + "/50020484-00001.png"; // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png | ||
var outputPng = __dirname + "/output.png"; | ||
var width = 640; | ||
var height = 480; | ||
var suite = new Benchmark.Suite; | ||
suite.add("imagemagick", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
imagemagick.resize({ | ||
srcPath: input, | ||
dstPath: output, | ||
quality: 0.75, | ||
width: width, | ||
height: height | ||
}, function(err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
deferred.resolve(); | ||
async.series({ | ||
jpeg: function(callback) { | ||
(new Benchmark.Suite("jpeg")).add("imagemagick", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
imagemagick.resize({ | ||
srcPath: inputJpg, | ||
dstPath: outputJpg, | ||
quality: 0.8, | ||
width: width, | ||
height: height | ||
}, function(err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
deferred.resolve(); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
}).add("gm", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
gm(input).crop(width, height).write(output, function (err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
deferred.resolve(); | ||
}).add("gm", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
gm(inputJpg).crop(width, height).quality(80).write(outputJpg, function (err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
deferred.resolve(); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
}).add("epeg", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
var image = new epeg.Image({path: input}); | ||
image.downsize(width, height).saveTo(output); | ||
deferred.resolve(); | ||
} | ||
}).add("sharp", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
sharp.crop(input, output, width, height, function(err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
}).add("epeg", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
var image = new epeg.Image({path: inputJpg}); | ||
image.downsize(width, height, 80).saveTo(outputJpg); | ||
deferred.resolve(); | ||
} | ||
}); | ||
}).add("sharp", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
sharp.crop(inputJpg, outputJpg, width, height, function(err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
deferred.resolve(); | ||
} | ||
}); | ||
} | ||
}).on("cycle", function(event) { | ||
console.log("jpeg " + String(event.target)); | ||
}).on("complete", function() { | ||
callback(null, this.filter("fastest").pluck("name")); | ||
}).run(); | ||
}, | ||
png: function(callback) { | ||
(new Benchmark.Suite("png")).add("imagemagick", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
imagemagick.resize({ | ||
srcPath: inputPng, | ||
dstPath: outputPng, | ||
width: width, | ||
height: height | ||
}, function(err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
deferred.resolve(); | ||
} | ||
}); | ||
} | ||
}).add("gm", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
gm(inputPng).crop(width, height).write(outputPng, function (err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
deferred.resolve(); | ||
} | ||
}); | ||
} | ||
}).add("sharp", { | ||
"defer": true, | ||
"fn": function(deferred) { | ||
sharp.crop(inputPng, outputPng, width, height, function(err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
deferred.resolve(); | ||
} | ||
}); | ||
} | ||
}).on("cycle", function(event) { | ||
console.log(" png " + String(event.target)); | ||
}).on("complete", function() { | ||
callback(null, this.filter("fastest").pluck("name")); | ||
}).run(); | ||
} | ||
}).on("cycle", function(event) { | ||
console.log(String(event.target)); | ||
}).on("complete", function() { | ||
assert(this.filter("fastest").pluck("name") == "sharp"); | ||
}).run(); | ||
}, function(err, results) { | ||
results.forEach(function(format, fastest) { | ||
assert(fastest === "sharp", "sharp was slower than " + fastest + " for " + format); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
943589
10.43%127
76.39%126
6.78%5
25%