From ca561daedf120d1b41e2aff120510f0b951f1fea Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 20 Oct 2014 15:32:56 +0100 Subject: [PATCH] Test code refactor #63 Use mocha for feature-specific unit tests Add test coverage report via istanbul --- .gitignore | 18 +- .jshintignore | 3 + .jshintrc | 8 + .npmignore | 20 +- index.js | 15 +- package.json | 12 +- test/bench/package.json | 21 + {tests => test/bench}/parallel.js | 9 +- {tests => test/bench}/perf.js | 231 ++--- test/bench/random.js | 65 ++ .../fixtures/2569067123_aca715a2ee_o.jpg | Bin {tests => test}/fixtures/4.webp | Bin {tests => test}/fixtures/50020484-00001.png | Bin .../Channel_digital_image_CMYK_color.jpg | Bin {tests => test}/fixtures/Crash_test.gif | Bin {tests => test}/fixtures/G31D.TIF | Bin {tests => test}/fixtures/Landscape_8.jpg | Bin {tests => test}/fixtures/blackbug.png | Bin .../fixtures/gamma_dalai_lama_gray.jpg | Bin test/fixtures/index.js | 30 + {tests => test/leak}/leak.sh | 5 +- {tests => test/leak}/sharp.supp | 0 test/unit/alpha.js | 49 + test/unit/colourspace.js | 62 ++ test/unit/crop.js | 82 ++ test/unit/embed.js | 49 + test/unit/extract.js | 93 ++ test/unit/gamma.js | 26 + test/unit/interpolation.js | 94 ++ test/unit/io.js | 253 +++++ test/unit/jshint.js | 1 + test/unit/metadata.js | 171 ++++ test/unit/resize.js | 142 +++ test/unit/rotate.js | 64 ++ test/unit/util.js | 38 + tests/random.js | 69 -- tests/unit.js | 934 ------------------ 37 files changed, 1341 insertions(+), 1223 deletions(-) create mode 100644 .jshintignore create mode 100644 .jshintrc create mode 100755 test/bench/package.json rename {tests => test/bench}/parallel.js (76%) rename {tests => test/bench}/perf.js (59%) create mode 100755 test/bench/random.js rename {tests => test}/fixtures/2569067123_aca715a2ee_o.jpg (100%) rename {tests => test}/fixtures/4.webp (100%) rename {tests => test}/fixtures/50020484-00001.png (100%) rename {tests => test}/fixtures/Channel_digital_image_CMYK_color.jpg (100%) rename {tests => test}/fixtures/Crash_test.gif (100%) rename {tests => test}/fixtures/G31D.TIF (100%) rename {tests => test}/fixtures/Landscape_8.jpg (100%) rename {tests => test}/fixtures/blackbug.png (100%) rename {tests => test}/fixtures/gamma_dalai_lama_gray.jpg (100%) create mode 100755 test/fixtures/index.js rename {tests => test/leak}/leak.sh (55%) rename {tests => test/leak}/sharp.supp (100%) mode change 100644 => 100755 create mode 100755 test/unit/alpha.js create mode 100755 test/unit/colourspace.js create mode 100755 test/unit/crop.js create mode 100755 test/unit/embed.js create mode 100755 test/unit/extract.js create mode 100755 test/unit/gamma.js create mode 100755 test/unit/interpolation.js create mode 100755 test/unit/io.js create mode 100755 test/unit/jshint.js create mode 100755 test/unit/metadata.js create mode 100755 test/unit/resize.js create mode 100755 test/unit/rotate.js create mode 100755 test/unit/util.js delete mode 100755 tests/random.js delete mode 100755 tests/unit.js diff --git a/.gitignore b/.gitignore index 5db96809..f0e8ed9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,9 @@ -lib-cov -*.seed -*.log -*.csv -*.dat -*.out -*.pid -*.gz - -pids -logs -results build node_modules -tests/fixtures/output.* -tests/libvips.supp +coverage +test/bench/node_modules +test/fixtures/output.* +test/leak/libvips.supp # Mac OS X .DS_Store diff --git a/.jshintignore b/.jshintignore new file mode 100644 index 00000000..426fab9f --- /dev/null +++ b/.jshintignore @@ -0,0 +1,3 @@ +node_modules +test/bench/node_modules +coverage diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000..9965e07b --- /dev/null +++ b/.jshintrc @@ -0,0 +1,8 @@ +{ + "strict": true, + "node": true, + "globals": { + "describe": true, + "it": true + } +} diff --git a/.npmignore b/.npmignore index 499622ef..9241b45c 100644 --- a/.npmignore +++ b/.npmignore @@ -1,18 +1,8 @@ -lib-cov -*.seed -*.log -*.csv -*.dat -*.out -*.pid -*.gz - -pids -logs -results build node_modules - +coverage +.jshintignore +.jshintrc .gitignore -tests -.travis.yml \ No newline at end of file +test +.travis.yml diff --git a/index.js b/index.js index 7418451e..949d146f 100755 --- a/index.js +++ b/index.js @@ -1,11 +1,10 @@ -/*jslint node: true */ 'use strict'; var util = require('util'); var stream = require('stream'); var color = require('color'); -var Promise = require('bluebird'); +var BluebirdPromise = require('bluebird'); var sharp = require('./build/Release/sharp'); @@ -292,7 +291,7 @@ Sharp.prototype.toFile = function(output, callback) { if (typeof callback === 'function') { callback(errOutputInvalid); } else { - return Promise.reject(errOutputInvalid); + return BluebirdPromise.reject(errOutputInvalid); } } else { if (this.options.fileIn === output) { @@ -300,7 +299,7 @@ Sharp.prototype.toFile = function(output, callback) { if (typeof callback === 'function') { callback(errOutputIsInput); } else { - return Promise.reject(errOutputIsInput); + return BluebirdPromise.reject(errOutputIsInput); } } else { this.options.output = output; @@ -387,7 +386,7 @@ Sharp.prototype._sharp = function(callback) { // output=promise if (this.options.streamIn) { // output=promise, input=stream - return new Promise(function(resolve, reject) { + return new BluebirdPromise(function(resolve, reject) { that.on('finish', function() { sharp.resize(that.options, function(err, data) { if (err) { @@ -400,7 +399,7 @@ Sharp.prototype._sharp = function(callback) { }); } else { // output=promise, input=file/buffer - return new Promise(function(resolve, reject) { + return new BluebirdPromise(function(resolve, reject) { sharp.resize(that.options, function(err, data) { if (err) { reject(err); @@ -430,7 +429,7 @@ Sharp.prototype.metadata = function(callback) { return this; } else { if (this.options.streamIn) { - return new Promise(function(resolve, reject) { + return new BluebirdPromise(function(resolve, reject) { that.on('finish', function() { sharp.metadata(that.options, function(err, data) { if (err) { @@ -442,7 +441,7 @@ Sharp.prototype.metadata = function(callback) { }); }); } else { - return new Promise(function(resolve, reject) { + return new BluebirdPromise(function(resolve, reject) { sharp.metadata(that.options, function(err, data) { if (err) { reject(err); diff --git a/package.json b/package.json index c52069c9..1ecc34b1 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sharp", - "version": "0.7.0", + "version": "0.7.1", "author": "Lovell Fuller ", "contributors": [ "Pierre Inglebert ", @@ -14,7 +14,7 @@ ], "description": "High performance Node.js module to resize JPEG, PNG and WebP images using the libvips library", "scripts": { - "test": "node tests/unit && node tests/perf" + "test": "node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- --slow=5000 --timeout=10000 ./test/unit/*.js" }, "main": "index.js", "repository": { @@ -45,11 +45,9 @@ "nan": "^1.3.0" }, "devDependencies": { - "imagemagick": "^0.1.3", - "imagemagick-native": "^1.4.0", - "gm": "^1.16.0", - "async": "^0.9.0", - "benchmark": "^1.0.0" + "mocha": "^1.21.5", + "mocha-jshint": "^0.0.9", + "istanbul": "^0.3.2" }, "license": "Apache 2.0", "engines": { diff --git a/test/bench/package.json b/test/bench/package.json new file mode 100755 index 00000000..56d7b973 --- /dev/null +++ b/test/bench/package.json @@ -0,0 +1,21 @@ +{ + "name": "sharp-benchmark", + "version": "0.0.1", + "private": true, + "author": "Lovell Fuller ", + "description": "Benchmark and performance tests for sharp", + "scripts": { + "test": "node perf && node random && node parallel" + }, + "devDependencies": { + "imagemagick": "^0.1.3", + "imagemagick-native": "^1.4.0", + "gm": "^1.16.0", + "async": "^0.9.0", + "benchmark": "^1.0.0" + }, + "license": "Apache 2.0", + "engines": { + "node": ">=0.10" + } +} diff --git a/tests/parallel.js b/test/bench/parallel.js similarity index 76% rename from tests/parallel.js rename to test/bench/parallel.js index 2692dac6..0c6725d4 100755 --- a/tests/parallel.js +++ b/test/bench/parallel.js @@ -1,12 +1,11 @@ -/*jslint node: true */ 'use strict'; -var sharp = require('../index'); -var path = require('path'); var assert = require('assert'); var async = require('async'); -var inputJpg = path.join(__dirname, 'fixtures/2569067123_aca715a2ee_o.jpg'); // http://www.flickr.com/photos/grizdave/2569067123/ +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + var width = 720; var height = 480; @@ -21,7 +20,7 @@ async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64, 128], function(parallelism, next) { async.times(parallelism, function(id, callback) { /*jslint unused: false */ - sharp(inputJpg).resize(width, height).toBuffer(function(err, buffer) { + sharp(fixtures.inputJpg).resize(width, height).toBuffer(function(err, buffer) { buffer = null; callback(err, new Date().getTime() - start); }); diff --git a/tests/perf.js b/test/bench/perf.js similarity index 59% rename from tests/perf.js rename to test/bench/perf.js index 9dec05a1..eb885e6e 100755 --- a/tests/perf.js +++ b/test/bench/perf.js @@ -1,31 +1,17 @@ -/*jslint node: true */ 'use strict'; -var sharp = require('../index'); var fs = require('fs'); -var path = require('path'); -var imagemagick = require('imagemagick'); -var imagemagickNative = require('imagemagick-native'); -var gm = require('gm'); + var async = require('async'); var assert = require('assert'); var Benchmark = require('benchmark'); -var fixturesPath = path.join(__dirname, 'fixtures'); +var imagemagick = require('imagemagick'); +var imagemagickNative = require('imagemagick-native'); +var gm = require('gm'); +var sharp = require('../../index'); -var inputJpg = path.join(fixturesPath, '2569067123_aca715a2ee_o.jpg'); // http://www.flickr.com/photos/grizdave/2569067123/ -var outputJpg = path.join(fixturesPath, 'output.jpg'); - -var inputPng = path.join(fixturesPath, '50020484-00001.png'); // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png -var outputPng = path.join(fixturesPath, 'output.png'); - -var inputWebp = path.join(fixturesPath, '4.webp'); // http://www.gstatic.com/webp/gallery/4.webp -var outputWebp = path.join(fixturesPath, 'output.webp'); - -var inputTiff = path.join(fixturesPath, 'G31D.TIF'); // http://www.fileformat.info/format/tiff/sample/e6c9a6e5253348f4aef6d17b534360ab/index.htm -var outputTiff = path.join(fixturesPath, 'output.tiff'); - -var inputGif = path.join(fixturesPath, 'Crash_test.gif'); // http://upload.wikimedia.org/wikipedia/commons/e/e3/Crash_test.gif +var fixtures = require('../fixtures'); var width = 720; var height = 480; @@ -35,13 +21,13 @@ sharp.cache(0); async.series({ jpeg: function(callback) { - var inputJpgBuffer = fs.readFileSync(inputJpg); + var inputJpgBuffer = fs.readFileSync(fixtures.inputJpg); (new Benchmark.Suite('jpeg')).add('imagemagick-file-file', { defer: true, fn: function(deferred) { imagemagick.resize({ - srcPath: inputJpg, - dstPath: outputJpg, + srcPath: fixtures.inputJpg, + dstPath: fixtures.outputJpg, quality: 0.8, width: width, height: height @@ -61,14 +47,14 @@ async.series({ quality: 80, width: width, height: height, - format: 'JPEG' + format: 'JPEG' }); - deferred.resolve(); + deferred.resolve(); } }).add('gm-buffer-file', { defer: true, fn: function(deferred) { - gm(inputJpgBuffer).resize(width, height).quality(80).write(outputJpg, function (err) { + gm(inputJpgBuffer).resize(width, height).quality(80).write(fixtures.outputJpg, function (err) { if (err) { throw err; } else { @@ -91,7 +77,7 @@ async.series({ }).add('gm-file-file', { defer: true, fn: function(deferred) { - gm(inputJpg).resize(width, height).quality(80).write(outputJpg, function (err) { + gm(fixtures.inputJpg).resize(width, height).quality(80).write(fixtures.outputJpg, function (err) { if (err) { throw err; } else { @@ -102,7 +88,7 @@ async.series({ }).add('gm-file-buffer', { defer: true, fn: function(deferred) { - gm(inputJpg).resize(width, height).quality(80).toBuffer(function (err, buffer) { + gm(fixtures.inputJpg).resize(width, height).quality(80).toBuffer(function (err, buffer) { if (err) { throw err; } else { @@ -114,7 +100,7 @@ async.series({ }).add('sharp-buffer-file', { defer: true, fn: function(deferred) { - sharp(inputJpgBuffer).resize(width, height).toFile(outputJpg, function(err) { + sharp(inputJpgBuffer).resize(width, height).toFile(fixtures.outputJpg, function(err) { if (err) { throw err; } else { @@ -137,7 +123,7 @@ async.series({ }).add('sharp-file-file', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).toFile(outputJpg, function(err) { + sharp(fixtures.inputJpg).resize(width, height).toFile(fixtures.outputJpg, function(err) { if (err) { throw err; } else { @@ -148,8 +134,8 @@ async.series({ }).add('sharp-stream-stream', { defer: true, fn: function(deferred) { - var readable = fs.createReadStream(inputJpg); - var writable = fs.createWriteStream(outputJpg); + var readable = fs.createReadStream(fixtures.inputJpg); + var writable = fs.createWriteStream(fixtures.outputJpg); writable.on('finish', function() { deferred.resolve(); }); @@ -159,7 +145,7 @@ async.series({ }).add('sharp-file-buffer', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).toBuffer(function(err, buffer) { + sharp(fixtures.inputJpg).resize(width, height).toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -168,18 +154,18 @@ async.series({ } }); } - }).add('sharp-file-buffer-promise', { + }).add('sharp-promise', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).toBuffer().then(function(buffer) { + sharp(inputJpgBuffer).resize(width, height).toBuffer().then(function(buffer) { assert.notStrictEqual(null, buffer); deferred.resolve(); }); } - }).add('sharp-file-buffer-sharpen', { + }).add('sharp-sharpen', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).sharpen().toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).sharpen().toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -188,10 +174,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-nearest-neighbour', { + }).add('sharp-nearest-neighbour', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).interpolateWith(sharp.interpolator.nearest).toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).interpolateWith(sharp.interpolator.nearest).toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -200,10 +186,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-bicubic', { + }).add('sharp-bicubic', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).interpolateWith(sharp.interpolator.bicubic).toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).interpolateWith(sharp.interpolator.bicubic).toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -212,10 +198,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-nohalo', { + }).add('sharp-nohalo', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).interpolateWith(sharp.interpolator.nohalo).toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).interpolateWith(sharp.interpolator.nohalo).toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -224,10 +210,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-locallyBoundedBicubic', { + }).add('sharp-locallyBoundedBicubic', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).interpolateWith(sharp.interpolator.locallyBoundedBicubic).toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).interpolateWith(sharp.interpolator.locallyBoundedBicubic).toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -236,10 +222,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-vertexSplitQuadraticBasisSpline', { + }).add('sharp-vertexSplitQuadraticBasisSpline', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).interpolateWith(sharp.interpolator.vertexSplitQuadraticBasisSpline).toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).interpolateWith(sharp.interpolator.vertexSplitQuadraticBasisSpline).toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -248,10 +234,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-gamma', { + }).add('sharp-gamma', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).gamma().toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).gamma().toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -260,10 +246,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-greyscale', { + }).add('sharp-greyscale', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).greyscale().toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).greyscale().toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -272,10 +258,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-greyscale-gamma', { + }).add('sharp-greyscale-gamma', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).gamma().greyscale().toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).gamma().greyscale().toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -284,10 +270,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-progressive', { + }).add('sharp-progressive', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).progressive().toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).progressive().toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -296,10 +282,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-rotate', { + }).add('sharp-rotate', { defer: true, fn: function(deferred) { - sharp(inputJpg).rotate(90).resize(width, height).toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).rotate(90).resize(width, height).toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -308,10 +294,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-sequentialRead', { + }).add('sharp-sequentialRead', { defer: true, fn: function(deferred) { - sharp(inputJpg).resize(width, height).sequentialRead().toBuffer(function(err, buffer) { + sharp(inputJpgBuffer).resize(width, height).sequentialRead().toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -327,13 +313,13 @@ async.series({ }).run(); }, png: function(callback) { - var inputPngBuffer = fs.readFileSync(inputPng); + var inputPngBuffer = fs.readFileSync(fixtures.inputPng); (new Benchmark.Suite('png')).add('imagemagick-file-file', { defer: true, fn: function(deferred) { imagemagick.resize({ - srcPath: inputPng, - dstPath: outputPng, + srcPath: fixtures.inputPng, + dstPath: fixtures.outputPng, width: width, height: height }, function(err) { @@ -351,14 +337,14 @@ async.series({ srcData: inputPngBuffer, width: width, height: height, - format: 'PNG' + format: 'PNG' }); - deferred.resolve(); + deferred.resolve(); } }).add('gm-file-file', { defer: true, fn: function(deferred) { - gm(inputPng).resize(width, height).write(outputPng, function (err) { + gm(fixtures.inputPng).resize(width, height).write(fixtures.outputPng, function (err) { if (err) { throw err; } else { @@ -369,7 +355,7 @@ async.series({ }).add('gm-file-buffer', { defer: true, fn: function(deferred) { - gm(inputPng).resize(width, height).quality(80).toBuffer(function (err, buffer) { + gm(fixtures.inputPng).resize(width, height).quality(80).toBuffer(function (err, buffer) { if (err) { throw err; } else { @@ -381,7 +367,7 @@ async.series({ }).add('sharp-buffer-file', { defer: true, fn: function(deferred) { - sharp(inputPngBuffer).resize(width, height).toFile(outputPng, function(err) { + sharp(inputPngBuffer).resize(width, height).toFile(fixtures.outputPng, function(err) { if (err) { throw err; } else { @@ -404,7 +390,7 @@ async.series({ }).add('sharp-file-file', { defer: true, fn: function(deferred) { - sharp(inputPng).resize(width, height).toFile(outputPng, function(err) { + sharp(fixtures.inputPng).resize(width, height).toFile(fixtures.outputPng, function(err) { if (err) { throw err; } else { @@ -415,7 +401,7 @@ async.series({ }).add('sharp-file-buffer', { defer: true, fn: function(deferred) { - sharp(inputPng).resize(width, height).toBuffer(function(err, buffer) { + sharp(fixtures.inputPng).resize(width, height).toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -424,22 +410,10 @@ async.series({ } }); } - }).add('sharp-file-buffer-sharpen', { + }).add('sharp-progressive', { defer: true, fn: function(deferred) { - sharp(inputPng).resize(width, height).sharpen().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) { - sharp(inputPng).resize(width, height).progressive().toBuffer(function(err, buffer) { + sharp(inputPngBuffer).resize(width, height).progressive().toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -455,11 +429,11 @@ async.series({ }).run(); }, webp: function(callback) { - var inputWebpBuffer = fs.readFileSync(inputWebp); + var inputWebPBuffer = fs.readFileSync(fixtures.inputWebP); (new Benchmark.Suite('webp')).add('sharp-buffer-file', { defer: true, fn: function(deferred) { - sharp(inputWebpBuffer).resize(width, height).toFile(outputWebp, function(err) { + sharp(inputWebPBuffer).resize(width, height).toFile(fixtures.outputWebP, function(err) { if (err) { throw err; } else { @@ -470,7 +444,7 @@ async.series({ }).add('sharp-buffer-buffer', { defer: true, fn: function(deferred) { - sharp(inputWebpBuffer).resize(width, height).toBuffer(function(err, buffer) { + sharp(inputWebPBuffer).resize(width, height).toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -482,7 +456,7 @@ async.series({ }).add('sharp-file-file', { defer: true, fn: function(deferred) { - sharp(inputWebp).resize(width, height).toFile(outputWebp, function(err) { + sharp(fixtures.inputWebP).resize(width, height).toFile(fixtures.outputWebP, function(err) { if (err) { throw err; } else { @@ -493,19 +467,7 @@ async.series({ }).add('sharp-file-buffer', { defer: true, fn: function(deferred) { - sharp(inputWebp).resize(width, height).toBuffer(function(err, buffer) { - if (err) { - throw err; - } else { - assert.notStrictEqual(null, buffer); - deferred.resolve(); - } - }); - } - }).add('sharp-file-buffer-sharpen', { - defer: true, - fn: function(deferred) { - sharp(inputWebp).resize(width, height).sharpen().toBuffer(function(err, buffer) { + sharp(fixtures.inputWebp).resize(width, height).toBuffer(function(err, buffer) { if (err) { throw err; } else { @@ -519,75 +481,6 @@ async.series({ }).on('complete', function() { callback(null, this.filter('fastest').pluck('name')); }).run(); - }, - tiff: function(callback) { - (new Benchmark.Suite('tiff')).add('sharp-file-file', { - defer: true, - fn: function(deferred) { - sharp(inputTiff).resize(width, height).toFile(outputTiff, function(err) { - if (err) { - throw err; - } else { - deferred.resolve(); - } - }); - } - }).add('sharp-file-file-sharpen', { - defer: true, - fn: function(deferred) { - sharp(inputTiff).resize(width, height).sharpen().toFile(outputTiff, function(err) { - if (err) { - throw err; - } else { - deferred.resolve(); - } - }); - } - }).on('cycle', function(event) { - console.log('tiff ' + String(event.target)); - }).on('complete', function() { - callback(null, this.filter('fastest').pluck('name')); - }).run(); - }, - gif: function(callback) { - (new Benchmark.Suite('gif')).add('sharp-file-file', { - defer: true, - fn: function(deferred) { - sharp(inputGif).resize(width, height).toFile(outputTiff, function(err) { - if (err) { - throw err; - } else { - deferred.resolve(); - } - }); - } - }).add('sharp-file-file-sharpen', { - defer: true, - fn: function(deferred) { - sharp(inputGif).resize(width, height).sharpen().toFile(outputTiff, function(err) { - if (err) { - throw err; - } else { - deferred.resolve(); - } - }); - } - }).add('sharp-file-file-sequentialRead', { - defer: true, - fn: function(deferred) { - sharp(inputGif).sequentialRead().resize(width, height).toFile(outputTiff, function(err) { - if (err) { - throw err; - } else { - deferred.resolve(); - } - }); - } - }).on('cycle', function(event) { - console.log('gif ' + String(event.target)); - }).on('complete', function() { - callback(null, this.filter('fastest').pluck('name')); - }).run(); } }, function(err, results) { assert(!err, err); diff --git a/test/bench/random.js b/test/bench/random.js new file mode 100755 index 00000000..6f8c84ca --- /dev/null +++ b/test/bench/random.js @@ -0,0 +1,65 @@ +'use strict'; + +var imagemagick = require('imagemagick'); +var gm = require('gm'); +var assert = require('assert'); +var Benchmark = require('benchmark'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +var min = 320; +var max = 960; + +var randomDimension = function() { + return Math.random() * (max - min) + min; +}; + +new Benchmark.Suite('random').add('imagemagick', { + defer: true, + fn: function(deferred) { + imagemagick.resize({ + srcPath: fixtures.inputJpg, + dstPath: fixtures.outputJpg, + quality: 0.8, + width: randomDimension(), + height: randomDimension() + }, function(err) { + if (err) { + throw err; + } else { + deferred.resolve(); + } + }); + } +}).add('gm', { + defer: true, + fn: function(deferred) { + gm(fixtures.inputJpg).resize(randomDimension(), randomDimension()).quality(80).toBuffer(function (err, buffer) { + if (err) { + throw err; + } else { + assert.notStrictEqual(null, buffer); + deferred.resolve(); + } + }); + } +}).add('sharp', { + defer: true, + fn: function(deferred) { + sharp(fixtures.inputJpg).resize(randomDimension(), randomDimension()).toBuffer(function(err, buffer) { + if (err) { + throw err; + } else { + assert.notStrictEqual(null, buffer); + deferred.resolve(); + } + }); + } +}).on('cycle', function(event) { + console.log(String(event.target)); +}).on('complete', function() { + var winner = this.filter('fastest').pluck('name'); + assert.strictEqual('sharp', String(winner), 'sharp was slower than ' + winner); + console.dir(sharp.cache()); +}).run(); diff --git a/tests/fixtures/2569067123_aca715a2ee_o.jpg b/test/fixtures/2569067123_aca715a2ee_o.jpg similarity index 100% rename from tests/fixtures/2569067123_aca715a2ee_o.jpg rename to test/fixtures/2569067123_aca715a2ee_o.jpg diff --git a/tests/fixtures/4.webp b/test/fixtures/4.webp similarity index 100% rename from tests/fixtures/4.webp rename to test/fixtures/4.webp diff --git a/tests/fixtures/50020484-00001.png b/test/fixtures/50020484-00001.png similarity index 100% rename from tests/fixtures/50020484-00001.png rename to test/fixtures/50020484-00001.png diff --git a/tests/fixtures/Channel_digital_image_CMYK_color.jpg b/test/fixtures/Channel_digital_image_CMYK_color.jpg similarity index 100% rename from tests/fixtures/Channel_digital_image_CMYK_color.jpg rename to test/fixtures/Channel_digital_image_CMYK_color.jpg diff --git a/tests/fixtures/Crash_test.gif b/test/fixtures/Crash_test.gif similarity index 100% rename from tests/fixtures/Crash_test.gif rename to test/fixtures/Crash_test.gif diff --git a/tests/fixtures/G31D.TIF b/test/fixtures/G31D.TIF similarity index 100% rename from tests/fixtures/G31D.TIF rename to test/fixtures/G31D.TIF diff --git a/tests/fixtures/Landscape_8.jpg b/test/fixtures/Landscape_8.jpg similarity index 100% rename from tests/fixtures/Landscape_8.jpg rename to test/fixtures/Landscape_8.jpg diff --git a/tests/fixtures/blackbug.png b/test/fixtures/blackbug.png similarity index 100% rename from tests/fixtures/blackbug.png rename to test/fixtures/blackbug.png diff --git a/tests/fixtures/gamma_dalai_lama_gray.jpg b/test/fixtures/gamma_dalai_lama_gray.jpg similarity index 100% rename from tests/fixtures/gamma_dalai_lama_gray.jpg rename to test/fixtures/gamma_dalai_lama_gray.jpg diff --git a/test/fixtures/index.js b/test/fixtures/index.js new file mode 100755 index 00000000..ab271bc0 --- /dev/null +++ b/test/fixtures/index.js @@ -0,0 +1,30 @@ +'use strict'; + +var path = require('path'); + +var getPath = function(filename) { + return path.join(__dirname, filename); +}; + +module.exports = { + + inputJpg: getPath('2569067123_aca715a2ee_o.jpg'), // http://www.flickr.com/photos/grizdave/2569067123/ + inputJpgWithExif: getPath('Landscape_8.jpg'), // https://github.com/recurser/exif-orientation-examples/blob/master/Landscape_8.jpg + inputJpgWithGammaHoliness: getPath('gamma_dalai_lama_gray.jpg'), // http://www.4p8.com/eric.brasseur/gamma.html + inputJpgWithCmykProfile: getPath('Channel_digital_image_CMYK_color.jpg'), // http://en.wikipedia.org/wiki/File:Channel_digital_image_CMYK_color.jpg + + inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png + inputPngWithTransparency: getPath('blackbug.png'), // public domain + + inputWebP: getPath('4.webp'), // http://www.gstatic.com/webp/gallery/4.webp + inputTiff: getPath('G31D.TIF'), // http://www.fileformat.info/format/tiff/sample/e6c9a6e5253348f4aef6d17b534360ab/index.htm + inputGif: getPath('Crash_test.gif'), // http://upload.wikimedia.org/wikipedia/commons/e/e3/Crash_test.gif + + outputJpg: getPath('output.jpg'), + outputPng: getPath('output.png'), + outputWebP: getPath('output.webp'), + outputZoinks: getPath('output.zoinks'), // an 'unknown' file extension + + path: getPath // allows tests to write files to fixtures directory (for testing with human eyes) + +}; diff --git a/tests/leak.sh b/test/leak/leak.sh similarity index 55% rename from tests/leak.sh rename to test/leak/leak.sh index 71972a9a..42b08995 100755 --- a/tests/leak.sh +++ b/test/leak/leak.sh @@ -3,5 +3,6 @@ if ! type valgrind >/dev/null; then exit 1 fi -curl -O https://raw.githubusercontent.com/jcupitt/libvips/master/libvips.supp -G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind --suppressions=libvips.supp --suppressions=sharp.supp --leak-check=full --show-leak-kinds=definite,indirect,possible --num-callers=20 node unit.js +curl -O https://raw.githubusercontent.com/jcupitt/libvips/master/libvips.supp test/leak/libvips.supp +cd ../../ +G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind --suppressions=test/leak/libvips.supp --suppressions=test/leak/sharp.supp --leak-check=full --show-leak-kinds=definite,indirect,possible --num-callers=20 npm test diff --git a/tests/sharp.supp b/test/leak/sharp.supp old mode 100644 new mode 100755 similarity index 100% rename from tests/sharp.supp rename to test/leak/sharp.supp diff --git a/test/unit/alpha.js b/test/unit/alpha.js new file mode 100755 index 00000000..b33814d9 --- /dev/null +++ b/test/unit/alpha.js @@ -0,0 +1,49 @@ +'use strict'; + +var assert = require('assert'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Alpha transparency', function() { + + it('Flatten to black', function(done) { + sharp(fixtures.inputPngWithTransparency) + .flatten() + .resize(400, 300) + .toFile(fixtures.path('output.flatten-black.jpg'), done); + }); + + it('Flatten to RGB orange', function(done) { + sharp(fixtures.inputPngWithTransparency) + .flatten() + .background({r: 255, g: 102, b: 0}) + .resize(400, 300) + .toFile(fixtures.path('output.flatten-rgb-orange.jpg'), done); + }); + + it('Flatten to CSS/hex orange', function(done) { + sharp(fixtures.inputPngWithTransparency) + .flatten() + .background('#ff6600') + .resize(400, 300) + .toFile(fixtures.path('output.flatten-hex-orange.jpg'), done); + }); + + it('Ignored for JPEG', function(done) { + sharp(fixtures.inputJpg) + .background('#ff0000') + .flatten() + .resize(500, 400) + .toBuffer(function(err, data) { + if (err) throw err; + sharp(data).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('jpeg', metadata.format); + assert.strictEqual(3, metadata.channels); + done(); + }); + }); + }); + +}); diff --git a/test/unit/colourspace.js b/test/unit/colourspace.js new file mode 100755 index 00000000..2feb5d72 --- /dev/null +++ b/test/unit/colourspace.js @@ -0,0 +1,62 @@ +'use strict'; + +var assert = require('assert'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Colour space conversion', function() { + + it('To greyscale', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 240) + .greyscale() + .toFile(fixtures.path('output.greyscale-gamma-0.0.jpg'), done); + }); + + it('To greyscale with gamma correction', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 240) + .gamma() + .greyscale() + .toFile(fixtures.path('output.greyscale-gamma-2.2.jpg'), done); + }); + + it('From 1-bit TIFF to sRGB WebP [slow]', function(done) { + sharp(fixtures.inputTiff) + .webp() + .toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('webp', info.format); + done(); + }); + }); + + it('From CMYK to sRGB', function(done) { + sharp(fixtures.inputJpgWithCmykProfile) + .resize(320) + .toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + done(); + }); + }); + + it('From CMYK to sRGB with white background, not yellow', function(done) { + sharp(fixtures.inputJpgWithCmykProfile) + .resize(320, 240) + .background('white') + .embed() + .toFile(fixtures.path('output.cmyk2srgb.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }); + +}); diff --git a/test/unit/crop.js b/test/unit/crop.js new file mode 100755 index 00000000..f02efe1b --- /dev/null +++ b/test/unit/crop.js @@ -0,0 +1,82 @@ +'use strict'; + +var assert = require('assert'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Crop gravities', function() { + + it('North', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 80) + .crop(sharp.gravity.north) + .toFile(fixtures.path('output.gravity-north.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual(320, info.width); + assert.strictEqual(80, info.height); + done(); + }); + }); + + it('East', function(done) { + sharp(fixtures.inputJpg) + .resize(80, 320) + .crop(sharp.gravity.east) + .toFile(fixtures.path('output.gravity-east.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual(80, info.width); + assert.strictEqual(320, info.height); + done(); + }); + }); + + it('South', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 80) + .crop(sharp.gravity.south) + .toFile(fixtures.path('output.gravity-south.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual(320, info.width); + assert.strictEqual(80, info.height); + done(); + }); + }); + + it('West', function(done) { + sharp(fixtures.inputJpg) + .resize(80, 320) + .crop(sharp.gravity.west) + .toFile(fixtures.path('output.gravity-west.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual(80, info.width); + assert.strictEqual(320, info.height); + done(); + }); + }); + + it('Center', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 80) + .crop(sharp.gravity.center) + .toFile(fixtures.path('output.gravity-center.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual(320, info.width); + assert.strictEqual(80, info.height); + done(); + }); + }); + + it('Centre', function(done) { + sharp(fixtures.inputJpg) + .resize(80, 320) + .crop(sharp.gravity.centre) + .toFile(fixtures.path('output.gravity-centre.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual(80, info.width); + assert.strictEqual(320, info.height); + done(); + }); + }); + +}); diff --git a/test/unit/embed.js b/test/unit/embed.js new file mode 100755 index 00000000..5e36bdba --- /dev/null +++ b/test/unit/embed.js @@ -0,0 +1,49 @@ +'use strict'; + +var assert = require('assert'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Embed', function() { + + it('JPEG within PNG, no alpha channel', function(done) { + sharp(fixtures.inputJpg) + .embed() + .resize(320, 240) + .png() + .toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('png', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + sharp(data).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual(3, metadata.channels); + done(); + }); + }); + }); + + it('JPEG within WebP, to include alpha channel', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 240) + .background({r: 0, g: 0, b: 0, a: 0}) + .embed() + .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); + sharp(data).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual(4, metadata.channels); + done(); + }); + }); + }); + +}); diff --git a/test/unit/extract.js b/test/unit/extract.js new file mode 100755 index 00000000..5e66afc6 --- /dev/null +++ b/test/unit/extract.js @@ -0,0 +1,93 @@ +'use strict'; + +var assert = require('assert'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Partial image extraction', function() { + + it('JPEG', function(done) { + sharp(fixtures.inputJpg) + .extract(2, 2, 20, 20) + .toFile(fixtures.path('output.extract.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual(20, info.width); + assert.strictEqual(20, info.height); + done(); + }); + }); + + it('PNG', function(done) { + sharp(fixtures.inputPng) + .extract(300, 200, 400, 200) + .toFile(fixtures.path('output.extract.png'), function(err, info) { + if (err) throw err; + assert.strictEqual(400, info.width); + assert.strictEqual(200, info.height); + done(); + }); + }); + + it('WebP', function(done) { + sharp(fixtures.inputWebP) + .extract(50, 100, 125, 200) + .toFile(fixtures.path('output.extract.webp'), function(err, info) { + if (err) throw err; + assert.strictEqual(125, info.width); + assert.strictEqual(200, info.height); + done(); + }); + }); + + it('TIFF', function(done) { + sharp(fixtures.inputTiff) + .extract(63, 34, 341, 529) + .toFile(fixtures.path('output.extract.tiff'), function(err, info) { + if (err) throw err; + assert.strictEqual(341, info.width); + assert.strictEqual(529, info.height); + done(); + }); + }); + + it('Before resize', function(done) { + sharp(fixtures.inputJpg) + .extract(10, 10, 10, 500, 500) + .resize(100, 100) + .toFile(fixtures.path('output.extract.resize.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual(100, info.width); + assert.strictEqual(100, info.height); + done(); + }); + }); + + it('After resize and crop', function(done) { + sharp(fixtures.inputJpg) + .resize(500, 500) + .crop(sharp.gravity.north) + .extract(10, 10, 100, 100) + .toFile(fixtures.path('output.resize.crop.extract.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual(100, info.width); + assert.strictEqual(100, info.height); + done(); + }); + }); + + it('Before and after resize and crop', function(done) { + sharp(fixtures.inputJpg) + .extract(0, 0, 700, 700) + .resize(500, 500) + .crop(sharp.gravity.north) + .extract(10, 10, 100, 100) + .toFile(fixtures.path('output.extract.resize.crop.extract.jpg'), function(err, info) { + if (err) throw err; + assert.strictEqual(100, info.width); + assert.strictEqual(100, info.height); + done(); + }); + }); + +}); diff --git a/test/unit/gamma.js b/test/unit/gamma.js new file mode 100755 index 00000000..da57b207 --- /dev/null +++ b/test/unit/gamma.js @@ -0,0 +1,26 @@ +'use strict'; + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Gamma correction', function() { + + it('value of 0.0 (disabled)', function(done) { + sharp(fixtures.inputJpgWithGammaHoliness) + .resize(129, 111) + .toFile(fixtures.path('output.gamma-0.0.jpg'), done); + }); + it('value of 2.2 (default)', function(done) { + sharp(fixtures.inputJpgWithGammaHoliness) + .resize(129, 111) + .gamma() + .toFile(fixtures.path('output.gamma-2.2.jpg'), done); + }); + it('value of 3.0', function(done) { + sharp(fixtures.inputJpgWithGammaHoliness) + .resize(129, 111) + .gamma(3) + .toFile(fixtures.path('output.gamma-3.0.jpg'), done); + }); + +}); diff --git a/test/unit/interpolation.js b/test/unit/interpolation.js new file mode 100755 index 00000000..81ade380 --- /dev/null +++ b/test/unit/interpolation.js @@ -0,0 +1,94 @@ +'use strict'; + +var assert = require('assert'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Interpolation', function() { + + it('nearest neighbour', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 240) + .interpolateWith(sharp.interpolator.nearest) + .toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }); + + it('bilinear', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 240) + .interpolateWith(sharp.interpolator.bilinear) + .toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }); + + it('bicubic', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 240) + .interpolateWith(sharp.interpolator.bicubic) + .toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }); + + it('nohalo', function(done) { + sharp(fixtures.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('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }); + + it('locally bounded bicubic (LBB)', function(done) { + sharp(fixtures.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('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }); + + it('vertex split quadratic basis spline (VSQBS)', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 240) + .interpolateWith(sharp.interpolator.vertexSplitQuadraticBasisSpline) + .toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }); + +}); diff --git a/test/unit/io.js b/test/unit/io.js new file mode 100755 index 00000000..3ede1b15 --- /dev/null +++ b/test/unit/io.js @@ -0,0 +1,253 @@ +'use strict'; + +var fs = require('fs'); +var assert = require('assert'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Input/output', function() { + + it('Read from File and write to Stream', function(done) { + var writable = fs.createWriteStream(fixtures.outputJpg); + writable.on('finish', function() { + sharp(fixtures.outputJpg).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + fs.unlinkSync(fixtures.outputJpg); + done(); + }); + }); + sharp(fixtures.inputJpg).resize(320, 240).pipe(writable); + }); + + it('Read from Buffer and write to Stream', function(done) { + var inputJpgBuffer = fs.readFileSync(fixtures.inputJpg); + var writable = fs.createWriteStream(fixtures.outputJpg); + writable.on('finish', function() { + sharp(fixtures.outputJpg).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + fs.unlinkSync(fixtures.outputJpg); + done(); + }); + }); + sharp(inputJpgBuffer).resize(320, 240).pipe(writable); + }); + + it('Read from Stream and write to File', function(done) { + var readable = fs.createReadStream(fixtures.inputJpg); + var pipeline = sharp().resize(320, 240).toFile(fixtures.outputJpg, function(err, info) { + if (err) throw err; + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + fs.unlinkSync(fixtures.outputJpg); + done(); + }); + readable.pipe(pipeline); + }); + + it('Read from Stream and write to Buffer', function(done) { + var readable = fs.createReadStream(fixtures.inputJpg); + var pipeline = sharp().resize(320, 240).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + readable.pipe(pipeline); + }); + + it('Read from Stream and write to Stream', function(done) { + var readable = fs.createReadStream(fixtures.inputJpg); + var writable = fs.createWriteStream(fixtures.outputJpg); + writable.on('finish', function() { + sharp(fixtures.outputJpg).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + fs.unlinkSync(fixtures.outputJpg); + done(); + }); + }); + var pipeline = sharp().resize(320, 240); + readable.pipe(pipeline).pipe(writable); + }); + + it('Handle Stream to Stream error ', function(done) { + var pipeline = sharp().resize(320, 240); + var anErrorWasEmitted = false; + pipeline.on('error', function(err) { + anErrorWasEmitted = !!err; + }).on('end', function() { + assert(anErrorWasEmitted); + fs.unlinkSync(fixtures.outputJpg); + done(); + }); + var readableButNotAnImage = fs.createReadStream(__filename); + var writable = fs.createWriteStream(fixtures.outputJpg); + readableButNotAnImage.pipe(pipeline).pipe(writable); + }); + + it('Handle File to Stream error', function(done) { + var readableButNotAnImage = sharp(__filename).resize(320, 240); + var anErrorWasEmitted = false; + readableButNotAnImage.on('error', function(err) { + anErrorWasEmitted = !!err; + }).on('end', function() { + assert(anErrorWasEmitted); + fs.unlinkSync(fixtures.outputJpg); + done(); + }); + var writable = fs.createWriteStream(fixtures.outputJpg); + readableButNotAnImage.pipe(writable); + }); + + it('Fail when output File is input File', function(done) { + sharp(fixtures.inputJpg).toFile(fixtures.inputJpg, function(err) { + assert(!!err); + done(); + }); + }); + + it('Fail when input is empty Buffer', function(done) { + var fail = false; + try { + sharp(new Buffer(0)); + fail = true; + } catch (e) {} + assert(!fail); + done(); + }); + + it('Promises/A+', function(done) { + sharp(fixtures.inputJpg).resize(320, 240).toBuffer().then(function(data) { + sharp(data).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }).catch(function(err) { + throw err; + }); + }); + + it('JPEG quality', function(done) { + sharp(fixtures.inputJpg).resize(320, 240).quality(70).toBuffer(function(err, buffer70) { + if (err) throw err; + sharp(fixtures.inputJpg).resize(320, 240).toBuffer(function(err, buffer80) { + if (err) throw err; + sharp(fixtures.inputJpg).resize(320, 240).quality(90).toBuffer(function(err, buffer90) { + if (err) throw err; + assert(buffer70.length < buffer80.length); + assert(buffer80.length < buffer90.length); + done(); + }); + }); + }); + }); + + describe('Output filename without extension uses input format', function() { + + it('JPEG', function(done) { + sharp(fixtures.inputJpg).resize(320, 80).toFile(fixtures.outputZoinks, function(err, info) { + if (err) throw err; + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(80, info.height); + fs.unlinkSync(fixtures.outputZoinks); + done(); + }); + }); + + it('PNG', function(done) { + sharp(fixtures.inputPng).resize(320, 80).toFile(fixtures.outputZoinks, function(err, info) { + if (err) throw err; + assert.strictEqual('png', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(80, info.height); + fs.unlinkSync(fixtures.outputZoinks); + done(); + }); + }); + + it('Transparent PNG', function(done) { + sharp(fixtures.inputPngWithTransparency).resize(320, 80).toFile(fixtures.outputZoinks, function(err, info) { + if (err) throw err; + assert.strictEqual('png', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(80, info.height); + done(); + }); + }); + + it('WebP', function(done) { + sharp(fixtures.inputWebP).resize(320, 80).toFile(fixtures.outputZoinks, function(err, info) { + if (err) throw err; + assert.strictEqual('webp', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(80, info.height); + fs.unlinkSync(fixtures.outputZoinks); + done(); + }); + }); + + it('TIFF', function(done) { + sharp(fixtures.inputTiff).resize(320, 80).toFile(fixtures.outputZoinks, function(err, info) { + if (err) throw err; + assert.strictEqual('tiff', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(80, info.height); + fs.unlinkSync(fixtures.outputZoinks); + done(); + }); + }); + + it('Fail with GIF', function(done) { + sharp(fixtures.inputGif).resize(320, 80).toFile(fixtures.outputZoinks, function(err) { + assert(!!err); + done(); + }); + }); + + }); + + describe('PNG compression level', function() { + + it('valid', function(done) { + var isValid = false; + try { + sharp().compressionLevel(0); + isValid = true; + } catch (e) {} + assert(isValid); + done(); + }); + + it('invalid', function(done) { + var isValid = false; + try { + sharp().compressionLevel(-1); + isValid = true; + } catch (e) {} + assert(!isValid); + done(); + }); + + }); + +}); diff --git a/test/unit/jshint.js b/test/unit/jshint.js new file mode 100755 index 00000000..ee8b8294 --- /dev/null +++ b/test/unit/jshint.js @@ -0,0 +1 @@ +require('mocha-jshint')(); diff --git a/test/unit/metadata.js b/test/unit/metadata.js new file mode 100755 index 00000000..9e70c17e --- /dev/null +++ b/test/unit/metadata.js @@ -0,0 +1,171 @@ +'use strict'; + +var fs = require('fs'); +var assert = require('assert'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Image metadata', function() { + + it('JPEG', function(done) { + sharp(fixtures.inputJpg).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('jpeg', metadata.format); + assert.strictEqual(2725, metadata.width); + assert.strictEqual(2225, metadata.height); + assert.strictEqual('srgb', metadata.space); + assert.strictEqual(3, metadata.channels); + assert.strictEqual('undefined', typeof metadata.orientation); + done(); + }); + }); + + it('JPEG with EXIF', function(done) { + sharp(fixtures.inputJpgWithExif).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('jpeg', metadata.format); + assert.strictEqual(450, metadata.width); + assert.strictEqual(600, metadata.height); + assert.strictEqual('srgb', metadata.space); + assert.strictEqual(3, metadata.channels); + assert.strictEqual(false, metadata.hasAlpha); + assert.strictEqual(8, metadata.orientation); + done(); + }); + }); + + it('TIFF', function(done) { + sharp(fixtures.inputTiff).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('tiff', metadata.format); + assert.strictEqual(2464, metadata.width); + assert.strictEqual(3248, metadata.height); + assert.strictEqual('b-w', metadata.space); + assert.strictEqual(1, metadata.channels); + assert.strictEqual(false, metadata.hasAlpha); + done(); + }); + }); + + it('PNG', function(done) { + sharp(fixtures.inputPng).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('png', metadata.format); + assert.strictEqual(2809, metadata.width); + assert.strictEqual(2074, metadata.height); + assert.strictEqual('b-w', metadata.space); + assert.strictEqual(1, metadata.channels); + assert.strictEqual(false, metadata.hasAlpha); + done(); + }); + }); + + it('Transparent PNG', function(done) { + sharp(fixtures.inputPngWithTransparency).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('png', metadata.format); + assert.strictEqual(2048, metadata.width); + assert.strictEqual(1536, metadata.height); + assert.strictEqual('srgb', metadata.space); + assert.strictEqual(4, metadata.channels); + assert.strictEqual(true, metadata.hasAlpha); + done(); + }); + }); + + it('WebP', function(done) { + sharp(fixtures.inputWebP).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('webp', metadata.format); + assert.strictEqual(1024, metadata.width); + assert.strictEqual(772, metadata.height); + assert.strictEqual('srgb', metadata.space); + assert.strictEqual(3, metadata.channels); + assert.strictEqual(false, metadata.hasAlpha); + done(); + }); + }); + + it('GIF via libmagick', function(done) { + sharp(fixtures.inputGif).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('magick', metadata.format); + assert.strictEqual(800, metadata.width); + assert.strictEqual(533, metadata.height); + assert.strictEqual(3, metadata.channels); + assert.strictEqual(false, metadata.hasAlpha); + done(); + }); + }); + + it('Promise', function(done) { + sharp(fixtures.inputJpg).metadata().then(function(metadata) { + assert.strictEqual('jpeg', metadata.format); + assert.strictEqual(2725, metadata.width); + assert.strictEqual(2225, metadata.height); + assert.strictEqual('srgb', metadata.space); + assert.strictEqual(3, metadata.channels); + assert.strictEqual(false, metadata.hasAlpha); + done(); + }); + }); + + it('Stream', function(done) { + var readable = fs.createReadStream(fixtures.inputJpg); + var pipeline = sharp().metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('jpeg', metadata.format); + assert.strictEqual(2725, metadata.width); + assert.strictEqual(2225, metadata.height); + assert.strictEqual('srgb', metadata.space); + assert.strictEqual(3, metadata.channels); + assert.strictEqual(false, metadata.hasAlpha); + done(); + }); + readable.pipe(pipeline); + }); + + it('Resize to half width using metadata', function(done) { + var image = sharp(fixtures.inputJpg); + image.metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('jpeg', metadata.format); + assert.strictEqual(2725, metadata.width); + assert.strictEqual(2225, metadata.height); + assert.strictEqual('srgb', metadata.space); + assert.strictEqual(3, metadata.channels); + assert.strictEqual(false, metadata.hasAlpha); + image.resize(metadata.width / 2).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual(1362, info.width); + assert.strictEqual(1112, info.height); + done(); + }); + }); + }); + + it('Keep EXIF metadata after a resize', function(done) { + sharp(fixtures.inputJpgWithExif).resize(320, 240).withMetadata().toBuffer(function(err, buffer) { + if (err) throw err; + sharp(buffer).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual(8, metadata.orientation); + done(); + }); + }); + }); + + it('Remove EXIF metadata after a resize', function(done) { + sharp(fixtures.inputJpgWithExif).resize(320, 240).withMetadata(false).toBuffer(function(err, buffer) { + if (err) throw err; + sharp(buffer).metadata(function(err, metadata) { + if (err) throw err; + assert.strictEqual('undefined', typeof metadata.orientation); + done(); + }); + }); + }); + +}); diff --git a/test/unit/resize.js b/test/unit/resize.js new file mode 100755 index 00000000..3e4048ae --- /dev/null +++ b/test/unit/resize.js @@ -0,0 +1,142 @@ +'use strict'; + +var assert = require('assert'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Resize dimensions', function() { + + it('Exact crop', function(done) { + sharp(fixtures.inputJpg).resize(320, 240).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }); + + it('Fixed width', function(done) { + sharp(fixtures.inputJpg).resize(320).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(261, info.height); + done(); + }); + }); + + it('Fixed height', function(done) { + sharp(fixtures.inputJpg).resize(null, 320).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(391, info.width); + assert.strictEqual(320, info.height); + done(); + }); + }); + + it('Identity transform', function(done) { + sharp(fixtures.inputJpg).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(2725, info.width); + assert.strictEqual(2225, info.height); + done(); + }); + }); + + it('Upscale', function(done) { + sharp(fixtures.inputJpg).resize(3000).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(3000, info.width); + assert.strictEqual(2449, info.height); + done(); + }); + }); + + it('TIFF embed known to cause rounding errors', function(done) { + sharp(fixtures.inputTiff).resize(240, 320).embed().jpeg().toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(240, info.width); + assert.strictEqual(320, info.height); + done(); + }); + }); + + it('TIFF known to cause rounding errors', function(done) { + sharp(fixtures.inputTiff).resize(240, 320).jpeg().toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(240, info.width); + assert.strictEqual(320, info.height); + done(); + }); + }); + + it('Max width or height considering ratio (landscape)', function(done) { + sharp(fixtures.inputJpg).resize(320, 320).max().toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(261, info.height); + done(); + }); + }); + + it('Max width or height considering ratio (portrait)', function(done) { + sharp(fixtures.inputTiff).resize(320, 320).max().jpeg().toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(243, info.width); + assert.strictEqual(320, info.height); + done(); + }); + }); + + it('Provide only one dimension with max, should default to crop', function(done) { + sharp(fixtures.inputJpg).resize(320).max().toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(261, info.height); + done(); + }); + }); + + it('Do not enlarge if input width is already less than output width', function(done) { + sharp(fixtures.inputJpg).resize(2800).withoutEnlargement().toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(2725, info.width); + assert.strictEqual(2225, info.height); + done(); + }); + }); + + it('Do not enlarge if input height is already less than output height', function(done) { + sharp(fixtures.inputJpg).resize(null, 2300).withoutEnlargement().toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(2725, info.width); + assert.strictEqual(2225, info.height); + done(); + }); + }); + +}); diff --git a/test/unit/rotate.js b/test/unit/rotate.js new file mode 100755 index 00000000..65a72997 --- /dev/null +++ b/test/unit/rotate.js @@ -0,0 +1,64 @@ +'use strict'; + +var assert = require('assert'); + +var sharp = require('../../index'); +var fixtures = require('../fixtures'); + +describe('Rotation', function() { + + it('Rotate by 90 degrees, respecting output input size', function(done) { + sharp(fixtures.inputJpg).rotate(90).resize(320, 240).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }); + + it('Input image has Orientation EXIF tag but do not rotate output', function(done) { + sharp(fixtures.inputJpgWithExif).resize(320).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(426, info.height); + done(); + }); + }); + + it('Input image has Orientation EXIF tag value of 8 (270 degrees), auto-rotate', function(done) { + sharp(fixtures.inputJpgWithExif).rotate().resize(320).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + done(); + }); + }); + + it('Attempt to auto-rotate using image that has no EXIF', function(done) { + sharp(fixtures.inputJpg).rotate().resize(320).toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual(true, data.length > 0); + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(261, info.height); + done(); + }); + }); + + it('Rotate to an invalid angle, should fail', function(done) { + var fail = false; + try { + sharp(fixtures.inputJpg).rotate(1); + fail = true; + } catch (e) {} + assert(!fail); + done(); + }); + +}); diff --git a/test/unit/util.js b/test/unit/util.js new file mode 100755 index 00000000..6f917135 --- /dev/null +++ b/test/unit/util.js @@ -0,0 +1,38 @@ +'use strict'; + +var assert = require('assert'); +var sharp = require('../../index'); + +var defaultConcurrency = sharp.concurrency(); + +describe('Utilities', function() { + + describe('Cache', function() { + it('Can be disabled', function() { + sharp.cache(0); + }); + it('Can be set to a maximum of 50MB and 500 items', function() { + sharp.cache(50, 500); + }); + }); + + describe('Concurrency', function() { + it('Can be set to use 16 threads', function() { + sharp.concurrency(16); + assert.strictEqual(16, sharp.concurrency()); + }); + it('Can be reset to default', function() { + sharp.concurrency(0); + assert.strictEqual(defaultConcurrency, sharp.concurrency()); + }); + }); + + describe('Counters', function() { + it('Have zero value at rest', function() { + var counters = sharp.counters(); + assert.strictEqual(0, counters.queue); + assert.strictEqual(0, counters.process); + }); + }); + +}); diff --git a/tests/random.js b/tests/random.js deleted file mode 100755 index b1168d59..00000000 --- a/tests/random.js +++ /dev/null @@ -1,69 +0,0 @@ -/*jslint node: true */ -'use strict'; - -var sharp = require('../index'); -var path = require('path'); -var imagemagick = require('imagemagick'); -var gm = require('gm'); -var assert = require('assert'); -var Benchmark = require('benchmark'); - -var fixturesPath = path.join(__dirname, 'fixtures'); -var inputJpg = path.join(fixturesPath, '2569067123_aca715a2ee_o.jpg'); // http://www.flickr.com/photos/grizdave/2569067123/ -var outputJpg = path.join(fixturesPath, 'output.jpg'); - -var min = 320; -var max = 960; - -var randomDimension = function() { - return Math.random() * (max - min) + min; -}; - -new Benchmark.Suite('random').add('imagemagick', { - defer: true, - fn: function(deferred) { - imagemagick.resize({ - srcPath: inputJpg, - dstPath: outputJpg, - quality: 0.8, - width: randomDimension(), - height: randomDimension() - }, function(err) { - if (err) { - throw err; - } else { - deferred.resolve(); - } - }); - } -}).add('gm', { - defer: true, - fn: function(deferred) { - gm(inputJpg).resize(randomDimension(), randomDimension()).quality(80).toBuffer(function (err, buffer) { - if (err) { - throw err; - } else { - assert.notStrictEqual(null, buffer); - deferred.resolve(); - } - }); - } -}).add('sharp', { - defer: true, - fn: function(deferred) { - sharp(inputJpg).resize(randomDimension(), randomDimension()).toBuffer(function(err, buffer) { - if (err) { - throw err; - } else { - assert.notStrictEqual(null, buffer); - deferred.resolve(); - } - }); - } -}).on('cycle', function(event) { - console.log(String(event.target)); -}).on('complete', function() { - var winner = this.filter('fastest').pluck('name'); - assert.strictEqual('sharp', String(winner), 'sharp was slower than ' + winner); - console.dir(sharp.cache()); -}).run(); diff --git a/tests/unit.js b/tests/unit.js deleted file mode 100755 index 8c71ccf1..00000000 --- a/tests/unit.js +++ /dev/null @@ -1,934 +0,0 @@ -/*jslint node: true */ -/*jslint es5: true */ -'use strict'; - -var sharp = require('../index'); -var fs = require('fs'); -var path = require('path'); -var assert = require('assert'); -var async = require('async'); - -var fixturesPath = path.join(__dirname, 'fixtures'); - -var inputJpg = path.join(fixturesPath, '2569067123_aca715a2ee_o.jpg'); // http://www.flickr.com/photos/grizdave/2569067123/ -var inputJpgWithExif = path.join(fixturesPath, 'Landscape_8.jpg'); // https://github.com/recurser/exif-orientation-examples/blob/master/Landscape_8.jpg -var inputJpgWithGammaHoliness = path.join(fixturesPath, 'gamma_dalai_lama_gray.jpg'); // http://www.4p8.com/eric.brasseur/gamma.html -var inputJpgWithCmykProfile = path.join(fixturesPath, 'Channel_digital_image_CMYK_color.jpg'); // http://en.wikipedia.org/wiki/File:Channel_digital_image_CMYK_color.jpg - -var inputPng = path.join(fixturesPath, '50020484-00001.png'); // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png -var inputPngWithTransparency = path.join(fixturesPath, 'blackbug.png'); // public domain - -var inputWebP = path.join(fixturesPath, '4.webp'); // http://www.gstatic.com/webp/gallery/4.webp -var inputTiff = path.join(fixturesPath, 'G31D.TIF'); // http://www.fileformat.info/format/tiff/sample/e6c9a6e5253348f4aef6d17b534360ab/index.htm -var inputGif = path.join(fixturesPath, 'Crash_test.gif'); // http://upload.wikimedia.org/wikipedia/commons/e/e3/Crash_test.gif - -var outputJpg = path.join(fixturesPath, 'output.jpg'); -var outputZoinks = path.join(fixturesPath, 'output.zoinks'); // an 'unknown' file extension - -// Ensure cache limits can be set -sharp.cache(0); // Disable -sharp.cache(50, 500); // 50MB, 500 items - -// Ensure concurrency can be set -var defaultConcurrency = sharp.concurrency(); -sharp.concurrency(16); -assert.strictEqual(16, sharp.concurrency()); -sharp.concurrency(0); -assert.strictEqual(defaultConcurrency, sharp.concurrency()); - -async.series([ - // Resize with exact crop - function(done) { - sharp(inputJpg).resize(320, 240).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - done(); - }); - }, - // Resize to fixed width - function(done) { - sharp(inputJpg).resize(320).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(261, info.height); - done(); - }); - }, - // Resize to fixed height - function(done) { - sharp(inputJpg).resize(null, 320).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(391, info.width); - assert.strictEqual(320, info.height); - done(); - }); - }, - // Identity transform - function(done) { - sharp(inputJpg).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(2725, info.width); - assert.strictEqual(2225, info.height); - done(); - }); - }, - // Upscale - function(done) { - sharp(inputJpg).resize(3000).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(3000, info.width); - assert.strictEqual(2449, info.height); - done(); - }); - }, - // Embed - JPEG within PNG, no alpha channel - function(done) { - sharp(inputJpg) - .embed() - .resize(320, 240) - .png() - .toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('png', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - sharp(data).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual(3, metadata.channels); - done(); - }); - }); - }, - // Embed - JPEG within WebP, to include alpha channel - function(done) { - sharp(inputJpg) - .resize(320, 240) - .background({r: 0, g: 0, b: 0, a: 0}) - .embed() - .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); - sharp(data).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual(4, metadata.channels); - done(); - }); - }); - }, - // Quality - function(done) { - sharp(inputJpg).resize(320, 240).quality(70).toBuffer(function(err, buffer70) { - if (err) throw err; - sharp(inputJpg).resize(320, 240).toBuffer(function(err, buffer80) { - if (err) throw err; - sharp(inputJpg).resize(320, 240).quality(90).toBuffer(function(err, buffer90) { - if (err) throw err; - assert(buffer70.length < buffer80.length); - assert(buffer80.length < buffer90.length); - done(); - }); - }); - }); - }, - // TIFF with dimensions known to cause rounding errors - function(done) { - sharp(inputTiff).resize(240, 320).embed().jpeg().toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(240, info.width); - assert.strictEqual(320, info.height); - done(); - }); - }, - function(done) { - sharp(inputTiff).resize(240, 320).jpeg().toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(240, info.width); - assert.strictEqual(320, info.height); - done(); - }); - }, - // Resize to max width or height considering ratio (landscape) - function(done) { - sharp(inputJpg).resize(320, 320).max().toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(261, info.height); - done(); - }); - }, - // Resize to max width or height considering ratio (portrait) - function(done) { - sharp(inputTiff).resize(320, 320).max().jpeg().toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(243, info.width); - assert.strictEqual(320, info.height); - done(); - }); - }, - // Attempt to resize to max but only provide one dimension, so should default to crop - function(done) { - sharp(inputJpg).resize(320).max().toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(261, info.height); - done(); - }); - }, - // Attempt to output to input, should fail - function(done) { - sharp(inputJpg).toFile(inputJpg, function(err) { - assert(!!err); - done(); - }); - }, - // Rotate by 90 degrees, respecting output input size - function(done) { - sharp(inputJpg).rotate(90).resize(320, 240).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - done(); - }); - }, - // Input image has Orientation EXIF tag but do not rotate output - function(done) { - sharp(inputJpgWithExif).resize(320).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(426, info.height); - done(); - }); - }, - // Input image has Orientation EXIF tag value of 8 (270 degrees), auto-rotate - function(done) { - sharp(inputJpgWithExif).rotate().resize(320).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - done(); - }); - }, - // Attempt to auto-rotate using image that has no EXIF - function(done) { - sharp(inputJpg).rotate().resize(320).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(261, info.height); - done(); - }); - }, - // Rotate to an invalid angle, should fail - function(done) { - var fail = false; - try { - sharp(inputJpg).rotate(1); - fail = true; - } catch (e) {} - assert(!fail); - done(); - }, - // Do not enlarge the output if the input width is already less than the output width - function(done) { - sharp(inputJpg).resize(2800).withoutEnlargement().toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(2725, info.width); - assert.strictEqual(2225, info.height); - done(); - }); - }, - // Do not enlarge the output if the input height is already less than the output height - function(done) { - sharp(inputJpg).resize(null, 2300).withoutEnlargement().toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(2725, info.width); - assert.strictEqual(2225, info.height); - done(); - }); - }, - // Promises/A+ - function(done) { - sharp(inputJpg).resize(320, 240).toBuffer().then(function(data) { - sharp(data).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - done(); - }); - }).catch(function(err) { - throw err; - }); - }, - // Empty Buffer, should fail - function(done) { - var fail = false; - try { - sharp(new Buffer(0)); - fail = true; - } catch (e) {} - assert(!fail); - done(); - }, - // Check colour space conversion occurs from TIFF to WebP (this used to segfault) - function(done) { - sharp(inputTiff).webp().toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('webp', info.format); - done(); - }); - }, - // Check colour space conversion from CMYK to sRGB - function(done) { - sharp(inputJpgWithCmykProfile).resize(320).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - done(); - }); - }, - // Check colour space conversion from CMYK to sRGB works with background colour (yellow=fail) - function(done) { - sharp(inputJpgWithCmykProfile).resize(320, 240).background('white').embed().toFile(path.join(fixturesPath, 'output.cmyk2srgb.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - done(); - }); - }, - // Interpolation: nearest neighbour - function(done) { - sharp(inputJpg).resize(320, 240).interpolateWith(sharp.interpolator.nearest).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - done(); - }); - }, - // Interpolation: bilinear - function(done) { - sharp(inputJpg).resize(320, 240).interpolateWith(sharp.interpolator.bilinear).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - done(); - }); - }, - // Interpolation: bicubic - function(done) { - sharp(inputJpg).resize(320, 240).interpolateWith(sharp.interpolator.bicubic).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - done(); - }); - }, - // Interpolation: nohalo - function(done) { - 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('jpeg', info.format); - 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('jpeg', info.format); - 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; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - done(); - }); - }, - // File-Stream - function(done) { - var writable = fs.createWriteStream(outputJpg); - writable.on('finish', function() { - sharp(outputJpg).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - fs.unlinkSync(outputJpg); - done(); - }); - }); - sharp(inputJpg).resize(320, 240).pipe(writable); - }, - // Buffer-Stream - function(done) { - var inputJpgBuffer = fs.readFileSync(inputJpg); - var writable = fs.createWriteStream(outputJpg); - writable.on('finish', function() { - sharp(outputJpg).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - fs.unlinkSync(outputJpg); - done(); - }); - }); - sharp(inputJpgBuffer).resize(320, 240).pipe(writable); - }, - // Stream-File - function(done) { - var readable = fs.createReadStream(inputJpg); - var pipeline = sharp().resize(320, 240).toFile(outputJpg, function(err, info) { - if (err) throw err; - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - fs.unlinkSync(outputJpg); - done(); - }); - readable.pipe(pipeline); - }, - // Stream-Buffer - function(done) { - var readable = fs.createReadStream(inputJpg); - var pipeline = sharp().resize(320, 240).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - done(); - }); - readable.pipe(pipeline); - }, - // Stream-Stream - function(done) { - var readable = fs.createReadStream(inputJpg); - var writable = fs.createWriteStream(outputJpg); - writable.on('finish', function() { - sharp(outputJpg).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(240, info.height); - fs.unlinkSync(outputJpg); - done(); - }); - }); - var pipeline = sharp().resize(320, 240); - readable.pipe(pipeline).pipe(writable); - }, - // Stream-Stream error handling - function(done) { - var pipeline = sharp().resize(320, 240); - var anErrorWasEmitted = false; - pipeline.on('error', function(err) { - anErrorWasEmitted = !!err; - }).on('end', function() { - assert(anErrorWasEmitted); - fs.unlinkSync(outputJpg); - done(); - }); - var readableButNotAnImage = fs.createReadStream(__filename); - var writable = fs.createWriteStream(outputJpg); - readableButNotAnImage.pipe(pipeline).pipe(writable); - }, - // File-Stream error handling - function(done) { - var readableButNotAnImage = sharp(__filename).resize(320, 240); - var anErrorWasEmitted = false; - readableButNotAnImage.on('error', function(err) { - anErrorWasEmitted = !!err; - }).on('end', function() { - assert(anErrorWasEmitted); - fs.unlinkSync(outputJpg); - done(); - }); - var writable = fs.createWriteStream(outputJpg); - readableButNotAnImage.pipe(writable); - }, - // Crop, gravity=north - function(done) { - sharp(inputJpg).resize(320, 80).crop(sharp.gravity.north).toFile(path.join(fixturesPath, 'output.gravity-north.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual(320, info.width); - assert.strictEqual(80, info.height); - done(); - }); - }, - // Crop, gravity=east - function(done) { - sharp(inputJpg).resize(80, 320).crop(sharp.gravity.east).toFile(path.join(fixturesPath, 'output.gravity-east.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual(80, info.width); - assert.strictEqual(320, info.height); - done(); - }); - }, - // Crop, gravity=south - function(done) { - sharp(inputJpg).resize(320, 80).crop(sharp.gravity.south).toFile(path.join(fixturesPath, 'output.gravity-south.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual(320, info.width); - assert.strictEqual(80, info.height); - done(); - }); - }, - // Crop, gravity=west - function(done) { - sharp(inputJpg).resize(80, 320).crop(sharp.gravity.west).toFile(path.join(fixturesPath, 'output.gravity-west.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual(80, info.width); - assert.strictEqual(320, info.height); - done(); - }); - }, - // Crop, gravity=center - function(done) { - sharp(inputJpg).resize(320, 80).crop(sharp.gravity.center).toFile(path.join(fixturesPath, 'output.gravity-center.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual(320, info.width); - assert.strictEqual(80, info.height); - done(); - }); - }, - // Crop, gravity=centre - function(done) { - sharp(inputJpg).resize(80, 320).crop(sharp.gravity.centre).toFile(path.join(fixturesPath, 'output.gravity-centre.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual(80, info.width); - assert.strictEqual(320, info.height); - done(); - }); - }, - // Extract jpg - function(done) { - sharp(inputJpg).extract(2,2,20,20).toFile(path.join(fixturesPath, 'output.extract.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual(20, info.width); - assert.strictEqual(20, info.height); - done(); - }); - }, - // Extract png - function(done) { - sharp(inputPng).extract(300,200,400,200).toFile(path.join(fixturesPath, 'output.extract.png'), function(err, info) { - if (err) throw err; - assert.strictEqual(400, info.width); - assert.strictEqual(200, info.height); - done(); - }); - }, - // Extract webp - function(done) { - sharp(inputWebP).extract(50, 100, 125, 200).toFile(path.join(fixturesPath, 'output.extract.webp'), function(err, info) { - if (err) throw err; - assert.strictEqual(125, info.width); - assert.strictEqual(200, info.height); - done(); - }); - }, - // Extract tiff - function(done) { - sharp(inputTiff).extract(63, 34, 341, 529).toFile(path.join(fixturesPath, 'output.extract.tiff'), function(err, info) { - if (err) throw err; - assert.strictEqual(341, info.width); - assert.strictEqual(529, info.height); - done(); - }); - }, - // Extract before resize - function(done) { - sharp(inputJpg).extract(10, 10, 10, 500, 500).resize(100, 100).toFile(path.join(fixturesPath, 'output.extract.resize.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual(100, info.width); - assert.strictEqual(100, info.height); - done(); - }); - }, - // Extract after resize and crop - function(done) { - sharp(inputJpg).resize(500, 500).crop(sharp.gravity.north).extract(10, 10, 100, 100).toFile(path.join(fixturesPath, 'output.resize.crop.extract.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual(100, info.width); - assert.strictEqual(100, info.height); - done(); - }); - }, - // Extract before and after resize and crop - function(done) { - sharp(inputJpg).extract(0, 0, 700, 700).resize(500, 500).crop(sharp.gravity.north).extract(10, 10, 100, 100).toFile(path.join(fixturesPath, 'output.extract.resize.crop.extract.jpg'), function(err, info) { - if (err) throw err; - assert.strictEqual(100, info.width); - assert.strictEqual(100, info.height); - done(); - }); - }, - // Keeps Metadata after a resize - function(done) { - sharp(inputJpgWithExif).resize(320, 240).withMetadata().toBuffer(function(err, buffer) { - if (err) throw err; - sharp(buffer).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual(8, metadata.orientation); - done(); - }); - }); - }, - // Keeps Metadata after a resize - function(done) { - sharp(inputJpgWithExif).resize(320, 240).withMetadata(false).toBuffer(function(err, buffer) { - if (err) throw err; - sharp(buffer).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual('undefined', typeof metadata.orientation); - done(); - }); - }); - }, - // Output filename without extension should mirror input format - function(done) { - sharp(inputJpg).resize(320, 80).toFile(outputZoinks, function(err, info) { - if (err) throw err; - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(80, info.height); - fs.unlinkSync(outputZoinks); - done(); - }); - }, - function(done) { - sharp(inputPng).resize(320, 80).toFile(outputZoinks, function(err, info) { - if (err) throw err; - assert.strictEqual('png', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(80, info.height); - fs.unlinkSync(outputZoinks); - done(); - }); - }, - function(done) { - sharp(inputPngWithTransparency).resize(320, 80).toFile(outputZoinks, function(err, info) { - if (err) throw err; - assert.strictEqual('png', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(80, info.height); - done(); - }); - }, - function(done) { - sharp(inputWebP).resize(320, 80).toFile(outputZoinks, function(err, info) { - if (err) throw err; - assert.strictEqual('webp', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(80, info.height); - fs.unlinkSync(outputZoinks); - done(); - }); - }, - function(done) { - sharp(inputTiff).resize(320, 80).toFile(outputZoinks, function(err, info) { - if (err) throw err; - assert.strictEqual('tiff', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(80, info.height); - fs.unlinkSync(outputZoinks); - done(); - }); - }, - function(done) { - sharp(inputGif).resize(320, 80).toFile(outputZoinks, function(err) { - assert(!!err); - done(); - }); - }, - // Metadata - JPEG - function(done) { - sharp(inputJpg).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual('jpeg', metadata.format); - assert.strictEqual(2725, metadata.width); - assert.strictEqual(2225, metadata.height); - assert.strictEqual('srgb', metadata.space); - assert.strictEqual(3, metadata.channels); - assert.strictEqual('undefined', typeof metadata.orientation); - done(); - }); - }, - // Metadata - JPEG with EXIF - function(done) { - sharp(inputJpgWithExif).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual('jpeg', metadata.format); - assert.strictEqual(450, metadata.width); - assert.strictEqual(600, metadata.height); - assert.strictEqual('srgb', metadata.space); - assert.strictEqual(3, metadata.channels); - assert.strictEqual(false, metadata.hasAlpha); - assert.strictEqual(8, metadata.orientation); - done(); - }); - }, - // Metadata - TIFF - function(done) { - sharp(inputTiff).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual('tiff', metadata.format); - assert.strictEqual(2464, metadata.width); - assert.strictEqual(3248, metadata.height); - assert.strictEqual('b-w', metadata.space); - assert.strictEqual(1, metadata.channels); - assert.strictEqual(false, metadata.hasAlpha); - done(); - }); - }, - // Metadata - PNG - function(done) { - sharp(inputPng).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual('png', metadata.format); - assert.strictEqual(2809, metadata.width); - assert.strictEqual(2074, metadata.height); - assert.strictEqual('b-w', metadata.space); - assert.strictEqual(1, metadata.channels); - assert.strictEqual(false, metadata.hasAlpha); - done(); - }); - }, - // Metadata - Transparent PNG - function(done) { - sharp(inputPngWithTransparency).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual('png', metadata.format); - assert.strictEqual(2048, metadata.width); - assert.strictEqual(1536, metadata.height); - assert.strictEqual('srgb', metadata.space); - assert.strictEqual(4, metadata.channels); - assert.strictEqual(true, metadata.hasAlpha); - done(); - }); - }, - // Metadata - WebP - function(done) { - sharp(inputWebP).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual('webp', metadata.format); - assert.strictEqual(1024, metadata.width); - assert.strictEqual(772, metadata.height); - assert.strictEqual('srgb', metadata.space); - assert.strictEqual(3, metadata.channels); - assert.strictEqual(false, metadata.hasAlpha); - done(); - }); - }, - // Metadata - GIF (via libmagick) - function(done) { - sharp(inputGif).metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual('magick', metadata.format); - assert.strictEqual(800, metadata.width); - assert.strictEqual(533, metadata.height); - assert.strictEqual(3, metadata.channels); - assert.strictEqual(false, metadata.hasAlpha); - done(); - }); - }, - // Metadata - Promise - function(done) { - sharp(inputJpg).metadata().then(function(metadata) { - assert.strictEqual('jpeg', metadata.format); - assert.strictEqual(2725, metadata.width); - assert.strictEqual(2225, metadata.height); - assert.strictEqual('srgb', metadata.space); - assert.strictEqual(3, metadata.channels); - assert.strictEqual(false, metadata.hasAlpha); - done(); - }); - }, - // Metadata - Stream - function(done) { - var readable = fs.createReadStream(inputJpg); - var pipeline = sharp().metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual('jpeg', metadata.format); - assert.strictEqual(2725, metadata.width); - assert.strictEqual(2225, metadata.height); - assert.strictEqual('srgb', metadata.space); - assert.strictEqual(3, metadata.channels); - assert.strictEqual(false, metadata.hasAlpha); - done(); - }); - readable.pipe(pipeline); - }, - // Get metadata then resize to half width - function(done) { - var image = sharp(inputJpg); - image.metadata(function(err, metadata) { - if (err) throw err; - assert.strictEqual('jpeg', metadata.format); - assert.strictEqual(2725, metadata.width); - assert.strictEqual(2225, metadata.height); - assert.strictEqual('srgb', metadata.space); - assert.strictEqual(3, metadata.channels); - assert.strictEqual(false, metadata.hasAlpha); - image.resize(metadata.width / 2).toBuffer(function(err, data, info) { - if (err) throw err; - assert.strictEqual(true, data.length > 0); - assert.strictEqual(1362, info.width); - assert.strictEqual(1112, info.height); - done(); - }); - }); - }, - // Gamma correction - function(done) { - sharp(inputJpgWithGammaHoliness).resize(129, 111).toFile(path.join(fixturesPath, 'output.gamma-0.0.jpg'), function(err) { - if (err) throw err; - done(); - }); - }, - function(done) { - sharp(inputJpgWithGammaHoliness).resize(129, 111).gamma().toFile(path.join(fixturesPath, 'output.gamma-2.2.jpg'), function(err) { - if (err) throw err; - done(); - }); - }, - function(done) { - sharp(inputJpgWithGammaHoliness).resize(129, 111).gamma(3).toFile(path.join(fixturesPath, 'output.gamma-3.0.jpg'), function(err) { - if (err) throw err; - done(); - }); - }, - // Greyscale conversion - function(done) { - sharp(inputJpg).resize(320, 240).greyscale().toFile(path.join(fixturesPath, 'output.greyscale-gamma-0.0.jpg'), function(err) { - if (err) throw err; - done(); - }); - }, - function(done) { - sharp(inputJpg).resize(320, 240).gamma().greyscale().toFile(path.join(fixturesPath, 'output.greyscale-gamma-2.2.jpg'), function(err) { - if (err) throw err; - done(); - }); - }, - // Flattening - function(done) { - sharp(inputPngWithTransparency).flatten().resize(400, 300).toFile(path.join(fixturesPath, 'output.flatten-black.jpg'), function(err) { - if (err) throw err; - done(); - }); - }, - function(done) { - sharp(inputPngWithTransparency).flatten().background({r: 255, g: 102, b: 0}).resize(400, 300).toFile(path.join(fixturesPath, 'output.flatten-rgb-orange.jpg'), function(err) { - if (err) throw err; - done(); - }); - }, - function(done) { - sharp(inputPngWithTransparency).flatten().background('#ff6600').resize(400, 300).toFile(path.join(fixturesPath, 'output.flatten-hex-orange.jpg'), function(err) { - if (err) throw err; - done(); - }); - }, - function(done) { - sharp(inputJpg).background('#ff0000').flatten().resize(500, 400).toFile(path.join(fixturesPath, 'output.flatten-input-jpg.jpg'), function(err) { - if (err) throw err; - done(); - }); - }, - // PNG compression level - valid - function(done) { - var isValid = false; - try { - sharp().compressionLevel(0); - isValid = true; - } catch (e) {} - assert(isValid); - done(); - }, - // PNG compression level - invalid - function(done) { - var isValid = false; - try { - sharp().compressionLevel(-1); - isValid = true; - } catch (e) {} - assert(!isValid); - done(); - }, - // Verify internal counters - function(done) { - var counters = sharp.counters(); - assert.strictEqual(0, counters.queue); - assert.strictEqual(0, counters.process); - done(); - }, - // Empty cache - function(done) { - sharp.cache(0); - done(); - } -]);