From 73195339695dbad73e32d0e7c8e8099ce2cc0d90 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sun, 1 Jun 2014 11:27:30 +0100 Subject: [PATCH] Add support for Promises/A+ #33 --- README.md | 51 ++++++++++++++++++++++++++------------------------- index.js | 30 +++++++++++++++++++++++------- package.json | 5 +++-- tests/unit.js | 16 ++++++++++++++++ 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index dbefdb72..8ab749f4 100755 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ 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. Everything remains non-blocking thanks to _libuv_. +The performance of JPEG resizing is typically 8x faster than ImageMagick and GraphicsMagick, based mainly on the number of CPU cores available. Everything remains non-blocking thanks to _libuv_ and Promises/A+ are supported. This module supports reading and writing images of JPEG, PNG and WebP to and from both Buffer objects and the filesystem. It also supports reading images of many other types from the filesystem via libmagick++ or libgraphicsmagick++ if present. @@ -94,19 +94,13 @@ sharp('input.jpg').rotate().resize(null, 200).progressive().toBuffer(function(er ``` ```javascript -sharp('input.png').rotate(180).resize(300).sharpen().quality(90).webp(function(err, outputBuffer) { - if (err) { - throw err; - } +sharp('input.png').rotate(180).resize(300).sharpen().quality(90).webp().then(function(outputBuffer) { // outputBuffer contains 300px wide, upside down, sharpened, 90% quality WebP image data }); ``` ```javascript -sharp(inputBuffer).resize(200, 300).embedWhite().toFile('output.tiff', function(err) { - if (err) { - throw err; - } +sharp(inputBuffer).resize(200, 300).embedWhite().toFile('output.tiff').then(function() { // output.tiff is a 200 pixels wide and 300 pixels high image containing a scaled // version, embedded on a white canvas, of the image data in buffer }); @@ -123,10 +117,7 @@ sharp('input.gif').resize(200, 300).embedBlack().webp(function(err, outputBuffer ``` ```javascript -sharp(inputBuffer).resize(200, 200).max().jpeg(function(err, outputBuffer) { - if (err) { - throw err; - } +sharp(inputBuffer).resize(200, 200).max().jpeg().then(function(outputBuffer) { // outputBuffer contains JPEG image data no wider than 200 pixels and no higher // than 200 pixels regardless of the inputBuffer image dimensions }); @@ -205,35 +196,45 @@ An advanced setting for the _zlib_ compression level of the lossless PNG output An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`. This will reduce memory usage and can improve performance on some systems. -### toFile(filename, callback) +### toFile(filename, [callback]) `filename` is a String containing the filename to write the image data to. The format is inferred from the extension, with JPEG, PNG, WebP and TIFF supported. -`callback` is called with a single argument `(err)` containing an error message, if any. +`callback`, if present, is called with a single argument `(err)` containing an error message, if any. -### jpeg(callback) +A Promises/A+ promise is returned when `callback` is not provided. + +### toBuffer([callback]) + +Write image data to a Buffer, the format of which will match the input image. JPEG, PNG and WebP are supported. + +`callback`, if present, gets two arguments `(err, buffer)` where `err` is an error message, if any, and `buffer` is the resultant image data. + +A Promises/A+ promise is returned when `callback` is not provided. + +### jpeg([callback]) Write JPEG image data to a Buffer. -`callback` gets two arguments `(err, buffer)` where `err` is an error message, if any, and `buffer` is the resultant JPEG image data. +`callback`, if present, gets two arguments `(err, buffer)` where `err` is an error message, if any, and `buffer` is the resultant JPEG image data. + +A Promises/A+ promise is returned when `callback` is not provided. ### png(callback) Write PNG image data to a Buffer. -`callback` gets two arguments `(err, buffer)` where `err` is an error message, if any, and `buffer` is the resultant PNG image data. +`callback`, if present, gets two arguments `(err, buffer)` where `err` is an error message, if any, and `buffer` is the resultant PNG image data. -### webp(callback) +A Promises/A+ promise is returned when `callback` is not provided. + +### webp([callback]) Write WebP image data to a Buffer. -`callback` gets two arguments `(err, buffer)` where `err` is an error message, if any, and `buffer` is the resultant WebP image data. +`callback`, if present, gets two arguments `(err, buffer)` where `err` is an error message, if any, and `buffer` is the resultant WebP image data. -### toBuffer(callback) - -Write image data to a Buffer, the format of which will match the input image. JPEG, PNG and WebP are supported. - -`callback` gets two arguments `(err, buffer)` where `err` is an error message, if any, and `buffer` is the resultant image data. +A Promises/A+ promise is returned when `callback` is not provided. ### sharp.cache([limit]) diff --git a/index.js b/index.js index b6c3310e..b59d06a6 100755 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ /*jslint node: true */ 'use strict'; +var Promise = require('bluebird'); var sharp = require('./build/Release/sharp'); var Sharp = function(input) { @@ -141,7 +142,7 @@ Sharp.prototype.toFile = function(output, callback) { if (this.options.fileIn === output) { callback('Cannot use same file for input and output'); } else { - this._sharp(output, callback); + return this._sharp(output, callback); } } return this; @@ -166,13 +167,28 @@ Sharp.prototype.webp = function(callback) { return this._sharp('__webp', callback); }; +/* + Invoke the C++ image processing pipeline + Supports callback and promise variants +*/ Sharp.prototype._sharp = function(output, callback) { - sharp.resize( - this.options, - output, - callback - ); - return this; + if (typeof callback === 'function') { + // I like callbacks + sharp.resize(this.options, output, callback); + return this; + } else { + // I like promises + var options = this.options; + return new Promise(function(resolve, reject) { + sharp.resize(options, output, function(err, data) { + if (err) { + reject(err); + } else { + resolve(data); + } + }); + }); + } }; module.exports.cache = function(limit) { diff --git a/package.json b/package.json index 6bb9cefa..51684d64 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sharp", - "version": "0.4.2", + "version": "0.5.0", "author": "Lovell Fuller ", "contributors": [ "Pierre Inglebert " @@ -31,7 +31,8 @@ "buffer" ], "dependencies": { - "nan": "^1.1.0" + "nan": "^1.1.2", + "bluebird": "^1.2.4" }, "devDependencies": { "imagemagick": "^0.1.3", diff --git a/tests/unit.js b/tests/unit.js index 8db8c823..1b396b6b 100755 --- a/tests/unit.js +++ b/tests/unit.js @@ -1,3 +1,7 @@ +/*jslint node: true */ +/*jslint es5: true */ +'use strict'; + var sharp = require("../index"); var path = require("path"); var imagemagick = require("imagemagick"); @@ -236,6 +240,18 @@ async.series([ done(); }); }); + }, + // Promises/A+ + function(done) { + sharp(inputJpg).resize(320, 240).toFile(outputJpg).then(function() { + imagemagick.identify(outputJpg, function(err, features) { + assert.strictEqual(320, features.width); + assert.strictEqual(240, features.height); + done(); + }); + }).catch(function(err) { + throw err; + }); } ]);