Compare commits

..

22 Commits

Author SHA1 Message Date
Lovell Fuller
1cce56b024 Use tile cache for interlace output
Doubles performance of Adam7 interlaced PNG output
2014-07-09 23:47:04 +01:00
Lovell Fuller
2126f9afc1 Ensure xcode/clang uses cflags
Silence pedantic warnings triggered by V8 in 0.11
2014-07-09 21:14:40 +01:00
Lovell Fuller
41420eedcf Add details of Heroku buildpack, thanks @alex88 #57 2014-07-06 13:20:41 +01:00
Lovell Fuller
1b6ab19b6d Remove fftw dependency when compiling libvips from src #57 2014-07-03 21:12:18 +01:00
Lovell Fuller
fbe5c18762 Expose depth of task queue 2014-06-25 23:21:39 +01:00
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
9 changed files with 227 additions and 93 deletions

View File

@@ -5,12 +5,12 @@ node_js:
before_install:
- sudo add-apt-repository ppa:lyrasis/precise-backports -y
- sudo apt-get update -qq
- sudo apt-get install -qq automake gobject-introspection gtk-doc-tools libfftw3-dev libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff4-dev libexif-dev libxml2-dev swig graphicsmagick libmagick++-dev
- sudo apt-get install -qq automake gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff4-dev libexif-dev libxml2-dev swig graphicsmagick libmagick++-dev
- git clone https://github.com/jcupitt/libvips.git
- cd libvips
- git checkout 7.38
- ./bootstrap.sh
- ./configure --enable-debug=no --enable-cxx=no --without-orc --without-python
- ./configure --enable-debug=no --enable-cxx=yes --without-orc --without-python --without-fftw
- make
- sudo make install
- sudo ldconfig

View File

@@ -48,12 +48,12 @@ The _gettext_ dependency of _libvips_ [can lead](https://github.com/lovell/sharp
Compiling from source is recommended:
sudo apt-get install automake build-essential git gobject-introspection gtk-doc-tools libfftw3-dev libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev libxml2-dev swig
sudo apt-get install automake build-essential git gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev libxml2-dev swig
git clone https://github.com/jcupitt/libvips.git
cd libvips
git checkout 7.38
./bootstrap.sh
./configure --enable-debug=no --enable-cxx=no --without-python --without-orc
./configure --enable-debug=no --enable-cxx=yes --without-python --without-orc --without-fftw
make
sudo make install
sudo ldconfig
@@ -68,6 +68,10 @@ Requires `libtiff4-dev` instead of `libtiff5-dev` and has [a bug](https://bugs.l
Then follow Ubuntu 13.x instructions.
### Install libvips on Heroku
[Alessandro Tagliapietra](https://github.com/alex88) maintains an [Heroku buildpack for libvips](https://github.com/alex88/heroku-buildpack-vips) and its dependencies.
## Usage examples
```javascript
@@ -100,8 +104,8 @@ sharp('input.png').rotate(180).resize(300).sharpen().quality(90).webp().then(fun
```
```javascript
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
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 bicubic scaled
// version, embedded on a white canvas, of the image data in buffer
});
```
@@ -160,11 +164,11 @@ Embed the resized image on a black background of the exact size specified.
### rotate([angle])
Rotate the output image by either an explicit angle or auto-orient based on the EXIF `Orientation` tag. Mirroring is not supported.
Rotate the output image by either an explicit angle or auto-orient based on the EXIF `Orientation` tag.
`angle`, if present, is a Number with a value of `0`, `90`, `180` or `270`.
Use this method without `angle` to determine the angle from EXIF data.
Use this method without `angle` to determine the angle from EXIF data. Mirroring is currently unsupported.
### withoutEnlargement()
@@ -176,6 +180,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%.
### 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()
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 +236,7 @@ Write JPEG image data to a Buffer.
A Promises/A+ promise is returned when `callback` is not provided.
### png(callback)
### png([callback])
Write PNG image data to a Buffer.
@@ -245,9 +261,9 @@ This method always returns cache statistics, useful for determining how much wor
Warnings such as _Application transferred too many scanlines_ are a good indicator you've set this value too low.
```javascript
var stats = sharp.cache(); // { current: 98, high: 115, limit: 100 }
sharp.cache(200); // { current: 98, high: 115, limit: 200 }
sharp.cache(50); // { current: 49, high: 115, limit: 50 }
var stats = sharp.cache(); // { current: 98, high: 115, limit: 100, queue: 0 }
sharp.cache(200); // { current: 98, high: 115, limit: 200, queue: 0 }
sharp.cache(50); // { current: 49, high: 115, limit: 50, queue: 0 }
```
## Testing

View File

@@ -2,19 +2,20 @@
'targets': [{
'target_name': 'sharp',
'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': [
'<!@(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': [
'/usr/local/include/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',
'<!(PKG_CONFIG_PATH="<(PKG_CONFIG_PATH)" pkg-config --cflags vips glib-2.0)',
'<!(node -e "require(\'nan\')")'
],
'cflags': ['-fexceptions', '-pedantic', '-Wall', '-O3'],
'cflags_cc': ['-fexceptions', '-pedantic', '-Wall', '-O3']
'cflags': ['-fexceptions', '-Wall', '-O3'],
'cflags_cc': ['-fexceptions', '-Wall', '-O3'],
'xcode_settings': {
'OTHER_CFLAGS': ['-fexceptions', '-Wall', '-O3']
}
}]
}

View File

@@ -15,10 +15,11 @@ var Sharp = function(input) {
angle: 0,
withoutEnlargement: false,
sharpen: false,
interpolator: 'bilinear',
progressive: false,
sequentialRead: false,
quality: 80,
compressionLevel: 6,
quality: 80,
compressionLevel: 6,
output: '__jpeg'
};
if (typeof input === 'string') {
@@ -27,10 +28,10 @@ var Sharp = function(input) {
if (input.length > 0) {
this.options.bufferIn = input;
} else {
throw 'Buffer is empty';
throw new Error('Buffer is empty');
}
} else {
throw 'Unsupported input ' + typeof input;
throw new Error('Unsupported input ' + typeof input);
}
return this;
};
@@ -66,7 +67,7 @@ Sharp.prototype.rotate = function(angle) {
} else if (!Number.isNaN(angle) && [0, 90, 180, 270].indexOf(angle) !== -1) {
this.options.angle = angle;
} else {
throw 'Unsupport angle (0, 90, 180, 270) ' + angle;
throw new Error('Unsupported angle (0, 90, 180, 270) ' + angle);
}
return this;
};
@@ -86,6 +87,30 @@ Sharp.prototype.sharpen = function(sharpen) {
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) {
this.options.progressive = (typeof progressive === 'boolean') ? progressive : true;
return this;
@@ -100,7 +125,7 @@ Sharp.prototype.quality = function(quality) {
if (!Number.isNaN(quality) && quality >= 1 && quality <= 100) {
this.options.quality = quality;
} else {
throw 'Invalid quality (1 to 100) ' + quality;
throw new Error('Invalid quality (1 to 100) ' + quality);
}
return this;
};
@@ -109,7 +134,7 @@ Sharp.prototype.compressionLevel = function(compressionLevel) {
if (!Number.isNaN(compressionLevel) && compressionLevel >= -1 && compressionLevel <= 9) {
this.options.compressionLevel = compressionLevel;
} else {
throw 'Invalid compressionLevel (-1 to 9) ' + compressionLevel;
throw new Error('Invalid compressionLevel (-1 to 9) ' + compressionLevel);
}
return this;
};
@@ -121,7 +146,7 @@ Sharp.prototype.resize = function(width, height) {
if (!Number.isNaN(width)) {
this.options.width = width;
} else {
throw 'Invalid width ' + width;
throw new Error('Invalid width ' + width);
}
}
if (!height) {
@@ -130,7 +155,7 @@ Sharp.prototype.resize = function(width, height) {
if (!Number.isNaN(height)) {
this.options.height = height;
} else {
throw 'Invalid height ' + height;
throw new Error('Invalid height ' + height);
}
}
return this;
@@ -141,10 +166,20 @@ Sharp.prototype.resize = function(width, height) {
*/
Sharp.prototype.toFile = function(output, callback) {
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 {
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 {
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
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) {
return this._sharp('__input', callback);

View File

@@ -1,9 +1,10 @@
{
"name": "sharp",
"version": "0.5.0",
"version": "0.5.2",
"author": "Lovell Fuller <npm@lovell.info>",
"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",
"scripts": {
@@ -31,12 +32,12 @@
"buffer"
],
"dependencies": {
"nan": "^1.1.2",
"bluebird": "^1.2.4"
"nan": "^1.2.0",
"bluebird": "^2.2.1"
},
"devDependencies": {
"imagemagick": "^0.1.3",
"imagemagick-native": "^1.0.0",
"imagemagick-native": "^1.2.2",
"gm": "^1.16.0",
"async": "^0.9.0",
"benchmark": "^1.0.0"

View File

@@ -23,6 +23,7 @@ struct resize_baton {
bool max;
VipsExtend extend;
bool sharpen;
std::string interpolator;
bool progressive;
bool without_enlargement;
VipsAccess access_method;
@@ -53,6 +54,9 @@ unsigned char const MARKER_JPEG[] = {0xff, 0xd8};
unsigned char const MARKER_PNG[] = {0x89, 0x50};
unsigned char const MARKER_WEBP[] = {0x52, 0x49};
// How many tasks are in the queue?
volatile int queue_length = 0;
static bool ends_with(std::string const &str, std::string const &end) {
return str.length() >= end.length() && 0 == str.compare(str.length() - end.length(), end.length(), end);
}
@@ -294,12 +298,17 @@ class ResizeWorker : public NanAsyncWorker {
}
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();
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);
}
g_object_unref(interpolator);
} else {
vips_copy(shrunk, &affined, NULL);
}
@@ -359,46 +368,63 @@ class ResizeWorker : public NanAsyncWorker {
}
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);
// Generate image tile cache when interlace output is required
VipsImage *cached = vips_image_new();
if (baton->progressive) {
if (vips_tilecache(colourspaced, &cached, "threaded", TRUE, "persistent", TRUE, "max_tiles", -1, NULL)) {
return resize_error(baton, colourspaced);
}
} else {
vips_copy(colourspaced, &cached, NULL);
}
g_object_unref(colourspaced);
// Output
VipsImage *output = cached;
if (baton->file_out == "__jpeg" || (baton->file_out == "__input" && inputImageType == JPEG)) {
// 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)) {
return resize_error(baton, sharpened);
if (vips_jpegsave_buffer(output, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
return resize_error(baton, output);
}
} else if (baton->file_out == "__png" || (baton->file_out == "__input" && inputImageType == PNG)) {
// 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)) {
return resize_error(baton, sharpened);
if (vips_pngsave_buffer(output, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) {
return resize_error(baton, output);
}
} else if (baton->file_out == "__webp" || (baton->file_out == "__input" && inputImageType == WEBP)) {
// Write WEBP to buffer
if (vips_webpsave_buffer(sharpened, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, NULL)) {
return resize_error(baton, sharpened);
if (vips_webpsave_buffer(output, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, NULL)) {
return resize_error(baton, output);
}
} else if (is_jpeg(baton->file_out)) {
// 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)) {
return resize_error(baton, sharpened);
if (vips_jpegsave(output, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
return resize_error(baton, output);
}
} else if (is_png(baton->file_out)) {
// Write PNG to file
if (vips_pngsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) {
return resize_error(baton, sharpened);
if (vips_pngsave(output, baton->file_out.c_str(), "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) {
return resize_error(baton, output);
}
} else if (is_webp(baton->file_out)) {
// Write WEBP to file
if (vips_webpsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, NULL)) {
return resize_error(baton, sharpened);
if (vips_webpsave(output, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, NULL)) {
return resize_error(baton, output);
}
} else if (is_tiff(baton->file_out)) {
// 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)) {
return resize_error(baton, sharpened);
if (vips_tiffsave(output, baton->file_out.c_str(), "strip", TRUE, "compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, "Q", baton->quality, NULL)) {
return resize_error(baton, output);
}
} else {
(baton->err).append("Unsupported output " + baton->file_out);
}
g_object_unref(sharpened);
g_object_unref(output);
vips_thread_shutdown();
}
@@ -416,6 +442,8 @@ class ResizeWorker : public NanAsyncWorker {
}
delete baton;
callback->Call(2, argv);
// Decrement queue length
g_atomic_int_dec_and_test(&queue_length);
}
private:
@@ -456,6 +484,7 @@ NAN_METHOD(resize) {
}
// Other options
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->without_enlargement = options->Get(NanNew<String>("withoutEnlargement"))->BooleanValue();
baton->access_method = options->Get(NanNew<String>("sequentialRead"))->BooleanValue() ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
@@ -468,6 +497,10 @@ NAN_METHOD(resize) {
// Join queue for worker thread
NanCallback *callback = new NanCallback(args[2].As<v8::Function>());
NanAsyncQueueWorker(new ResizeWorker(callback, baton));
// Increment queue length
g_atomic_int_inc(&queue_length);
NanReturnUndefined();
}
@@ -484,6 +517,7 @@ NAN_METHOD(cache) {
cache->Set(NanNew<String>("current"), NanNew<Number>(vips_tracked_get_mem() / 1048576));
cache->Set(NanNew<String>("high"), NanNew<Number>(vips_tracked_get_mem_highwater() / 1048576));
cache->Set(NanNew<String>("limit"), NanNew<Number>(vips_cache_get_max_mem() / 1048576));
cache->Set(NanNew<String>("queue"), NanNew<Number>(queue_length));
NanReturnValue(cache);
}

View File

@@ -8,6 +8,10 @@ var inputJpg = path.join(__dirname, "fixtures/2569067123_aca715a2ee_o.jpg"); //
var width = 720;
var height = 480;
var timer = setInterval(function() {
console.dir(sharp.cache());
}, 100);
async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64, 128], function(parallelism, next) {
var start = new Date().getTime();
async.times(parallelism,
@@ -28,5 +32,6 @@ async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64, 128], function(parallelism, next) {
}
);
}, function() {
clearInterval(timer);
console.dir(sharp.cache());
});

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", {
defer: true,
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", {
defer: true,
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) {
console.log(" png " + String(event.target));
}).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) {
console.log("webp " + String(event.target));
}).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) {
console.log("tiff " + String(event.target));
}).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
function(done) {
sharp(inputJpg).resize(2800).withoutEnlargement().write(outputJpg, function(err) {
sharp(inputJpg).resize(2800).withoutEnlargement().toFile(outputJpg, function(err) {
if (err) throw err;
imagemagick.identify(outputJpg, function(err, features) {
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
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;
imagemagick.identify(outputJpg, function(err, features) {
if (err) throw err;
@@ -262,5 +262,47 @@ async.series([
} catch (e) {}
assert(!fail);
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();
});
});
},
]);