Expose libvips interpolators #69

This commit is contained in:
Lovell Fuller 2014-08-22 16:50:24 +01:00
parent 6498fc3a9e
commit 017bf1e905
4 changed files with 112 additions and 46 deletions

View File

@ -110,21 +110,33 @@ image.metadata(function(err, metadata) {
``` ```
```javascript ```javascript
var pipeline = sharp().rotate().resize(null, 200).progressive().toBuffer(function(err, outputBuffer, info) { var pipeline = sharp()
if (err) { .rotate()
throw err; .resize(null, 200)
} .progressive()
// outputBuffer contains 200px high progressive JPEG image data, auto-rotated using EXIF Orientation tag .toBuffer(function(err, outputBuffer, info) {
// info.width and info.height contain the final pixel dimensions of the resized image if (err) {
}); throw err;
}
// outputBuffer contains 200px high progressive JPEG image data,
// auto-rotated using EXIF Orientation tag
// info.width and info.height contain the dimensions of the resized image
});
readableStream.pipe(pipeline); readableStream.pipe(pipeline);
``` ```
```javascript ```javascript
sharp('input.png').rotate(180).resize(300).sharpen().quality(90).webp().toBuffer().then(function(outputBuffer, info) { sharp('input.png')
// outputBuffer contains 300px wide, upside down, sharpened, 90% quality WebP image data .rotate(180)
// info.width and info.height contain the final pixel dimensions of the resized image .resize(300)
}); .sharpen()
.quality(90)
.webp()
.toBuffer()
.then(function(outputBuffer) {
// outputBuffer contains 300px wide, upside down, sharpened,
// 90% quality WebP image data
});
``` ```
```javascript ```javascript
@ -137,10 +149,16 @@ http.createServer(function(request, response) {
``` ```
```javascript ```javascript
sharp(inputBuffer).resize(200, 300).bicubicInterpolation().embedWhite().toFile('output.tiff').then(function() { sharp(inputBuffer)
// output.tiff is a 200 pixels wide and 300 pixels high image containing a bicubic scaled .resize(200, 300)
// version, embedded on a white canvas, of the image data in buffer .interpolateWith(sharp.interpolator.nohalo)
}); .embedWhite()
.toFile('output.tiff')
.then(function() {
// output.tiff is a 200 pixels wide and 300 pixels high image
// containing a bicubic scaled version, embedded on a white canvas,
// of the image data in inputBuffer
});
``` ```
```javascript ```javascript
@ -247,17 +265,17 @@ This is equivalent to GraphicsMagick's `>` geometry option: "change the dimensio
Perform a mild sharpen of the resultant image. This typically reduces performance by 30%. Perform a mild sharpen of the resultant image. This typically reduces performance by 30%.
#### bilinearInterpolation() #### interpolateWith(interpolator)
Use [bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation) for image resizing, the default (and fastest) interpolation if none is specified. Use the given interpolator for image resizing, where `interpolator` is an attribute of the `sharp.interpolator` Object e.g. `sharp.interpolator.bicubic`.
#### bicubicInterpolation() Possible interpolators, in order of performance, are:
Use [bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation) for image resizing. This typically reduces performance by 5%. * `bilinear`: Use [bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation), the default (and fastest) interpolation.
* `bicubic`: Use [bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation), which typically reduces performance by 5%.
#### nohaloInterpolation() * `vertexSplitQuadraticBasisSpline`: Use [VSQBS interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/vsqbs.cpp#L48), which prevents "staircasing" when enlarging and typically reduces performance by 5%.
* `locallyBoundedBicubic`: Use [LBB interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/lbb.cpp#L100), which prevents some "[acutance](http://en.wikipedia.org/wiki/Acutance)" and typically reduces performance by a factor of 2.
Use [Nohalo interpolation](http://eprints.soton.ac.uk/268086/) for image resizing. This typically reduces performance by a factor of 2. * `nohalo`: Use [Nohalo interpolation](http://eprints.soton.ac.uk/268086/), which prevents acutance and typically reduces performance by a factor of 3.
### Output options ### Output options

View File

@ -135,28 +135,32 @@ Sharp.prototype.sharpen = function(sharpen) {
}; };
/* /*
Use bilinear interpolation for the affine transformation (fastest, default) Set the interpolator to use for the affine transformation
*/ */
Sharp.prototype.bilinearInterpolation = function() { module.exports.interpolator = {
this.options.interpolator = 'bilinear'; bilinear: 'bilinear',
bicubic: 'bicubic',
nohalo: 'nohalo',
locallyBoundedBicubic: 'lbb',
vertexSplitQuadraticBasisSpline: 'vsqbs'
};
Sharp.prototype.interpolateWith = function(interpolator) {
this.options.interpolator = interpolator;
return this; return this;
}; };
/* /*
Use bicubic interpolation for the affine transformation Deprecated interpolation methods, to be removed in v0.7.0
*/ */
Sharp.prototype.bicubicInterpolation = function() { Sharp.prototype.bilinearInterpolation = util.deprecate(function() {
this.options.interpolator = 'bicubic'; return this.interpolateWith(module.exports.interpolator.bilinear);
return this; }, 'bilinearInterpolation() is deprecated, use interpolateWith(sharp.interpolator.bilinear) instead');
}; Sharp.prototype.bicubicInterpolation = util.deprecate(function() {
return this.interpolateWith(module.exports.interpolator.bicubic);
/* }, 'bicubicInterpolation() is deprecated, use interpolateWith(sharp.interpolator.bicubic) instead');
Use Nohalo interpolation for the affine transformation Sharp.prototype.nohaloInterpolation = util.deprecate(function() {
*/ return this.interpolateWith(module.exports.interpolator.nohalo);
Sharp.prototype.nohaloInterpolation = function() { }, 'nohaloInterpolation() is deprecated, use interpolateWith(sharp.interpolator.nohalo) instead');
this.options.interpolator = 'nohalo';
return this;
};
Sharp.prototype.progressive = function(progressive) { Sharp.prototype.progressive = function(progressive) {
this.options.progressive = (typeof progressive === 'boolean') ? progressive : true; this.options.progressive = (typeof progressive === 'boolean') ? progressive : true;

View File

@ -188,7 +188,7 @@ async.series({
}).add("sharp-file-buffer-bicubic", { }).add("sharp-file-buffer-bicubic", {
defer: true, defer: true,
fn: function(deferred) { fn: function(deferred) {
sharp(inputJpg).resize(width, height).bicubicInterpolation().toBuffer(function(err, buffer) { sharp(inputJpg).resize(width, height).interpolateWith(sharp.interpolator.bicubic).toBuffer(function(err, buffer) {
if (err) { if (err) {
throw err; throw err;
} else { } else {
@ -200,7 +200,31 @@ async.series({
}).add("sharp-file-buffer-nohalo", { }).add("sharp-file-buffer-nohalo", {
defer: true, defer: true,
fn: function(deferred) { fn: function(deferred) {
sharp(inputJpg).resize(width, height).nohaloInterpolation().toBuffer(function(err, buffer) { sharp(inputJpg).resize(width, height).interpolateWith(sharp.interpolator.nohalo).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add("sharp-file-buffer-locallyBoundedBicubic", {
defer: true,
fn: function(deferred) {
sharp(inputJpg).resize(width, height).interpolateWith(sharp.interpolator.locallyBoundedBicubic).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add("sharp-file-buffer-vertexSplitQuadraticBasisSpline", {
defer: true,
fn: function(deferred) {
sharp(inputJpg).resize(width, height).interpolateWith(sharp.interpolator.vertexSplitQuadraticBasisSpline).toBuffer(function(err, buffer) {
if (err) { if (err) {
throw err; throw err;
} else { } else {

View File

@ -249,7 +249,7 @@ async.series([
}, },
// Interpolation: bilinear // Interpolation: bilinear
function(done) { function(done) {
sharp(inputJpg).resize(320, 240).bilinearInterpolation().toBuffer(function(err, data, info) { sharp(inputJpg).resize(320, 240).interpolateWith(sharp.interpolator.bilinear).toBuffer(function(err, data, info) {
if (err) throw err; if (err) throw err;
assert.strictEqual(true, data.length > 0); assert.strictEqual(true, data.length > 0);
assert.strictEqual(320, info.width); assert.strictEqual(320, info.width);
@ -259,7 +259,7 @@ async.series([
}, },
// Interpolation: bicubic // Interpolation: bicubic
function(done) { function(done) {
sharp(inputJpg).resize(320, 240).bicubicInterpolation().toBuffer(function(err, data, info) { sharp(inputJpg).resize(320, 240).interpolateWith(sharp.interpolator.bicubic).toBuffer(function(err, data, info) {
if (err) throw err; if (err) throw err;
assert.strictEqual(true, data.length > 0); assert.strictEqual(true, data.length > 0);
assert.strictEqual(320, info.width); assert.strictEqual(320, info.width);
@ -269,7 +269,27 @@ async.series([
}, },
// Interpolation: nohalo // Interpolation: nohalo
function(done) { function(done) {
sharp(inputJpg).resize(320, 240).nohaloInterpolation().toBuffer(function(err, data, info) { sharp(inputJpg).resize(320, 240).interpolateWith(sharp.interpolator.nohalo).toBuffer(function(err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
done();
});
},
// Interpolation: locally bounded bicubic (LBB)
function(done) {
sharp(inputJpg).resize(320, 240).interpolateWith(sharp.interpolator.locallyBoundedBicubic).toBuffer(function(err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
done();
});
},
// Interpolation: vertex split quadratic basis spline (VSQBS)
function(done) {
sharp(inputJpg).resize(320, 240).interpolateWith(sharp.interpolator.vertexSplitQuadraticBasisSpline).toBuffer(function(err, data, info) {
if (err) throw err; if (err) throw err;
assert.strictEqual(true, data.length > 0); assert.strictEqual(true, data.length > 0);
assert.strictEqual(320, info.width); assert.strictEqual(320, info.width);
@ -346,7 +366,7 @@ async.series([
}); });
}); });
var pipeline = sharp().resize(320, 240); var pipeline = sharp().resize(320, 240);
readable.pipe(pipeline).pipe(writable) readable.pipe(pipeline).pipe(writable);
}, },
// Crop, gravity=north // Crop, gravity=north
function(done) { function(done) {
@ -516,7 +536,7 @@ async.series([
assert.strictEqual(1362, info.width); assert.strictEqual(1362, info.width);
assert.strictEqual(1112, info.height); assert.strictEqual(1112, info.height);
done(); done();
}) });
}); });
}, },
// Verify internal counters // Verify internal counters