mirror of
https://github.com/lovell/sharp.git
synced 2026-02-05 06:06:18 +01:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55ea432711 | ||
|
|
1f7e80e581 | ||
|
|
0e91ca90d6 | ||
|
|
8f41fed9c2 | ||
|
|
96dd40cee1 | ||
|
|
62767d072b | ||
|
|
33880ce19e | ||
|
|
988176846d | ||
|
|
657d436a0f | ||
|
|
e5549e3063 | ||
|
|
0b2fb967b8 | ||
|
|
f57478c1aa | ||
|
|
e5a5e2ca7e | ||
|
|
797d503a99 | ||
|
|
512a281986 | ||
|
|
37c5ca7166 |
@@ -1,7 +1,8 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "0.10"
|
- "0.10"
|
||||||
- "0.11"
|
- "0.12"
|
||||||
|
- iojs
|
||||||
before_install:
|
before_install:
|
||||||
- curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | sudo bash -
|
- curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | sudo bash -
|
||||||
after_success:
|
after_success:
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -187,7 +187,7 @@ sharp(inputBuffer)
|
|||||||
.toFile('output.tiff')
|
.toFile('output.tiff')
|
||||||
.then(function() {
|
.then(function() {
|
||||||
// output.tiff is a 200 pixels wide and 300 pixels high image
|
// output.tiff is a 200 pixels wide and 300 pixels high image
|
||||||
// containing a bicubic scaled version, embedded on a white canvas,
|
// containing a nohalo scaled version, embedded on a white canvas,
|
||||||
// of the image data in inputBuffer
|
// of the image data in inputBuffer
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
@@ -197,7 +197,7 @@ sharp('input.gif')
|
|||||||
.resize(200, 300)
|
.resize(200, 300)
|
||||||
.background({r: 0, g: 0, b: 0, a: 0})
|
.background({r: 0, g: 0, b: 0, a: 0})
|
||||||
.embed()
|
.embed()
|
||||||
.webp()
|
.toFormat(sharp.format.webp)
|
||||||
.toBuffer(function(err, outputBuffer) {
|
.toBuffer(function(err, outputBuffer) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
@@ -211,7 +211,7 @@ sharp('input.gif')
|
|||||||
sharp(inputBuffer)
|
sharp(inputBuffer)
|
||||||
.resize(200, 200)
|
.resize(200, 200)
|
||||||
.max()
|
.max()
|
||||||
.jpeg()
|
.toFormat('jpeg')
|
||||||
.toBuffer().then(function(outputBuffer) {
|
.toBuffer().then(function(outputBuffer) {
|
||||||
// outputBuffer contains JPEG image data no wider than 200 pixels and no higher
|
// outputBuffer contains JPEG image data no wider than 200 pixels and no higher
|
||||||
// than 200 pixels regardless of the inputBuffer image dimensions
|
// than 200 pixels regardless of the inputBuffer image dimensions
|
||||||
@@ -415,6 +415,13 @@ The number of channels depends on the input image and selected options.
|
|||||||
* 3 channels for colour images without alpha transparency, with bytes ordered \[red, green, blue, red, green, blue, etc.\]).
|
* 3 channels for colour images without alpha transparency, with bytes ordered \[red, green, blue, red, green, blue, etc.\]).
|
||||||
* 4 channels for colour images with alpha transparency, with bytes ordered \[red, green, blue, alpha, red, green, blue, alpha, etc.\].
|
* 4 channels for colour images with alpha transparency, with bytes ordered \[red, green, blue, alpha, red, green, blue, alpha, etc.\].
|
||||||
|
|
||||||
|
#### toFormat(format)
|
||||||
|
|
||||||
|
Convenience method for the above output format methods, where `format` is either:
|
||||||
|
|
||||||
|
* an attribute of the `sharp.format` Object e.g. `sharp.format.jpeg`, or
|
||||||
|
* a String containing `jpeg`, `png`, `webp` or `raw`.
|
||||||
|
|
||||||
#### quality(quality)
|
#### quality(quality)
|
||||||
|
|
||||||
The output quality to use for lossy JPEG, WebP and TIFF output formats. The default quality is `80`.
|
The output quality to use for lossy JPEG, WebP and TIFF output formats. The default quality is `80`.
|
||||||
@@ -431,6 +438,15 @@ Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
|
|||||||
|
|
||||||
The default behaviour is to strip all metadata and convert to the device-independent sRGB colour space.
|
The default behaviour is to strip all metadata and convert to the device-independent sRGB colour space.
|
||||||
|
|
||||||
|
#### withoutChromaSubsampling()
|
||||||
|
|
||||||
|
Disable the use of [chroma subsampling](http://en.wikipedia.org/wiki/Chroma_subsampling) with JPEG output (4:4:4).
|
||||||
|
|
||||||
|
This can improve colour representation at higher quality settings (90+),
|
||||||
|
but usually increases output file size and typically reduces performance by 25%.
|
||||||
|
|
||||||
|
The default behaviour is to use chroma subsampling (4:2:0).
|
||||||
|
|
||||||
#### compressionLevel(compressionLevel)
|
#### compressionLevel(compressionLevel)
|
||||||
|
|
||||||
An advanced setting for the _zlib_ compression level of the lossless PNG output format. The default level is `6`.
|
An advanced setting for the _zlib_ compression level of the lossless PNG output format. The default level is `6`.
|
||||||
|
|||||||
47
index.js
47
index.js
@@ -64,6 +64,7 @@ var Sharp = function(input) {
|
|||||||
quality: 80,
|
quality: 80,
|
||||||
compressionLevel: 6,
|
compressionLevel: 6,
|
||||||
withoutAdaptiveFiltering: false,
|
withoutAdaptiveFiltering: false,
|
||||||
|
withoutChromaSubsampling: false,
|
||||||
streamOut: false,
|
streamOut: false,
|
||||||
withMetadata: false
|
withMetadata: false
|
||||||
};
|
};
|
||||||
@@ -142,7 +143,11 @@ Sharp.prototype.extract = function(topOffset, leftOffset, width, height) {
|
|||||||
var suffix = this.options.width === -1 && this.options.height === -1 ? 'Pre' : 'Post';
|
var suffix = this.options.width === -1 && this.options.height === -1 ? 'Pre' : 'Post';
|
||||||
var values = arguments;
|
var values = arguments;
|
||||||
['topOffset', 'leftOffset', 'width', 'height'].forEach(function(name, index) {
|
['topOffset', 'leftOffset', 'width', 'height'].forEach(function(name, index) {
|
||||||
this.options[name + suffix] = values[index];
|
if (typeof values[index] === 'number' && !Number.isNaN(values[index]) && (values[index] % 1 === 0) && values[index] >= 0) {
|
||||||
|
this.options[name + suffix] = values[index];
|
||||||
|
} else {
|
||||||
|
throw new Error('Non-integer value for ' + name + ' of ' + values[index]);
|
||||||
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
// Ensure existing rotation occurs before pre-resize extraction
|
// Ensure existing rotation occurs before pre-resize extraction
|
||||||
if (suffix === 'Pre' && this.options.angle !== 0) {
|
if (suffix === 'Pre' && this.options.angle !== 0) {
|
||||||
@@ -364,6 +369,14 @@ Sharp.prototype.withoutAdaptiveFiltering = function(withoutAdaptiveFiltering) {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Disable the use of chroma subsampling for JPEG output
|
||||||
|
*/
|
||||||
|
Sharp.prototype.withoutChromaSubsampling = function(withoutChromaSubsampling) {
|
||||||
|
this.options.withoutChromaSubsampling = (typeof withoutChromaSubsampling === 'boolean') ? withoutChromaSubsampling : true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
Sharp.prototype.withMetadata = function(withMetadata) {
|
Sharp.prototype.withMetadata = function(withMetadata) {
|
||||||
this.options.withMetadata = (typeof withMetadata === 'boolean') ? withMetadata : true;
|
this.options.withMetadata = (typeof withMetadata === 'boolean') ? withMetadata : true;
|
||||||
return this;
|
return this;
|
||||||
@@ -431,25 +444,40 @@ Sharp.prototype.toFile = function(output, callback) {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Write output to a Buffer
|
||||||
|
*/
|
||||||
Sharp.prototype.toBuffer = function(callback) {
|
Sharp.prototype.toBuffer = function(callback) {
|
||||||
return this._sharp(callback);
|
return this._sharp(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Force JPEG output
|
||||||
|
*/
|
||||||
Sharp.prototype.jpeg = function() {
|
Sharp.prototype.jpeg = function() {
|
||||||
this.options.output = '__jpeg';
|
this.options.output = '__jpeg';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Force PNG output
|
||||||
|
*/
|
||||||
Sharp.prototype.png = function() {
|
Sharp.prototype.png = function() {
|
||||||
this.options.output = '__png';
|
this.options.output = '__png';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Force WebP output
|
||||||
|
*/
|
||||||
Sharp.prototype.webp = function() {
|
Sharp.prototype.webp = function() {
|
||||||
this.options.output = '__webp';
|
this.options.output = '__webp';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Force raw, uint8 output
|
||||||
|
*/
|
||||||
Sharp.prototype.raw = function() {
|
Sharp.prototype.raw = function() {
|
||||||
if (semver.gte(libvipsVersion, '7.42.0')) {
|
if (semver.gte(libvipsVersion, '7.42.0')) {
|
||||||
this.options.output = '__raw';
|
this.options.output = '__raw';
|
||||||
@@ -459,6 +487,23 @@ Sharp.prototype.raw = function() {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Force output to a given format
|
||||||
|
*/
|
||||||
|
module.exports.format = {'jpeg': 'jpeg', 'png': 'png', 'webp': 'webp', 'raw': 'raw'};
|
||||||
|
Sharp.prototype.toFormat = function(format) {
|
||||||
|
if (
|
||||||
|
typeof format === 'string' &&
|
||||||
|
typeof module.exports.format[format] === 'string' &&
|
||||||
|
typeof this[format] === 'function'
|
||||||
|
) {
|
||||||
|
this[format]();
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported format ' + format);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Used by a Writable Stream to notify that it is ready for data
|
Used by a Writable Stream to notify that it is ready for data
|
||||||
*/
|
*/
|
||||||
|
|||||||
8
package.json
Executable file → Normal file
8
package.json
Executable file → Normal file
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sharp",
|
"name": "sharp",
|
||||||
"version": "0.9.0",
|
"version": "0.9.2",
|
||||||
"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>",
|
||||||
@@ -34,10 +34,10 @@
|
|||||||
"vips"
|
"vips"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "^2.8.2",
|
"bluebird": "^2.9.9",
|
||||||
"color": "^0.7.3",
|
"color": "^0.7.3",
|
||||||
"nan": "^1.6.1",
|
"nan": "^1.6.2",
|
||||||
"semver": "^4.2.0"
|
"semver": "^4.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "^2.1.0",
|
"mocha": "^2.1.0",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
vips_version_minimum=7.40.0
|
vips_version_minimum=7.40.0
|
||||||
vips_version_latest_major=7.42
|
vips_version_latest_major=7.42
|
||||||
vips_version_latest_minor=1
|
vips_version_latest_minor=2
|
||||||
|
|
||||||
install_libvips_from_source() {
|
install_libvips_from_source() {
|
||||||
echo "Compiling libvips $vips_version_latest_major.$vips_version_latest_minor from source"
|
echo "Compiling libvips $vips_version_latest_major.$vips_version_latest_minor from source"
|
||||||
@@ -137,7 +137,7 @@ case $(uname -s) in
|
|||||||
"Fedora release 21 "*|"Fedora release 22 "*)
|
"Fedora release 21 "*|"Fedora release 22 "*)
|
||||||
# Fedora 21, 22
|
# Fedora 21, 22
|
||||||
echo "Installing libvips via yum"
|
echo "Installing libvips via yum"
|
||||||
yum install vips-devel
|
yum install -y vips-devel
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
# Unsupported RHEL-based OS
|
# Unsupported RHEL-based OS
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ struct ResizeBaton {
|
|||||||
int quality;
|
int quality;
|
||||||
int compressionLevel;
|
int compressionLevel;
|
||||||
bool withoutAdaptiveFiltering;
|
bool withoutAdaptiveFiltering;
|
||||||
|
bool withoutChromaSubsampling;
|
||||||
std::string err;
|
std::string err;
|
||||||
bool withMetadata;
|
bool withMetadata;
|
||||||
|
|
||||||
@@ -117,6 +118,7 @@ struct ResizeBaton {
|
|||||||
quality(80),
|
quality(80),
|
||||||
compressionLevel(6),
|
compressionLevel(6),
|
||||||
withoutAdaptiveFiltering(false),
|
withoutAdaptiveFiltering(false),
|
||||||
|
withoutChromaSubsampling(false),
|
||||||
withMetadata(false) {
|
withMetadata(false) {
|
||||||
background[0] = 0.0;
|
background[0] = 0.0;
|
||||||
background[1] = 0.0;
|
background[1] = 0.0;
|
||||||
@@ -675,7 +677,8 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
if (baton->output == "__jpeg" || (baton->output == "__input" && inputImageType == ImageType::JPEG)) {
|
if (baton->output == "__jpeg" || (baton->output == "__input" && inputImageType == ImageType::JPEG)) {
|
||||||
// Write JPEG to buffer
|
// Write JPEG to buffer
|
||||||
if (vips_jpegsave_buffer(image, &baton->bufferOut, &baton->bufferOutLength, "strip", !baton->withMetadata,
|
if (vips_jpegsave_buffer(image, &baton->bufferOut, &baton->bufferOutLength, "strip", !baton->withMetadata,
|
||||||
"Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
|
"Q", baton->quality, "optimize_coding", TRUE, "no_subsample", baton->withoutChromaSubsampling,
|
||||||
|
"interlace", baton->progressive, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
baton->outputFormat = "jpeg";
|
baton->outputFormat = "jpeg";
|
||||||
@@ -741,7 +744,8 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
if (outputJpeg || (matchInput && inputImageType == ImageType::JPEG)) {
|
if (outputJpeg || (matchInput && inputImageType == ImageType::JPEG)) {
|
||||||
// Write JPEG to file
|
// Write JPEG to file
|
||||||
if (vips_jpegsave(image, baton->output.c_str(), "strip", !baton->withMetadata,
|
if (vips_jpegsave(image, baton->output.c_str(), "strip", !baton->withMetadata,
|
||||||
"Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
|
"Q", baton->quality, "optimize_coding", TRUE, "no_subsample", baton->withoutChromaSubsampling,
|
||||||
|
"interlace", baton->progressive, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
baton->outputFormat = "jpeg";
|
baton->outputFormat = "jpeg";
|
||||||
@@ -992,6 +996,7 @@ NAN_METHOD(resize) {
|
|||||||
baton->quality = options->Get(NanNew<String>("quality"))->Int32Value();
|
baton->quality = options->Get(NanNew<String>("quality"))->Int32Value();
|
||||||
baton->compressionLevel = options->Get(NanNew<String>("compressionLevel"))->Int32Value();
|
baton->compressionLevel = options->Get(NanNew<String>("compressionLevel"))->Int32Value();
|
||||||
baton->withoutAdaptiveFiltering = options->Get(NanNew<String>("withoutAdaptiveFiltering"))->BooleanValue();
|
baton->withoutAdaptiveFiltering = options->Get(NanNew<String>("withoutAdaptiveFiltering"))->BooleanValue();
|
||||||
|
baton->withoutChromaSubsampling = options->Get(NanNew<String>("withoutChromaSubsampling"))->BooleanValue();
|
||||||
baton->withMetadata = options->Get(NanNew<String>("withMetadata"))->BooleanValue();
|
baton->withMetadata = options->Get(NanNew<String>("withMetadata"))->BooleanValue();
|
||||||
// Output filename or __format for Buffer
|
// Output filename or __format for Buffer
|
||||||
baton->output = *String::Utf8Value(options->Get(NanNew<String>("output"))->ToString());
|
baton->output = *String::Utf8Value(options->Get(NanNew<String>("output"))->ToString());
|
||||||
|
|||||||
@@ -13,12 +13,9 @@ extern "C" void init(v8::Handle<v8::Object> target) {
|
|||||||
vips_init("sharp");
|
vips_init("sharp");
|
||||||
|
|
||||||
// Set libvips operation cache limits
|
// Set libvips operation cache limits
|
||||||
vips_cache_set_max_mem(100 * 1048576); // 100 MB
|
vips_cache_set_max_mem(100 * 1024 * 1024); // 100 MB
|
||||||
vips_cache_set_max(500); // 500 operations
|
vips_cache_set_max(500); // 500 operations
|
||||||
|
|
||||||
// Notify the V8 garbage collector of max cache size
|
|
||||||
NanAdjustExternalMemory(vips_cache_get_max_mem());
|
|
||||||
|
|
||||||
// Methods available to JavaScript
|
// Methods available to JavaScript
|
||||||
NODE_SET_METHOD(target, "metadata", metadata);
|
NODE_SET_METHOD(target, "metadata", metadata);
|
||||||
NODE_SET_METHOD(target, "resize", resize);
|
NODE_SET_METHOD(target, "resize", resize);
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"imagemagick": "^0.1.3",
|
"imagemagick": "^0.1.3",
|
||||||
"imagemagick-native": "^1.6.0",
|
"imagemagick-native": "^1.7.0",
|
||||||
"gm": "^1.17.0",
|
"gm": "^1.17.0",
|
||||||
"async": "^0.9.0",
|
"async": "^0.9.0",
|
||||||
"semver": "^4.2.0",
|
"semver": "^4.3.0",
|
||||||
"benchmark": "^1.0.0"
|
"benchmark": "^1.0.0"
|
||||||
},
|
},
|
||||||
"license": "Apache 2.0",
|
"license": "Apache 2.0",
|
||||||
|
|||||||
@@ -347,6 +347,18 @@ async.series({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}).add('sharp-without-chroma-subsampling', {
|
||||||
|
defer: true,
|
||||||
|
fn: function(deferred) {
|
||||||
|
sharp(inputJpgBuffer).resize(width, height).withoutChromaSubsampling().toBuffer(function(err, buffer) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
assert.notStrictEqual(null, buffer);
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}).add('sharp-rotate', {
|
}).add('sharp-rotate', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ var fixtures = require('../fixtures');
|
|||||||
var min = 320;
|
var min = 320;
|
||||||
var max = 960;
|
var max = 960;
|
||||||
|
|
||||||
|
// Nearest equivalent to bilinear
|
||||||
|
var magickFilter = 'Triangle';
|
||||||
|
|
||||||
var randomDimension = function() {
|
var randomDimension = function() {
|
||||||
return Math.ceil(Math.random() * (max - min) + min);
|
return Math.ceil(Math.random() * (max - min) + min);
|
||||||
};
|
};
|
||||||
@@ -23,7 +26,9 @@ new Benchmark.Suite('random').add('imagemagick', {
|
|||||||
dstPath: fixtures.outputJpg,
|
dstPath: fixtures.outputJpg,
|
||||||
quality: 0.8,
|
quality: 0.8,
|
||||||
width: randomDimension(),
|
width: randomDimension(),
|
||||||
height: randomDimension()
|
height: randomDimension(),
|
||||||
|
format: 'jpg',
|
||||||
|
filter: magickFilter
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
@@ -35,14 +40,18 @@ new Benchmark.Suite('random').add('imagemagick', {
|
|||||||
}).add('gm', {
|
}).add('gm', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
gm(fixtures.inputJpg).resize(randomDimension(), randomDimension()).quality(80).toBuffer(function (err, buffer) {
|
gm(fixtures.inputJpg)
|
||||||
if (err) {
|
.resize(randomDimension(), randomDimension())
|
||||||
throw err;
|
.filter(magickFilter)
|
||||||
} else {
|
.quality(80)
|
||||||
assert.notStrictEqual(null, buffer);
|
.toBuffer(function (err, buffer) {
|
||||||
deferred.resolve();
|
if (err) {
|
||||||
}
|
throw err;
|
||||||
});
|
} else {
|
||||||
|
assert.notStrictEqual(null, buffer);
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}).add('sharp', {
|
}).add('sharp', {
|
||||||
defer: true,
|
defer: true,
|
||||||
|
|||||||
@@ -116,4 +116,62 @@ describe('Partial image extraction', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Invalid parameters', function() {
|
||||||
|
|
||||||
|
it('Undefined', function(done) {
|
||||||
|
var isValid = true;
|
||||||
|
try {
|
||||||
|
sharp(fixtures.inputJpg).extract();
|
||||||
|
} catch (err) {
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
assert.strictEqual(false, isValid);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('String top', function(done) {
|
||||||
|
var isValid = true;
|
||||||
|
try {
|
||||||
|
sharp(fixtures.inputJpg).extract('spoons', 10, 10, 10);
|
||||||
|
} catch (err) {
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
assert.strictEqual(false, isValid);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Non-integral left', function(done) {
|
||||||
|
var isValid = true;
|
||||||
|
try {
|
||||||
|
sharp(fixtures.inputJpg).extract(10, 10.2, 10, 10);
|
||||||
|
} catch (err) {
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
assert.strictEqual(false, isValid);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Negative width - negative', function(done) {
|
||||||
|
var isValid = true;
|
||||||
|
try {
|
||||||
|
sharp(fixtures.inputJpg).extract(10, 10, -10, 10);
|
||||||
|
} catch (err) {
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
assert.strictEqual(false, isValid);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Null height', function(done) {
|
||||||
|
var isValid = true;
|
||||||
|
try {
|
||||||
|
sharp(fixtures.inputJpg).extract(10, 10, 10, null);
|
||||||
|
} catch (err) {
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
assert.strictEqual(false, isValid);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -135,10 +135,11 @@ describe('Input/output', function() {
|
|||||||
readableButNotAnImage.pipe(writable);
|
readableButNotAnImage.pipe(writable);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Sequential read', function(done) {
|
it('Sequential read, force JPEG', function(done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.sequentialRead()
|
.sequentialRead()
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
|
.toFormat(sharp.format.jpeg)
|
||||||
.toBuffer(function(err, data, info) {
|
.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);
|
||||||
@@ -150,10 +151,11 @@ describe('Input/output', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Not sequential read', function(done) {
|
it('Not sequential read, force JPEG', function(done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.sequentialRead(false)
|
.sequentialRead(false)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
|
.toFormat('jpeg')
|
||||||
.toBuffer(function(err, data, info) {
|
.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);
|
||||||
@@ -292,6 +294,30 @@ describe('Input/output', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('WebP output', function(done) {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(320, 240)
|
||||||
|
.toFormat(sharp.format.webp)
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual('webp', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid output format', function(done) {
|
||||||
|
var isValid = false;
|
||||||
|
try {
|
||||||
|
sharp().toFormat('zoinks');
|
||||||
|
isValid = true;
|
||||||
|
} catch (e) {}
|
||||||
|
assert(!isValid);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
it('File input with corrupt header fails gracefully', function(done) {
|
it('File input with corrupt header fails gracefully', function(done) {
|
||||||
sharp(fixtures.inputJpgWithCorruptHeader)
|
sharp(fixtures.inputJpgWithCorruptHeader)
|
||||||
.toBuffer(function(err) {
|
.toBuffer(function(err) {
|
||||||
@@ -433,16 +459,48 @@ describe('Input/output', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Convert SVG to PNG', function(done) {
|
it('Without chroma subsampling generates larger file', function(done) {
|
||||||
|
// First generate with chroma subsampling (default)
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(320, 240)
|
||||||
|
.withoutChromaSubsampling(false)
|
||||||
|
.toBuffer(function(err, withChromaSubsamplingData, withChromaSubsamplingInfo) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, withChromaSubsamplingData.length > 0);
|
||||||
|
assert.strictEqual(withChromaSubsamplingData.length, withChromaSubsamplingInfo.size);
|
||||||
|
assert.strictEqual('jpeg', withChromaSubsamplingInfo.format);
|
||||||
|
assert.strictEqual(320, withChromaSubsamplingInfo.width);
|
||||||
|
assert.strictEqual(240, withChromaSubsamplingInfo.height);
|
||||||
|
// Then generate without
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(320, 240)
|
||||||
|
.withoutChromaSubsampling()
|
||||||
|
.toBuffer(function(err, withoutChromaSubsamplingData, withoutChromaSubsamplingInfo) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, withoutChromaSubsamplingData.length > 0);
|
||||||
|
assert.strictEqual(withoutChromaSubsamplingData.length, withoutChromaSubsamplingInfo.size);
|
||||||
|
assert.strictEqual('jpeg', withoutChromaSubsamplingInfo.format);
|
||||||
|
assert.strictEqual(320, withoutChromaSubsamplingInfo.width);
|
||||||
|
assert.strictEqual(240, withoutChromaSubsamplingInfo.height);
|
||||||
|
assert.strictEqual(true, withChromaSubsamplingData.length < withoutChromaSubsamplingData.length);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Convert SVG, if supported, to PNG', function(done) {
|
||||||
sharp(fixtures.inputSvg)
|
sharp(fixtures.inputSvg)
|
||||||
.resize(100, 100)
|
.resize(100, 100)
|
||||||
.png()
|
.toFormat('png')
|
||||||
.toFile(fixtures.path('output.svg.png'), function(err, info) {
|
.toFile(fixtures.path('output.svg.png'), function(err, info) {
|
||||||
if (err) throw err;
|
if (err) {
|
||||||
assert.strictEqual(true, info.size > 0);
|
assert.strictEqual('Input file is of an unsupported image format', err.message);
|
||||||
assert.strictEqual('png', info.format);
|
} else {
|
||||||
assert.strictEqual(100, info.width);
|
assert.strictEqual(true, info.size > 0);
|
||||||
assert.strictEqual(100, info.height);
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(100, info.width);
|
||||||
|
assert.strictEqual(100, info.height);
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -450,7 +508,7 @@ describe('Input/output', function() {
|
|||||||
it('Convert PSD to PNG', function(done) {
|
it('Convert PSD to PNG', function(done) {
|
||||||
sharp(fixtures.inputPsd)
|
sharp(fixtures.inputPsd)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.png()
|
.toFormat(sharp.format.png)
|
||||||
.toFile(fixtures.path('output.psd.png'), function(err, info) {
|
.toFile(fixtures.path('output.psd.png'), function(err, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(true, info.size > 0);
|
assert.strictEqual(true, info.size > 0);
|
||||||
@@ -498,7 +556,7 @@ describe('Input/output', function() {
|
|||||||
it('3 channel colour image without transparency', function(done) {
|
it('3 channel colour image without transparency', function(done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(32, 24)
|
.resize(32, 24)
|
||||||
.raw()
|
.toFormat('raw')
|
||||||
.toBuffer(function(err, data, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
assert.strictEqual(32 * 24 * 3, info.size);
|
assert.strictEqual(32 * 24 * 3, info.size);
|
||||||
assert.strictEqual(data.length, info.size);
|
assert.strictEqual(data.length, info.size);
|
||||||
@@ -511,7 +569,7 @@ describe('Input/output', function() {
|
|||||||
it('4 channel colour image with transparency', function(done) {
|
it('4 channel colour image with transparency', function(done) {
|
||||||
sharp(fixtures.inputPngWithTransparency)
|
sharp(fixtures.inputPngWithTransparency)
|
||||||
.resize(32, 24)
|
.resize(32, 24)
|
||||||
.raw()
|
.toFormat(sharp.format.raw)
|
||||||
.toBuffer(function(err, data, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
assert.strictEqual(32 * 24 * 4, info.size);
|
assert.strictEqual(32 * 24 * 4, info.size);
|
||||||
assert.strictEqual(data.length, info.size);
|
assert.strictEqual(data.length, info.size);
|
||||||
|
|||||||
Reference in New Issue
Block a user