Compare commits

...

17 Commits

Author SHA1 Message Date
Lovell Fuller
8acb0ed5d0 Enable libvips C++ interpolators in Travis CI 2014-06-18 21:08:09 +01:00
Lovell Fuller
430e04d894 Update (and reduce) dependencies ahead of v0.5.1 2014-06-17 20:24:22 +01:00
Lovell Fuller
012edb4379 Support existing path to pkg-config lib for Heroku #57 2014-06-17 19:55:41 +01:00
Lovell Fuller
11ead360a9 Add Promises benchmark 2014-06-13 19:20:39 +01:00
Lovell Fuller
84a059d7e3 Rotate should throw Error, not String.
Minor JSLint and whitespace fixes.
2014-06-13 18:57:54 +01:00
Lovell Fuller
b1b070ae5c Revert "use native Promise if available"
This reverts commit 261a90c8a2.
2014-06-13 18:46:36 +01:00
Lovell Fuller
4eb910fec9 Add support for bicubic and Nohalo interpolation #41 2014-06-08 20:46:03 +01:00
Lovell Fuller
f0a9d82bf7 Always convert to sRGB colourspace to prevent libwebp segfault #58 2014-06-07 22:49:15 +01:00
Lovell Fuller
6d20a1ca81 Simplify gyp to support non-standard brew installs #56 2014-06-05 22:19:02 +01:00
Lovell Fuller
eca2787213 Add @jonathanong to contributors - thank you!
Bump versions
2014-06-05 22:18:47 +01:00
Lovell Fuller
8d146accf3 Correct docs - callback is optional for png 2014-06-05 22:00:39 +01:00
Lovell Fuller
b635d015cd Merge pull request #55 from jonathanong/native-promises
use native Promise if available
2014-06-04 20:48:17 +01:00
Jonathan Ong
261a90c8a2 use native Promise if available 2014-06-04 09:03:37 -07:00
Lovell Fuller
4ae22b3425 Merge pull request #51 from jonathanong/deprecate-write
show deprecation warning for .write()
2014-06-04 10:43:59 +01:00
Lovell Fuller
c9aa9c7723 Merge pull request #49 from jonathanong/strings-are-not-errors
fix error types, support promises on convenience methods
2014-06-04 10:35:06 +01:00
Jonathan Ong
5e0b5969da show deprecation warning for .write() 2014-06-03 20:53:37 -07:00
Jonathan Ong
ae6d5e69b1 fix error types, support promises on convenience methods
closes #48
2014-06-03 20:41:15 -07:00
8 changed files with 184 additions and 84 deletions

View File

@@ -10,7 +10,7 @@ before_install:
- cd libvips - cd libvips
- git checkout 7.38 - git checkout 7.38
- ./bootstrap.sh - ./bootstrap.sh
- ./configure --enable-debug=no --enable-cxx=no --without-orc --without-python - ./configure --enable-debug=no --enable-cxx=yes --without-orc --without-python
- make - make
- sudo make install - sudo make install
- sudo ldconfig - sudo ldconfig

View File

@@ -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.
@@ -220,7 +232,7 @@ Write JPEG image data to a Buffer.
A Promises/A+ promise is returned when `callback` is not provided. A Promises/A+ promise is returned when `callback` is not provided.
### png(callback) ### png([callback])
Write PNG image data to a Buffer. Write PNG image data to a Buffer.

View File

@@ -2,16 +2,14 @@
'targets': [{ 'targets': [{
'target_name': 'sharp', 'target_name': 'sharp',
'sources': ['src/sharp.cc'], 'sources': ['src/sharp.cc'],
'variables': {
'PKG_CONFIG_PATH': '<!(which brew >/dev/null 2>&1 && eval $(brew --env) && echo $PKG_CONFIG_LIBDIR || true):$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig'
},
'libraries': [ 'libraries': [
'<!@(PKG_CONFIG_PATH="/usr/local/Library/ENV/pkgconfig/10.8:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig" pkg-config --libs vips)' '<!(PKG_CONFIG_PATH="<(PKG_CONFIG_PATH)" pkg-config --libs vips)'
], ],
'include_dirs': [ 'include_dirs': [
'/usr/local/include/glib-2.0', '<!(PKG_CONFIG_PATH="<(PKG_CONFIG_PATH)" pkg-config --cflags vips glib-2.0)',
'/usr/local/lib/glib-2.0/include',
'/usr/include/glib-2.0',
'/usr/lib/glib-2.0/include',
'/usr/lib/x86_64-linux-gnu/glib-2.0/include',
'/usr/lib/i386-linux-gnu/glib-2.0/include',
'<!(node -e "require(\'nan\')")' '<!(node -e "require(\'nan\')")'
], ],
'cflags': ['-fexceptions', '-pedantic', '-Wall', '-O3'], 'cflags': ['-fexceptions', '-pedantic', '-Wall', '-O3'],

View File

@@ -15,10 +15,11 @@ 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,
compressionLevel: 6, compressionLevel: 6,
output: '__jpeg' output: '__jpeg'
}; };
if (typeof input === 'string') { if (typeof input === 'string') {
@@ -27,10 +28,10 @@ var Sharp = function(input) {
if (input.length > 0) { if (input.length > 0) {
this.options.bufferIn = input; this.options.bufferIn = input;
} else { } else {
throw 'Buffer is empty'; throw new Error('Buffer is empty');
} }
} else { } else {
throw 'Unsupported input ' + typeof input; throw new Error('Unsupported input ' + typeof input);
} }
return this; return this;
}; };
@@ -66,7 +67,7 @@ Sharp.prototype.rotate = function(angle) {
} else if (!Number.isNaN(angle) && [0, 90, 180, 270].indexOf(angle) !== -1) { } else if (!Number.isNaN(angle) && [0, 90, 180, 270].indexOf(angle) !== -1) {
this.options.angle = angle; this.options.angle = angle;
} else { } else {
throw 'Unsupport angle (0, 90, 180, 270) ' + angle; throw new Error('Unsupported angle (0, 90, 180, 270) ' + angle);
} }
return this; return this;
}; };
@@ -86,6 +87,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;
@@ -100,7 +125,7 @@ Sharp.prototype.quality = function(quality) {
if (!Number.isNaN(quality) && quality >= 1 && quality <= 100) { if (!Number.isNaN(quality) && quality >= 1 && quality <= 100) {
this.options.quality = quality; this.options.quality = quality;
} else { } else {
throw 'Invalid quality (1 to 100) ' + quality; throw new Error('Invalid quality (1 to 100) ' + quality);
} }
return this; return this;
}; };
@@ -109,7 +134,7 @@ Sharp.prototype.compressionLevel = function(compressionLevel) {
if (!Number.isNaN(compressionLevel) && compressionLevel >= -1 && compressionLevel <= 9) { if (!Number.isNaN(compressionLevel) && compressionLevel >= -1 && compressionLevel <= 9) {
this.options.compressionLevel = compressionLevel; this.options.compressionLevel = compressionLevel;
} else { } else {
throw 'Invalid compressionLevel (-1 to 9) ' + compressionLevel; throw new Error('Invalid compressionLevel (-1 to 9) ' + compressionLevel);
} }
return this; return this;
}; };
@@ -121,7 +146,7 @@ Sharp.prototype.resize = function(width, height) {
if (!Number.isNaN(width)) { if (!Number.isNaN(width)) {
this.options.width = width; this.options.width = width;
} else { } else {
throw 'Invalid width ' + width; throw new Error('Invalid width ' + width);
} }
} }
if (!height) { if (!height) {
@@ -130,7 +155,7 @@ Sharp.prototype.resize = function(width, height) {
if (!Number.isNaN(height)) { if (!Number.isNaN(height)) {
this.options.height = height; this.options.height = height;
} else { } else {
throw 'Invalid height ' + height; throw new Error('Invalid height ' + height);
} }
} }
return this; return this;
@@ -141,10 +166,20 @@ Sharp.prototype.resize = function(width, height) {
*/ */
Sharp.prototype.toFile = function(output, callback) { Sharp.prototype.toFile = function(output, callback) {
if (!output || output.length === 0) { if (!output || output.length === 0) {
callback('Invalid output'); var errOutputInvalid = new Error('Invalid output');
if (typeof callback === 'function') {
callback(errOutputInvalid);
} else {
return Promise.reject(errOutputInvalid);
}
} else { } else {
if (this.options.fileIn === output) { if (this.options.fileIn === output) {
callback('Cannot use same file for input and output'); var errOutputIsInput = new Error('Cannot use same file for input and output');
if (typeof callback === 'function') {
callback(errOutputIsInput);
} else {
return Promise.reject(errOutputIsInput);
}
} else { } else {
return this._sharp(output, callback); return this._sharp(output, callback);
} }
@@ -153,7 +188,10 @@ Sharp.prototype.toFile = function(output, callback) {
}; };
// Deprecated to make way for future stream support - remove in v0.6.0 // Deprecated to make way for future stream support - remove in v0.6.0
Sharp.prototype.write = Sharp.prototype.toFile; Sharp.prototype.write = require('util').deprecate(
Sharp.prototype.toFile,
'.write() is deprecated and will be removed in v0.6.0. Use .toFile() instead.'
);
Sharp.prototype.toBuffer = function(callback) { Sharp.prototype.toBuffer = function(callback) {
return this._sharp('__input', callback); return this._sharp('__input', callback);

View File

@@ -1,9 +1,10 @@
{ {
"name": "sharp", "name": "sharp",
"version": "0.5.0", "version": "0.5.1",
"author": "Lovell Fuller <npm@lovell.info>", "author": "Lovell Fuller <npm@lovell.info>",
"contributors": [ "contributors": [
"Pierre Inglebert <pierre.inglebert@gmail.com>" "Pierre Inglebert <pierre.inglebert@gmail.com>",
"Jonathan Ong <jonathanrichardong@gmail.com>"
], ],
"description": "High performance Node.js module to resize JPEG, PNG and WebP images using the libvips library", "description": "High performance Node.js module to resize JPEG, PNG and WebP images using the libvips library",
"scripts": { "scripts": {
@@ -31,12 +32,12 @@
"buffer" "buffer"
], ],
"dependencies": { "dependencies": {
"nan": "^1.1.2", "nan": "^1.2.0",
"bluebird": "^1.2.4" "bluebird": "^2.1.2"
}, },
"devDependencies": { "devDependencies": {
"imagemagick": "^0.1.3", "imagemagick": "^0.1.3",
"imagemagick-native": "^1.0.0", "imagemagick-native": "^1.1.1",
"gm": "^1.16.0", "gm": "^1.16.0",
"async": "^0.9.0", "async": "^0.9.0",
"benchmark": "^1.0.0" "benchmark": "^1.0.0"

View File

@@ -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);
} }
@@ -359,46 +365,51 @@ class ResizeWorker : public NanAsyncWorker {
} }
g_object_unref(canvased); g_object_unref(canvased);
// Always convert to sRGB colour space
VipsImage *colourspaced = vips_image_new();
vips_colourspace(sharpened, &colourspaced, VIPS_INTERPRETATION_sRGB, NULL);
g_object_unref(sharpened);
// Output // Output
if (baton->file_out == "__jpeg" || (baton->file_out == "__input" && inputImageType == JPEG)) { if (baton->file_out == "__jpeg" || (baton->file_out == "__input" && inputImageType == JPEG)) {
// Write JPEG to buffer // Write JPEG to buffer
if (vips_jpegsave_buffer(sharpened, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) { if (vips_jpegsave_buffer(colourspaced, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
return resize_error(baton, sharpened); return resize_error(baton, colourspaced);
} }
} else if (baton->file_out == "__png" || (baton->file_out == "__input" && inputImageType == PNG)) { } else if (baton->file_out == "__png" || (baton->file_out == "__input" && inputImageType == PNG)) {
// Write PNG to buffer // Write PNG to buffer
if (vips_pngsave_buffer(sharpened, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) { if (vips_pngsave_buffer(colourspaced, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) {
return resize_error(baton, sharpened); return resize_error(baton, colourspaced);
} }
} else if (baton->file_out == "__webp" || (baton->file_out == "__input" && inputImageType == WEBP)) { } else if (baton->file_out == "__webp" || (baton->file_out == "__input" && inputImageType == WEBP)) {
// Write WEBP to buffer // Write WEBP to buffer
if (vips_webpsave_buffer(sharpened, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, NULL)) { if (vips_webpsave_buffer(colourspaced, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, NULL)) {
return resize_error(baton, sharpened); return resize_error(baton, colourspaced);
} }
} else if (is_jpeg(baton->file_out)) { } else if (is_jpeg(baton->file_out)) {
// Write JPEG to file // Write JPEG to file
if (vips_jpegsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) { if (vips_jpegsave(colourspaced, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
return resize_error(baton, sharpened); return resize_error(baton, colourspaced);
} }
} else if (is_png(baton->file_out)) { } else if (is_png(baton->file_out)) {
// Write PNG to file // Write PNG to file
if (vips_pngsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) { if (vips_pngsave(colourspaced, baton->file_out.c_str(), "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) {
return resize_error(baton, sharpened); return resize_error(baton, colourspaced);
} }
} else if (is_webp(baton->file_out)) { } else if (is_webp(baton->file_out)) {
// Write WEBP to file // Write WEBP to file
if (vips_webpsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, NULL)) { if (vips_webpsave(colourspaced, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, NULL)) {
return resize_error(baton, sharpened); return resize_error(baton, colourspaced);
} }
} else if (is_tiff(baton->file_out)) { } else if (is_tiff(baton->file_out)) {
// Write TIFF to file // Write TIFF to file
if (vips_tiffsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, "Q", baton->quality, NULL)) { if (vips_tiffsave(colourspaced, baton->file_out.c_str(), "strip", TRUE, "compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, "Q", baton->quality, NULL)) {
return resize_error(baton, sharpened); return resize_error(baton, colourspaced);
} }
} else { } else {
(baton->err).append("Unsupported output " + baton->file_out); (baton->err).append("Unsupported output " + baton->file_out);
} }
g_object_unref(sharpened); g_object_unref(colourspaced);
vips_thread_shutdown(); vips_thread_shutdown();
} }
@@ -456,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;

View File

@@ -154,6 +154,14 @@ async.series({
} }
}); });
} }
}).add("sharp-file-buffer-promise", {
defer: true,
fn: function(deferred) {
sharp(inputJpg).resize(width, height).toBuffer().then(function(buffer) {
assert.notStrictEqual(null, buffer);
deferred.resolve();
});
}
}).add("sharp-file-buffer-sharpen", { }).add("sharp-file-buffer-sharpen", {
defer: true, defer: true,
fn: function(deferred) { fn: function(deferred) {
@@ -166,6 +174,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) {
@@ -330,18 +362,6 @@ async.series({
} }
}); });
} }
}).add("sharp-file-buffer-sequentialRead", {
defer: true,
fn: function(deferred) {
sharp(inputPng).sequentialRead().resize(width, height).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).on("cycle", function(event) { }).on("cycle", function(event) {
console.log(" png " + String(event.target)); console.log(" png " + String(event.target));
}).on("complete", function() { }).on("complete", function() {
@@ -408,18 +428,6 @@ async.series({
} }
}); });
} }
}).add("sharp-file-buffer-sequentialRead", {
defer: true,
fn: function(deferred) {
sharp(inputWebp).sequentialRead().resize(width, height).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).on("cycle", function(event) { }).on("cycle", function(event) {
console.log("webp " + String(event.target)); console.log("webp " + String(event.target));
}).on("complete", function() { }).on("complete", function() {
@@ -449,17 +457,6 @@ async.series({
} }
}); });
} }
}).add("sharp-file-file-sequentialRead", {
defer: true,
fn: function(deferred) {
sharp(inputTiff).sequentialRead().resize(width, height).toFile(outputTiff, function(err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).on("cycle", function(event) { }).on("cycle", function(event) {
console.log("tiff " + String(event.target)); console.log("tiff " + String(event.target));
}).on("complete", function() { }).on("complete", function() {

View File

@@ -219,7 +219,7 @@ async.series([
}, },
// Do not enlarge the output if the input width is already less than the output width // Do not enlarge the output if the input width is already less than the output width
function(done) { function(done) {
sharp(inputJpg).resize(2800).withoutEnlargement().write(outputJpg, function(err) { sharp(inputJpg).resize(2800).withoutEnlargement().toFile(outputJpg, function(err) {
if (err) throw err; if (err) throw err;
imagemagick.identify(outputJpg, function(err, features) { imagemagick.identify(outputJpg, function(err, features) {
if (err) throw err; if (err) throw err;
@@ -231,7 +231,7 @@ async.series([
}, },
// Do not enlarge the output if the input height is already less than the output height // Do not enlarge the output if the input height is already less than the output height
function(done) { function(done) {
sharp(inputJpg).resize(null, 2300).withoutEnlargement().write(outputJpg, function(err) { sharp(inputJpg).resize(null, 2300).withoutEnlargement().toFile(outputJpg, function(err) {
if (err) throw err; if (err) throw err;
imagemagick.identify(outputJpg, function(err, features) { imagemagick.identify(outputJpg, function(err, features) {
if (err) throw err; if (err) throw err;
@@ -262,5 +262,47 @@ async.series([
} catch (e) {} } catch (e) {}
assert(!fail); assert(!fail);
done(); done();
} },
// Check colour space conversion occurs from TIFF to WebP (this used to segfault)
function(done) {
sharp(inputTiff).webp().then(function() {
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();
});
});
},
]); ]);