mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Add support for bicubic and Nohalo interpolation #41
This commit is contained in:
parent
f0a9d82bf7
commit
4eb910fec9
18
README.md
18
README.md
@ -53,7 +53,7 @@ Compiling from source is recommended:
|
|||||||
cd libvips
|
cd libvips
|
||||||
git checkout 7.38
|
git checkout 7.38
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
./configure --enable-debug=no --enable-cxx=no --without-python --without-orc
|
./configure --enable-debug=no --enable-cxx=yes --without-python --without-orc
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
@ -100,8 +100,8 @@ sharp('input.png').rotate(180).resize(300).sharpen().quality(90).webp().then(fun
|
|||||||
```
|
```
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
sharp(inputBuffer).resize(200, 300).embedWhite().toFile('output.tiff').then(function() {
|
sharp(inputBuffer).resize(200, 300).bicubicInterpolation().embedWhite().toFile('output.tiff').then(function() {
|
||||||
// output.tiff is a 200 pixels wide and 300 pixels high image containing a scaled
|
// 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 buffer
|
// version, embedded on a white canvas, of the image data in buffer
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
@ -176,6 +176,18 @@ 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()
|
||||||
|
|
||||||
|
Use [bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation) for image resizing, the default (and fastest) interpolation if none is specified.
|
||||||
|
|
||||||
|
### bicubicInterpolation()
|
||||||
|
|
||||||
|
Use [bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation) for image resizing. This typically reduces performance by 5%.
|
||||||
|
|
||||||
|
### nohaloInterpolation()
|
||||||
|
|
||||||
|
Use [Nohalo interpolation](http://eprints.soton.ac.uk/268086/) for image resizing. This typically reduces performance by a factor of 2.
|
||||||
|
|
||||||
### progressive()
|
### progressive()
|
||||||
|
|
||||||
Use progressive (interlace) scan for JPEG and PNG output. This typically reduces compression performance by 30% but results in an image that can be rendered sooner when decompressed.
|
Use progressive (interlace) scan for JPEG and PNG output. This typically reduces compression performance by 30% but results in an image that can be rendered sooner when decompressed.
|
||||||
|
25
index.js
25
index.js
@ -16,6 +16,7 @@ var Sharp = function(input) {
|
|||||||
angle: 0,
|
angle: 0,
|
||||||
withoutEnlargement: false,
|
withoutEnlargement: false,
|
||||||
sharpen: false,
|
sharpen: false,
|
||||||
|
interpolator: 'bilinear',
|
||||||
progressive: false,
|
progressive: false,
|
||||||
sequentialRead: false,
|
sequentialRead: false,
|
||||||
quality: 80,
|
quality: 80,
|
||||||
@ -87,6 +88,30 @@ Sharp.prototype.sharpen = function(sharpen) {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use bilinear interpolation for the affine transformation (fastest, default)
|
||||||
|
*/
|
||||||
|
Sharp.prototype.bilinearInterpolation = function() {
|
||||||
|
this.options.interpolator = 'bilinear';
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use bicubic interpolation for the affine transformation
|
||||||
|
*/
|
||||||
|
Sharp.prototype.bicubicInterpolation = function() {
|
||||||
|
this.options.interpolator = 'bicubic';
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use Nohalo interpolation for the affine transformation
|
||||||
|
*/
|
||||||
|
Sharp.prototype.nohaloInterpolation = function() {
|
||||||
|
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;
|
||||||
return this;
|
return this;
|
||||||
|
11
src/sharp.cc
11
src/sharp.cc
@ -23,6 +23,7 @@ struct resize_baton {
|
|||||||
bool max;
|
bool max;
|
||||||
VipsExtend extend;
|
VipsExtend extend;
|
||||||
bool sharpen;
|
bool sharpen;
|
||||||
|
std::string interpolator;
|
||||||
bool progressive;
|
bool progressive;
|
||||||
bool without_enlargement;
|
bool without_enlargement;
|
||||||
VipsAccess access_method;
|
VipsAccess access_method;
|
||||||
@ -294,12 +295,17 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
g_object_unref(shrunk_on_load);
|
g_object_unref(shrunk_on_load);
|
||||||
|
|
||||||
// Use vips_affine with the remaining float part using bilinear interpolation
|
// Use vips_affine with the remaining float part
|
||||||
VipsImage *affined = vips_image_new();
|
VipsImage *affined = vips_image_new();
|
||||||
if (residual != 0) {
|
if (residual != 0) {
|
||||||
if (vips_affine(shrunk, &affined, residual, 0, 0, residual, "interpolate", vips_interpolate_bilinear_static(), NULL)) {
|
// Create interpolator - "bilinear" (default), "bicubic" or "nohalo"
|
||||||
|
VipsInterpolate *interpolator = vips_interpolate_new(baton->interpolator.c_str());
|
||||||
|
// Perform affine transformation
|
||||||
|
if (vips_affine(shrunk, &affined, residual, 0, 0, residual, "interpolate", interpolator, NULL)) {
|
||||||
|
g_object_unref(interpolator);
|
||||||
return resize_error(baton, shrunk);
|
return resize_error(baton, shrunk);
|
||||||
}
|
}
|
||||||
|
g_object_unref(interpolator);
|
||||||
} else {
|
} else {
|
||||||
vips_copy(shrunk, &affined, NULL);
|
vips_copy(shrunk, &affined, NULL);
|
||||||
}
|
}
|
||||||
@ -461,6 +467,7 @@ NAN_METHOD(resize) {
|
|||||||
}
|
}
|
||||||
// Other options
|
// Other options
|
||||||
baton->sharpen = options->Get(NanNew<String>("sharpen"))->BooleanValue();
|
baton->sharpen = options->Get(NanNew<String>("sharpen"))->BooleanValue();
|
||||||
|
baton->interpolator = *String::Utf8Value(options->Get(NanNew<String>("interpolator"))->ToString());
|
||||||
baton->progressive = options->Get(NanNew<String>("progressive"))->BooleanValue();
|
baton->progressive = options->Get(NanNew<String>("progressive"))->BooleanValue();
|
||||||
baton->without_enlargement = options->Get(NanNew<String>("withoutEnlargement"))->BooleanValue();
|
baton->without_enlargement = options->Get(NanNew<String>("withoutEnlargement"))->BooleanValue();
|
||||||
baton->access_method = options->Get(NanNew<String>("sequentialRead"))->BooleanValue() ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
baton->access_method = options->Get(NanNew<String>("sequentialRead"))->BooleanValue() ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
||||||
|
@ -166,6 +166,30 @@ async.series({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}).add("sharp-file-buffer-bicubic", {
|
||||||
|
defer: true,
|
||||||
|
fn: function(deferred) {
|
||||||
|
sharp(inputJpg).resize(width, height).bicubicInterpolation().toBuffer(function(err, buffer) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
assert.notStrictEqual(null, buffer);
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).add("sharp-file-buffer-nohalo", {
|
||||||
|
defer: true,
|
||||||
|
fn: function(deferred) {
|
||||||
|
sharp(inputJpg).resize(width, height).nohaloInterpolation().toBuffer(function(err, buffer) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
assert.notStrictEqual(null, buffer);
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}).add("sharp-file-buffer-progressive", {
|
}).add("sharp-file-buffer-progressive", {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
|
@ -268,5 +268,41 @@ async.series([
|
|||||||
sharp(inputTiff).webp().then(function() {
|
sharp(inputTiff).webp().then(function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
// Interpolation: bilinear
|
||||||
|
function(done) {
|
||||||
|
sharp(inputJpg).resize(320, 240).bilinearInterpolation().toFile(outputJpg, function(err) {
|
||||||
|
if (err) throw err;
|
||||||
|
imagemagick.identify(outputJpg, function(err, features) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(320, features.width);
|
||||||
|
assert.strictEqual(240, features.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// Interpolation: bicubic
|
||||||
|
function(done) {
|
||||||
|
sharp(inputJpg).resize(320, 240).bicubicInterpolation().toFile(outputJpg, function(err) {
|
||||||
|
if (err) throw err;
|
||||||
|
imagemagick.identify(outputJpg, function(err, features) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(320, features.width);
|
||||||
|
assert.strictEqual(240, features.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// Interpolation: nohalo
|
||||||
|
function(done) {
|
||||||
|
sharp(inputJpg).resize(320, 240).nohaloInterpolation().toFile(outputJpg, function(err) {
|
||||||
|
if (err) throw err;
|
||||||
|
imagemagick.identify(outputJpg, function(err, features) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(320, features.width);
|
||||||
|
assert.strictEqual(240, features.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user