diff --git a/README.md b/README.md index 42ac11e4..a616fa94 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,9 @@ The typical use case for this high performance Node.js module is to convert a la 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. -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. Speed is typically 25-30% faster than the imagemagick equivalent. +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. + +Speed is typically 4x faster than the imagemagick equivalent. ## Prerequisites @@ -26,7 +28,7 @@ Ubuntu 12.04 LTS: sudo ln -s /usr/lib/pkgconfig/vips-7.26.pc /usr/lib/pkgconfig/vips.pc -Ubuntu 13.04: +Ubuntu 13.04 (64-bit): sudo ln -s /usr/lib/x86_64-linux-gnu/pkgconfig/vips-7.28.pc /usr/lib/pkgconfig/vips.pc @@ -36,28 +38,59 @@ Ubuntu 13.04: ## Usage + var sharp = require("sharp"); + +### crop(inputPath, outputPath, width, height, callback) + +Scale and crop JPEG `inputPath` to `width` x `height` and write JPEG to `outputPath` calling `callback` when complete. + +Example: + ```javascript -var sharp = require("sharp"); sharp.crop("input.jpg", "output.jpg", 300, 200, function(err) { if (err) { throw err; } - // output.jpg is cropped input.jpg + // output.jpg is a 300 pixels wide and 200 pixels high image + // containing a scaled and cropped version of input.jpg }); +``` + +### embedWhite(inputPath, outputPath, width, height, callback) + +Scale and embed JPEG `inputPath` to `width` x `height` using a white canvas and write JPEG to `outputPath` calling `callback` when complete. + +```javascript sharp.embedWhite("input.jpg", "output.jpg", 200, 300, function(err) { if (err) { throw err; } - // output.jpg contains input.jpg embedded with a white border + // output.jpg is a 300 pixels wide and 200 pixels high image + // containing a scaled version of input.jpg embedded on a white canvas }); +``` + +### embedBlack(inputPath, outputPath, width, height, callback) + +Scale and embed JPEG `inputPath` to `width` x `height` using a black canvas and write JPEG to `outputPath` calling `callback` when complete. + +```javascript sharp.embedBlack("input.jpg", "output.jpg", 200, 300, function(err) { if (err) { throw err; } - // output.jpg contains input.jpg embedded with a black border + // output.jpg is a 300 pixels wide and 200 pixels high image + // containing a scaled version of input.jpg embedded on a black canvas }); ``` ## Testing [![Build Status](https://travis-ci.org/lovell/sharp.png?branch=master)](https://travis-ci.org/lovell/sharp) npm test + +## Performance + +Using an AMD Athlon quad core CPU with 512KB L2 cache clocked at 3.3GHz with 8GB RAM: + +* imagemagick x 5.55 ops/sec ±0.68% (31 runs sampled) +* sharp x 24.49 ops/sec ±6.85% (64 runs sampled) diff --git a/package.json b/package.json index 3b64e186..614843aa 100755 --- a/package.json +++ b/package.json @@ -1,14 +1,15 @@ { "name": "sharp", - "version": "0.0.1", - "main": "./build/Release/sharp", + "version": "0.0.2", + "main": "index.js", "description": "High performance Node.js module to resize JPEG images using the libvips image processing library", "repository": { "type": "git", "url": "git://github.com/lovell/sharp" }, "devDependencies": { - "imagemagick": "*" + "imagemagick": "*", + "benchmark": "*" }, "scripts": { "test": "node tests/perf.js" @@ -20,11 +21,11 @@ "jpeg", "resize", "thumbnail", - "sharpen", - "crop", - "embed", + "sharpen", + "crop", + "embed", "libvips", - "fast" + "fast" ], "author": "Lovell Fuller", "license": "Apache 2.0" diff --git a/tests/perf.js b/tests/perf.js index 6fe98389..e28c1b58 100755 --- a/tests/perf.js +++ b/tests/perf.js @@ -1,42 +1,44 @@ var sharp = require("../index"); var imagemagick = require("imagemagick"); var assert = require("assert"); +var Benchmark = require("benchmark"); -// http://www.flickr.com/photos/grizdave/2569067123/ -var input = __dirname + "/2569067123_aca715a2ee_o.jpg"; +var input = __dirname + "/2569067123_aca715a2ee_o.jpg"; // http://www.flickr.com/photos/grizdave/2569067123/ var output = __dirname + "/output.jpg"; - var width = 640; var height = 480; -// imagemagick -var time = process.hrtime(); -imagemagick.resize({ - srcPath: input, - dstPath: output, - quality: 0.75, - width: width, - height: height -}, function(err) { - if (err) { - throw err; +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(); + } + }); } - var diff = process.hrtime(time); - imagemagickTime = diff[0] * 1e9 + diff[1]; - console.log("imagemagick took %d nanoseconds", imagemagickTime); - - // sharp - time = process.hrtime(); - sharp.crop(input, output, width, height, function(err) { - if (err) { - throw err; - } - diff = process.hrtime(time); - var sharpTime = diff[0] * 1e9 + diff[1]; - console.log("sharp took %d nanoseconds", sharpTime); - - // diff - assert(sharpTime < imagemagickTime, "sharp was blunt"); - console.log("sharp was %d%% faster", (imagemagickTime - sharpTime) / imagemagickTime * 100); - }); -}); +}).add("sharp", { + "defer": true, + "fn": function(deferred) { + sharp.crop(input, output, width, height, function(err) { + if (err) { + throw err; + } else { + deferred.resolve(); + } + }); + } +}).on("cycle", function(event) { + console.log(String(event.target)); +}).on("complete", function() { + assert(this.filter("fastest").pluck("name") == "sharp"); +}).run();