Tests: separate IO suite into per-format unit files

This commit is contained in:
Lovell Fuller 2019-01-13 10:11:32 +00:00
parent 98797445de
commit 32a34a8841
7 changed files with 1013 additions and 965 deletions

View File

@ -349,162 +349,6 @@ describe('Input/output', function () {
.toBuffer();
});
it('JPEG quality', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ 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)
.jpeg({ quality: 90 })
.toBuffer(function (err, buffer90) {
if (err) throw err;
assert(buffer70.length < buffer80.length);
assert(buffer80.length < buffer90.length);
done();
});
});
});
});
describe('Invalid JPEG quality', function () {
[-1, 88.2, 'test'].forEach(function (quality) {
it(quality.toString(), function () {
assert.throws(function () {
sharp().jpeg({ quality: quality });
});
});
});
});
describe('Invalid JPEG quantisation table', function () {
[-1, 88.2, 'test'].forEach(function (table) {
it(table.toString(), function () {
assert.throws(function () {
sharp().jpeg({ quantisationTable: table });
});
});
});
});
it('Progressive JPEG image', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ progressive: false })
.toBuffer(function (err, nonProgressiveData, nonProgressiveInfo) {
if (err) throw err;
assert.strictEqual(true, nonProgressiveData.length > 0);
assert.strictEqual(nonProgressiveData.length, nonProgressiveInfo.size);
assert.strictEqual('jpeg', nonProgressiveInfo.format);
assert.strictEqual(320, nonProgressiveInfo.width);
assert.strictEqual(240, nonProgressiveInfo.height);
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ progressive: true })
.toBuffer(function (err, progressiveData, progressiveInfo) {
if (err) throw err;
assert.strictEqual(true, progressiveData.length > 0);
assert.strictEqual(progressiveData.length, progressiveInfo.size);
assert.strictEqual(false, progressiveData.length === nonProgressiveData.length);
assert.strictEqual('jpeg', progressiveInfo.format);
assert.strictEqual(320, progressiveInfo.width);
assert.strictEqual(240, progressiveInfo.height);
done();
});
});
});
it('Progressive PNG image', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.png({ progressive: false })
.toBuffer(function (err, nonProgressiveData, nonProgressiveInfo) {
if (err) throw err;
assert.strictEqual(true, nonProgressiveData.length > 0);
assert.strictEqual(nonProgressiveData.length, nonProgressiveInfo.size);
assert.strictEqual('png', nonProgressiveInfo.format);
assert.strictEqual(320, nonProgressiveInfo.width);
assert.strictEqual(240, nonProgressiveInfo.height);
sharp(nonProgressiveData)
.png({ progressive: true })
.toBuffer(function (err, progressiveData, progressiveInfo) {
if (err) throw err;
assert.strictEqual(true, progressiveData.length > 0);
assert.strictEqual(progressiveData.length, progressiveInfo.size);
assert.strictEqual(true, progressiveData.length > nonProgressiveData.length);
assert.strictEqual('png', progressiveInfo.format);
assert.strictEqual(320, progressiveInfo.width);
assert.strictEqual(240, progressiveInfo.height);
done();
});
});
});
if (sharp.format.webp.output.buffer) {
it('WebP output', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.toFormat(sharp.format.webp)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual('webp', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
done();
});
});
it('should work for webp alpha quality', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({ alphaQuality: 80 })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual('webp', info.format);
fixtures.assertSimilar(fixtures.expected('webp-alpha-80.webp'), data, done);
});
});
it('should work for webp lossless', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({ lossless: true })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual('webp', info.format);
fixtures.assertSimilar(fixtures.expected('webp-lossless.webp'), data, done);
});
});
it('should work for webp near-lossless', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({ nearLossless: true, quality: 50 })
.toBuffer(function (err50, data50, info50) {
if (err50) throw err50;
assert.strictEqual(true, data50.length > 0);
assert.strictEqual('webp', info50.format);
fixtures.assertSimilar(fixtures.expected('webp-near-lossless-50.webp'), data50, done);
});
});
it('should use near-lossless when both lossless and nearLossless are specified', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({ nearLossless: true, quality: 50, lossless: true })
.toBuffer(function (err50, data50, info50) {
if (err50) throw err50;
assert.strictEqual(true, data50.length > 0);
assert.strictEqual('webp', info50.format);
fixtures.assertSimilar(fixtures.expected('webp-near-lossless-50.webp'), data50, done);
});
});
}
it('Invalid output format', function (done) {
let isValid = false;
try {
@ -531,22 +375,6 @@ describe('Input/output', function () {
});
});
it('TIFF file input with invalid page fails gracefully', function (done) {
sharp(fixtures.inputTiffMultipage, { page: 2 })
.toBuffer(function (err) {
assert.strictEqual(true, !!err);
done();
});
});
it('TIFF buffer input with invalid page fails gracefully', function (done) {
sharp(fs.readFileSync(fixtures.inputTiffMultipage), { page: 2 })
.toBuffer(function (err) {
assert.strictEqual(true, !!err);
done();
});
});
describe('Output filename with unknown extension', function () {
it('Match JPEG input', function (done) {
sharp(fixtures.inputJpg)
@ -628,669 +456,6 @@ describe('Input/output', function () {
});
});
it('Without chroma subsampling generates larger file', function (done) {
// First generate with chroma subsampling (default)
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ chromaSubsampling: '4:2:0' })
.toBuffer(function (err, withChromaSubsamplingData, withChromaSubsamplingInfo) {
if (err) throw err;
assert.strictEqual(true, withChromaSubsamplingData.length > 0);
assert.strictEqual(withChromaSubsamplingData.length, withChromaSubsamplingInfo.size);
assert.strictEqual('jpeg', withChromaSubsamplingInfo.format);
assert.strictEqual(320, withChromaSubsamplingInfo.width);
assert.strictEqual(240, withChromaSubsamplingInfo.height);
// Then generate without
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ chromaSubsampling: '4:4:4' })
.toBuffer(function (err, withoutChromaSubsamplingData, withoutChromaSubsamplingInfo) {
if (err) throw err;
assert.strictEqual(true, withoutChromaSubsamplingData.length > 0);
assert.strictEqual(withoutChromaSubsamplingData.length, withoutChromaSubsamplingInfo.size);
assert.strictEqual('jpeg', withoutChromaSubsamplingInfo.format);
assert.strictEqual(320, withoutChromaSubsamplingInfo.width);
assert.strictEqual(240, withoutChromaSubsamplingInfo.height);
assert.strictEqual(true, withChromaSubsamplingData.length < withoutChromaSubsamplingData.length);
done();
});
});
});
it('Invalid JPEG chromaSubsampling value throws error', function () {
assert.throws(function () {
sharp().jpeg({ chromaSubsampling: '4:2:2' });
});
});
it('Trellis quantisation', function (done) {
// First generate without
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ trellisQuantisation: false })
.toBuffer(function (err, withoutData, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withoutData.length > 0);
assert.strictEqual(withoutData.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Then generate with
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ trellisQuantization: true })
.toBuffer(function (err, withData, withInfo) {
if (err) throw err;
assert.strictEqual(true, withData.length > 0);
assert.strictEqual(withData.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
// Verify image is same (as mozjpeg may not be present) size or less
assert.strictEqual(true, withData.length <= withoutData.length);
done();
});
});
});
it('Overshoot deringing', function (done) {
// First generate without
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ overshootDeringing: false })
.toBuffer(function (err, withoutData, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withoutData.length > 0);
assert.strictEqual(withoutData.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Then generate with
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ overshootDeringing: true })
.toBuffer(function (err, withData, withInfo) {
if (err) throw err;
assert.strictEqual(true, withData.length > 0);
assert.strictEqual(withData.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
done();
});
});
});
it('Optimise scans generates different output length', function (done) {
// First generate without
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimiseScans: false })
.toBuffer(function (err, withoutData, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withoutData.length > 0);
assert.strictEqual(withoutData.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Then generate with
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimizeScans: true })
.toBuffer(function (err, withData, withInfo) {
if (err) throw err;
assert.strictEqual(true, withData.length > 0);
assert.strictEqual(withData.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
// Verify image is of a different size (progressive output even without mozjpeg)
assert.notStrictEqual(withData.length, withoutData.length);
done();
});
});
});
it('Optimise coding generates smaller output length', function (done) {
// First generate with optimize coding enabled (default)
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg()
.toBuffer(function (err, withOptimiseCoding, withInfo) {
if (err) throw err;
assert.strictEqual(true, withOptimiseCoding.length > 0);
assert.strictEqual(withOptimiseCoding.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
// Then generate with coding disabled
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimizeCoding: false })
.toBuffer(function (err, withoutOptimiseCoding, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withoutOptimiseCoding.length > 0);
assert.strictEqual(withoutOptimiseCoding.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Verify optimised image is of a smaller size
assert.strictEqual(true, withOptimiseCoding.length < withoutOptimiseCoding.length);
done();
});
});
});
it('Specifying quantisation table provides different JPEG', function (done) {
// First generate with default quantisation table
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimiseCoding: false })
.toBuffer(function (err, withDefaultQuantisationTable, withInfo) {
if (err) throw err;
assert.strictEqual(true, withDefaultQuantisationTable.length > 0);
assert.strictEqual(withDefaultQuantisationTable.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
// Then generate with different quantisation table
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimiseCoding: false, quantisationTable: 3 })
.toBuffer(function (err, withQuantTable3, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withQuantTable3.length > 0);
assert.strictEqual(withQuantTable3.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Verify image is same (as mozjpeg may not be present) size or less
assert.strictEqual(true, withQuantTable3.length <= withDefaultQuantisationTable.length);
done();
});
});
});
it('Convert SVG to PNG at default 72DPI', function (done) {
sharp(fixtures.inputSvg)
.resize(1024)
.extract({ left: 290, top: 760, width: 40, height: 40 })
.toFormat('png')
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('png', info.format);
assert.strictEqual(40, info.width);
assert.strictEqual(40, info.height);
fixtures.assertSimilar(fixtures.expected('svg72.png'), data, function (err) {
if (err) throw err;
sharp(data).metadata(function (err, info) {
if (err) throw err;
assert.strictEqual(72, info.density);
done();
});
});
});
});
it('Convert SVG to PNG at 1200DPI', function (done) {
sharp(fixtures.inputSvg, { density: 1200 })
.resize(1024)
.extract({ left: 290, top: 760, width: 40, height: 40 })
.toFormat('png')
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('png', info.format);
assert.strictEqual(40, info.width);
assert.strictEqual(40, info.height);
fixtures.assertSimilar(fixtures.expected('svg1200.png'), data, function (err) {
if (err) throw err;
sharp(data).metadata(function (err, info) {
if (err) throw err;
assert.strictEqual(1200, info.density);
done();
});
});
});
});
it('Convert SVG to PNG at 14.4DPI', function (done) {
sharp(fixtures.inputSvg, { density: 14.4 })
.toFormat('png')
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('png', info.format);
assert.strictEqual(20, info.width);
assert.strictEqual(20, info.height);
fixtures.assertSimilar(fixtures.expected('svg14.4.png'), data, function (err) {
if (err) throw err;
done();
});
});
});
it('Convert SVG with embedded images to PNG, respecting dimensions, autoconvert to PNG', function (done) {
sharp(fixtures.inputSvgWithEmbeddedImages)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('png', info.format);
assert.strictEqual(480, info.width);
assert.strictEqual(360, info.height);
assert.strictEqual(4, info.channels);
fixtures.assertSimilar(fixtures.expected('svg-embedded.png'), data, done);
});
});
it('Load TIFF from Buffer', function (done) {
const inputTiffBuffer = fs.readFileSync(fixtures.inputTiff);
sharp(inputTiffBuffer)
.resize(320, 240)
.jpeg()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual(data.length, info.size);
assert.strictEqual('jpeg', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
done();
});
});
it('Load multi-page TIFF\'s from file', function (done) {
sharp(fixtures.inputTiffMultipage) // defaults to page 0
.jpeg()
.toBuffer(function (err, defaultData, defaultInfo) {
if (err) throw err;
assert.strictEqual(true, defaultData.length > 0);
assert.strictEqual(defaultData.length, defaultInfo.size);
assert.strictEqual('jpeg', defaultInfo.format);
sharp(fixtures.inputTiffMultipage, { page: 1 }) // 50%-scale copy of page 0
.jpeg()
.toBuffer(function (err, scaledData, scaledInfo) {
if (err) throw err;
assert.strictEqual(true, scaledData.length > 0);
assert.strictEqual(scaledData.length, scaledInfo.size);
assert.strictEqual('jpeg', scaledInfo.format);
assert.strictEqual(defaultInfo.width, scaledInfo.width * 2);
assert.strictEqual(defaultInfo.height, scaledInfo.height * 2);
done();
});
});
});
it('Load multi-page TIFF\'s from Buffer', function (done) {
const inputTiffBuffer = fs.readFileSync(fixtures.inputTiffMultipage);
sharp(inputTiffBuffer) // defaults to page 0
.jpeg()
.toBuffer(function (err, defaultData, defaultInfo) {
if (err) throw err;
assert.strictEqual(true, defaultData.length > 0);
assert.strictEqual(defaultData.length, defaultInfo.size);
assert.strictEqual('jpeg', defaultInfo.format);
sharp(inputTiffBuffer, { page: 1 }) // 50%-scale copy of page 0
.jpeg()
.toBuffer(function (err, scaledData, scaledInfo) {
if (err) throw err;
assert.strictEqual(true, scaledData.length > 0);
assert.strictEqual(scaledData.length, scaledInfo.size);
assert.strictEqual('jpeg', scaledInfo.format);
assert.strictEqual(defaultInfo.width, scaledInfo.width * 2);
assert.strictEqual(defaultInfo.height, scaledInfo.height * 2);
done();
});
});
});
it('Save TIFF to Buffer', function (done) {
sharp(fixtures.inputTiff)
.resize(320, 240)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual(data.length, info.size);
assert.strictEqual('tiff', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
done();
});
});
it('Invalid WebP quality throws error', function () {
assert.throws(function () {
sharp().webp({ quality: 101 });
});
});
it('Invalid WebP alpha quality throws error', function () {
assert.throws(function () {
sharp().webp({ alphaQuality: 101 });
});
});
it('Invalid TIFF quality throws error', function () {
assert.throws(function () {
sharp().tiff({ quality: 101 });
});
});
it('Missing TIFF quality does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff();
});
});
it('Not squashing TIFF to a bit depth of 1 should not change the file size', function (done) {
const startSize = fs.statSync(fixtures.inputTiff8BitDepth).size;
sharp(fixtures.inputTiff8BitDepth)
.toColourspace('b-w') // can only squash 1 band uchar images
.tiff({
squash: false,
compression: 'none',
predictor: 'none'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size === startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('Squashing TIFF to a bit depth of 1 should significantly reduce file size', function (done) {
const startSize = fs.statSync(fixtures.inputTiff8BitDepth).size;
sharp(fixtures.inputTiff8BitDepth)
.toColourspace('b-w') // can only squash 1 band uchar images
.tiff({
squash: true,
compression: 'none',
predictor: 'none'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < (startSize / 2));
rimraf(fixtures.outputTiff, done);
});
});
it('Invalid TIFF squash value throws error', function () {
assert.throws(function () {
sharp().tiff({ squash: 'true' });
});
});
it('TIFF setting xres and yres on file', function (done) {
const res = 1000.0; // inputTiff has a dpi of 300 (res*2.54)
sharp(fixtures.inputTiff)
.tiff({
xres: (res),
yres: (res)
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
sharp(fixtures.outputTiff).metadata(function (err, metadata) {
if (err) throw err;
assert.strictEqual(metadata.density, res * 2.54); // convert to dpi
rimraf(fixtures.outputTiff, done);
});
});
});
it('TIFF setting xres and yres on buffer', function (done) {
const res = 1000.0; // inputTiff has a dpi of 300 (res*2.54)
sharp(fixtures.inputTiff)
.tiff({
xres: (res),
yres: (res)
})
.toBuffer(function (err, data, info) {
if (err) throw err;
sharp(data).metadata(function (err, metadata) {
if (err) throw err;
assert.strictEqual(metadata.density, res * 2.54); // convert to dpi
done();
});
});
});
it('TIFF invalid xres value should throw an error', function () {
assert.throws(function () {
sharp().tiff({ xres: '1000.0' });
});
});
it('TIFF invalid yres value should throw an error', function () {
assert.throws(function () {
sharp().tiff({ yres: '1000.0' });
});
});
it('TIFF lzw compression with horizontal predictor shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'lzw',
predictor: 'horizontal'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF ccittfax4 compression shrinks b-w test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiff).size;
sharp(fixtures.inputTiff)
.toColourspace('b-w')
.tiff({
squash: true,
compression: 'ccittfax4'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF deflate compression with horizontal predictor shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'deflate',
predictor: 'horizontal'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF deflate compression with float predictor shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'deflate',
predictor: 'float'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF deflate compression without predictor shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'deflate',
predictor: 'none'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF jpeg compression shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'jpeg'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF none compression does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ compression: 'none' });
});
});
it('TIFF lzw compression does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ compression: 'lzw' });
});
});
it('TIFF deflate compression does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ compression: 'deflate' });
});
});
it('TIFF invalid compression option throws', function () {
assert.throws(function () {
sharp().tiff({ compression: 0 });
});
});
it('TIFF invalid compression option throws', function () {
assert.throws(function () {
sharp().tiff({ compression: 'a' });
});
});
it('TIFF invalid predictor option throws', function () {
assert.throws(function () {
sharp().tiff({ predictor: 'a' });
});
});
it('TIFF horizontal predictor does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ predictor: 'horizontal' });
});
});
it('TIFF float predictor does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ predictor: 'float' });
});
});
it('TIFF none predictor does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ predictor: 'none' });
});
});
it('TIFF tiled pyramid image without compression enlarges test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'none',
pyramid: true,
tile: true,
tileHeight: 256,
tileWidth: 256
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size > startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF pyramid true value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ pyramid: true });
});
});
it('Invalid TIFF pyramid value throws error', function () {
assert.throws(function () {
sharp().tiff({ pyramid: 'true' });
});
});
it('Invalid TIFF tile value throws error', function () {
assert.throws(function () {
sharp().tiff({ tile: 'true' });
});
});
it('TIFF tile true value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ tile: true });
});
});
it('Valid TIFF tileHeight value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ tileHeight: 512 });
});
});
it('Valid TIFF tileWidth value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ tileWidth: 512 });
});
});
it('Invalid TIFF tileHeight value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileHeight: '256' });
});
});
it('Invalid TIFF tileWidth value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileWidth: '256' });
});
});
it('Invalid TIFF tileHeight value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileHeight: 0 });
});
});
it('Invalid TIFF tileWidth value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileWidth: 0 });
});
});
it('Input and output formats match when not forcing', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
@ -1392,53 +557,6 @@ describe('Input/output', function () {
});
});
describe('Ouput raw, uncompressed image data', function () {
it('1 channel greyscale image', function (done) {
sharp(fixtures.inputJpg)
.greyscale()
.resize(32, 24)
.raw()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(32 * 24 * 1, info.size);
assert.strictEqual(data.length, info.size);
assert.strictEqual('raw', info.format);
assert.strictEqual(32, info.width);
assert.strictEqual(24, info.height);
assert.strictEqual(1, info.channels);
done();
});
});
it('3 channel colour image without transparency', function (done) {
sharp(fixtures.inputJpg)
.resize(32, 24)
.toFormat('raw')
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(32 * 24 * 3, info.size);
assert.strictEqual(data.length, info.size);
assert.strictEqual('raw', info.format);
assert.strictEqual(32, info.width);
assert.strictEqual(24, info.height);
done();
});
});
it('4 channel colour image with transparency', function (done) {
sharp(fixtures.inputPngWithTransparency)
.resize(32, 24)
.toFormat(sharp.format.raw)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(32 * 24 * 4, info.size);
assert.strictEqual(data.length, info.size);
assert.strictEqual('raw', info.format);
assert.strictEqual(32, info.width);
assert.strictEqual(24, info.height);
done();
});
});
});
describe('Limit pixel count of input image', function () {
it('Invalid fails - negative', function (done) {
let isValid = false;
@ -1530,88 +648,6 @@ describe('Input/output', function () {
});
});
describe('Raw pixel input', function () {
it('Missing options', function () {
assert.throws(function () {
sharp({ raw: {} });
});
});
it('Incomplete options', function () {
assert.throws(function () {
sharp({ raw: { width: 1, height: 1 } });
});
});
it('Invalid channels', function () {
assert.throws(function () {
sharp({ raw: { width: 1, height: 1, channels: 5 } });
});
});
it('Invalid height', function () {
assert.throws(function () {
sharp({ raw: { width: 1, height: 0, channels: 4 } });
});
});
it('Invalid width', function () {
assert.throws(function () {
sharp({ raw: { width: 'zoinks', height: 1, channels: 4 } });
});
});
it('RGB', function (done) {
// Convert to raw pixel data
sharp(fixtures.inputJpg)
.resize(256)
.raw()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(256, info.width);
assert.strictEqual(209, info.height);
assert.strictEqual(3, info.channels);
// Convert back to JPEG
sharp(data, {
raw: {
width: info.width,
height: info.height,
channels: info.channels
} })
.jpeg()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(256, info.width);
assert.strictEqual(209, info.height);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(fixtures.inputJpg, data, done);
});
});
});
it('RGBA', function (done) {
// Convert to raw pixel data
sharp(fixtures.inputPngOverlayLayer1)
.resize(256)
.raw()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(256, info.width);
assert.strictEqual(192, info.height);
assert.strictEqual(4, info.channels);
// Convert back to PNG
sharp(data, {
raw: {
width: info.width,
height: info.height,
channels: info.channels
} })
.png()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(256, info.width);
assert.strictEqual(192, info.height);
assert.strictEqual(4, info.channels);
fixtures.assertSimilar(fixtures.inputPngOverlayLayer1, data, { threshold: 7 }, done);
});
});
});
});
describe('create new image', function () {
it('RGB', function (done) {
const create = {

262
test/unit/jpeg.js Normal file
View File

@ -0,0 +1,262 @@
'use strict';
const assert = require('assert');
const sharp = require('../../');
const fixtures = require('../fixtures');
describe('JPEG', function () {
it('JPEG quality', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ 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)
.jpeg({ quality: 90 })
.toBuffer(function (err, buffer90) {
if (err) throw err;
assert(buffer70.length < buffer80.length);
assert(buffer80.length < buffer90.length);
done();
});
});
});
});
describe('Invalid JPEG quality', function () {
[-1, 88.2, 'test'].forEach(function (quality) {
it(quality.toString(), function () {
assert.throws(function () {
sharp().jpeg({ quality: quality });
});
});
});
});
describe('Invalid JPEG quantisation table', function () {
[-1, 88.2, 'test'].forEach(function (table) {
it(table.toString(), function () {
assert.throws(function () {
sharp().jpeg({ quantisationTable: table });
});
});
});
});
it('Progressive JPEG image', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ progressive: false })
.toBuffer(function (err, nonProgressiveData, nonProgressiveInfo) {
if (err) throw err;
assert.strictEqual(true, nonProgressiveData.length > 0);
assert.strictEqual(nonProgressiveData.length, nonProgressiveInfo.size);
assert.strictEqual('jpeg', nonProgressiveInfo.format);
assert.strictEqual(320, nonProgressiveInfo.width);
assert.strictEqual(240, nonProgressiveInfo.height);
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ progressive: true })
.toBuffer(function (err, progressiveData, progressiveInfo) {
if (err) throw err;
assert.strictEqual(true, progressiveData.length > 0);
assert.strictEqual(progressiveData.length, progressiveInfo.size);
assert.strictEqual(false, progressiveData.length === nonProgressiveData.length);
assert.strictEqual('jpeg', progressiveInfo.format);
assert.strictEqual(320, progressiveInfo.width);
assert.strictEqual(240, progressiveInfo.height);
done();
});
});
});
it('Without chroma subsampling generates larger file', function (done) {
// First generate with chroma subsampling (default)
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ chromaSubsampling: '4:2:0' })
.toBuffer(function (err, withChromaSubsamplingData, withChromaSubsamplingInfo) {
if (err) throw err;
assert.strictEqual(true, withChromaSubsamplingData.length > 0);
assert.strictEqual(withChromaSubsamplingData.length, withChromaSubsamplingInfo.size);
assert.strictEqual('jpeg', withChromaSubsamplingInfo.format);
assert.strictEqual(320, withChromaSubsamplingInfo.width);
assert.strictEqual(240, withChromaSubsamplingInfo.height);
// Then generate without
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ chromaSubsampling: '4:4:4' })
.toBuffer(function (err, withoutChromaSubsamplingData, withoutChromaSubsamplingInfo) {
if (err) throw err;
assert.strictEqual(true, withoutChromaSubsamplingData.length > 0);
assert.strictEqual(withoutChromaSubsamplingData.length, withoutChromaSubsamplingInfo.size);
assert.strictEqual('jpeg', withoutChromaSubsamplingInfo.format);
assert.strictEqual(320, withoutChromaSubsamplingInfo.width);
assert.strictEqual(240, withoutChromaSubsamplingInfo.height);
assert.strictEqual(true, withChromaSubsamplingData.length < withoutChromaSubsamplingData.length);
done();
});
});
});
it('Invalid JPEG chromaSubsampling value throws error', function () {
assert.throws(function () {
sharp().jpeg({ chromaSubsampling: '4:2:2' });
});
});
it('Trellis quantisation', function (done) {
// First generate without
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ trellisQuantisation: false })
.toBuffer(function (err, withoutData, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withoutData.length > 0);
assert.strictEqual(withoutData.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Then generate with
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ trellisQuantization: true })
.toBuffer(function (err, withData, withInfo) {
if (err) throw err;
assert.strictEqual(true, withData.length > 0);
assert.strictEqual(withData.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
// Verify image is same (as mozjpeg may not be present) size or less
assert.strictEqual(true, withData.length <= withoutData.length);
done();
});
});
});
it('Overshoot deringing', function (done) {
// First generate without
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ overshootDeringing: false })
.toBuffer(function (err, withoutData, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withoutData.length > 0);
assert.strictEqual(withoutData.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Then generate with
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ overshootDeringing: true })
.toBuffer(function (err, withData, withInfo) {
if (err) throw err;
assert.strictEqual(true, withData.length > 0);
assert.strictEqual(withData.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
done();
});
});
});
it('Optimise scans generates different output length', function (done) {
// First generate without
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimiseScans: false })
.toBuffer(function (err, withoutData, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withoutData.length > 0);
assert.strictEqual(withoutData.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Then generate with
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimizeScans: true })
.toBuffer(function (err, withData, withInfo) {
if (err) throw err;
assert.strictEqual(true, withData.length > 0);
assert.strictEqual(withData.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
// Verify image is of a different size (progressive output even without mozjpeg)
assert.notStrictEqual(withData.length, withoutData.length);
done();
});
});
});
it('Optimise coding generates smaller output length', function (done) {
// First generate with optimize coding enabled (default)
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg()
.toBuffer(function (err, withOptimiseCoding, withInfo) {
if (err) throw err;
assert.strictEqual(true, withOptimiseCoding.length > 0);
assert.strictEqual(withOptimiseCoding.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
// Then generate with coding disabled
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimizeCoding: false })
.toBuffer(function (err, withoutOptimiseCoding, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withoutOptimiseCoding.length > 0);
assert.strictEqual(withoutOptimiseCoding.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Verify optimised image is of a smaller size
assert.strictEqual(true, withOptimiseCoding.length < withoutOptimiseCoding.length);
done();
});
});
});
it('Specifying quantisation table provides different JPEG', function (done) {
// First generate with default quantisation table
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimiseCoding: false })
.toBuffer(function (err, withDefaultQuantisationTable, withInfo) {
if (err) throw err;
assert.strictEqual(true, withDefaultQuantisationTable.length > 0);
assert.strictEqual(withDefaultQuantisationTable.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
// Then generate with different quantisation table
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimiseCoding: false, quantisationTable: 3 })
.toBuffer(function (err, withQuantTable3, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withQuantTable3.length > 0);
assert.strictEqual(withQuantTable3.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Verify image is same (as mozjpeg may not be present) size or less
assert.strictEqual(true, withQuantTable3.length <= withDefaultQuantisationTable.length);
done();
});
});
});
});

View File

@ -6,7 +6,7 @@ const assert = require('assert');
const sharp = require('../../');
const fixtures = require('../fixtures');
describe('PNG output', function () {
describe('PNG', function () {
it('compression level is valid', function () {
assert.doesNotThrow(function () {
sharp().png({ compressionLevel: 0 });
@ -77,6 +77,32 @@ describe('PNG output', function () {
});
});
it('Progressive PNG image', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.png({ progressive: false })
.toBuffer(function (err, nonProgressiveData, nonProgressiveInfo) {
if (err) throw err;
assert.strictEqual(true, nonProgressiveData.length > 0);
assert.strictEqual(nonProgressiveData.length, nonProgressiveInfo.size);
assert.strictEqual('png', nonProgressiveInfo.format);
assert.strictEqual(320, nonProgressiveInfo.width);
assert.strictEqual(240, nonProgressiveInfo.height);
sharp(nonProgressiveData)
.png({ progressive: true })
.toBuffer(function (err, progressiveData, progressiveInfo) {
if (err) throw err;
assert.strictEqual(true, progressiveData.length > 0);
assert.strictEqual(progressiveData.length, progressiveInfo.size);
assert.strictEqual(true, progressiveData.length > nonProgressiveData.length);
assert.strictEqual('png', progressiveInfo.format);
assert.strictEqual(320, progressiveInfo.width);
assert.strictEqual(240, progressiveInfo.height);
done();
});
});
});
it('Valid PNG libimagequant palette value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().png({ palette: false });

145
test/unit/raw.js Normal file
View File

@ -0,0 +1,145 @@
'use strict';
const assert = require('assert');
const sharp = require('../../');
const fixtures = require('../fixtures');
describe('Raw pixel data', function () {
describe('Raw pixel input', function () {
it('Missing options', function () {
assert.throws(function () {
sharp({ raw: {} });
});
});
it('Incomplete options', function () {
assert.throws(function () {
sharp({ raw: { width: 1, height: 1 } });
});
});
it('Invalid channels', function () {
assert.throws(function () {
sharp({ raw: { width: 1, height: 1, channels: 5 } });
});
});
it('Invalid height', function () {
assert.throws(function () {
sharp({ raw: { width: 1, height: 0, channels: 4 } });
});
});
it('Invalid width', function () {
assert.throws(function () {
sharp({ raw: { width: 'zoinks', height: 1, channels: 4 } });
});
});
it('RGB', function (done) {
// Convert to raw pixel data
sharp(fixtures.inputJpg)
.resize(256)
.raw()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(256, info.width);
assert.strictEqual(209, info.height);
assert.strictEqual(3, info.channels);
// Convert back to JPEG
sharp(data, {
raw: {
width: info.width,
height: info.height,
channels: info.channels
} })
.jpeg()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(256, info.width);
assert.strictEqual(209, info.height);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(fixtures.inputJpg, data, done);
});
});
});
it('RGBA', function (done) {
// Convert to raw pixel data
sharp(fixtures.inputPngOverlayLayer1)
.resize(256)
.raw()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(256, info.width);
assert.strictEqual(192, info.height);
assert.strictEqual(4, info.channels);
// Convert back to PNG
sharp(data, {
raw: {
width: info.width,
height: info.height,
channels: info.channels
} })
.png()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(256, info.width);
assert.strictEqual(192, info.height);
assert.strictEqual(4, info.channels);
fixtures.assertSimilar(fixtures.inputPngOverlayLayer1, data, { threshold: 7 }, done);
});
});
});
});
describe('Ouput raw, uncompressed image data', function () {
it('1 channel greyscale image', function (done) {
sharp(fixtures.inputJpg)
.greyscale()
.resize(32, 24)
.raw()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(32 * 24 * 1, info.size);
assert.strictEqual(data.length, info.size);
assert.strictEqual('raw', info.format);
assert.strictEqual(32, info.width);
assert.strictEqual(24, info.height);
assert.strictEqual(1, info.channels);
done();
});
});
it('3 channel colour image without transparency', function (done) {
sharp(fixtures.inputJpg)
.resize(32, 24)
.toFormat('raw')
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(32 * 24 * 3, info.size);
assert.strictEqual(data.length, info.size);
assert.strictEqual('raw', info.format);
assert.strictEqual(32, info.width);
assert.strictEqual(24, info.height);
done();
});
});
it('4 channel colour image with transparency', function (done) {
sharp(fixtures.inputPngWithTransparency)
.resize(32, 24)
.toFormat(sharp.format.raw)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(32 * 24 * 4, info.size);
assert.strictEqual(data.length, info.size);
assert.strictEqual('raw', info.format);
assert.strictEqual(32, info.width);
assert.strictEqual(24, info.height);
done();
});
});
});
});

77
test/unit/svg.js Normal file
View File

@ -0,0 +1,77 @@
'use strict';
const assert = require('assert');
const sharp = require('../../');
const fixtures = require('../fixtures');
describe('SVG input', function () {
it('Convert SVG to PNG at default 72DPI', function (done) {
sharp(fixtures.inputSvg)
.resize(1024)
.extract({ left: 290, top: 760, width: 40, height: 40 })
.toFormat('png')
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('png', info.format);
assert.strictEqual(40, info.width);
assert.strictEqual(40, info.height);
fixtures.assertSimilar(fixtures.expected('svg72.png'), data, function (err) {
if (err) throw err;
sharp(data).metadata(function (err, info) {
if (err) throw err;
assert.strictEqual(72, info.density);
done();
});
});
});
});
it('Convert SVG to PNG at 1200DPI', function (done) {
sharp(fixtures.inputSvg, { density: 1200 })
.resize(1024)
.extract({ left: 290, top: 760, width: 40, height: 40 })
.toFormat('png')
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('png', info.format);
assert.strictEqual(40, info.width);
assert.strictEqual(40, info.height);
fixtures.assertSimilar(fixtures.expected('svg1200.png'), data, function (err) {
if (err) throw err;
sharp(data).metadata(function (err, info) {
if (err) throw err;
assert.strictEqual(1200, info.density);
done();
});
});
});
});
it('Convert SVG to PNG at 14.4DPI', function (done) {
sharp(fixtures.inputSvg, { density: 14.4 })
.toFormat('png')
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('png', info.format);
assert.strictEqual(20, info.width);
assert.strictEqual(20, info.height);
fixtures.assertSimilar(fixtures.expected('svg14.4.png'), data, function (err) {
if (err) throw err;
done();
});
});
});
it('Convert SVG with embedded images to PNG, respecting dimensions, autoconvert to PNG', function (done) {
sharp(fixtures.inputSvgWithEmbeddedImages)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('png', info.format);
assert.strictEqual(480, info.width);
assert.strictEqual(360, info.height);
assert.strictEqual(4, info.channels);
fixtures.assertSimilar(fixtures.expected('svg-embedded.png'), data, done);
});
});
});

424
test/unit/tiff.js Normal file
View File

@ -0,0 +1,424 @@
'use strict';
const fs = require('fs');
const assert = require('assert');
const rimraf = require('rimraf');
const sharp = require('../../');
const fixtures = require('../fixtures');
describe('TIFF', function () {
it('Load TIFF from Buffer', function (done) {
const inputTiffBuffer = fs.readFileSync(fixtures.inputTiff);
sharp(inputTiffBuffer)
.resize(320, 240)
.jpeg()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual(data.length, info.size);
assert.strictEqual('jpeg', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
done();
});
});
it('Load multi-page TIFF from file', function (done) {
sharp(fixtures.inputTiffMultipage) // defaults to page 0
.jpeg()
.toBuffer(function (err, defaultData, defaultInfo) {
if (err) throw err;
assert.strictEqual(true, defaultData.length > 0);
assert.strictEqual(defaultData.length, defaultInfo.size);
assert.strictEqual('jpeg', defaultInfo.format);
sharp(fixtures.inputTiffMultipage, { page: 1 }) // 50%-scale copy of page 0
.jpeg()
.toBuffer(function (err, scaledData, scaledInfo) {
if (err) throw err;
assert.strictEqual(true, scaledData.length > 0);
assert.strictEqual(scaledData.length, scaledInfo.size);
assert.strictEqual('jpeg', scaledInfo.format);
assert.strictEqual(defaultInfo.width, scaledInfo.width * 2);
assert.strictEqual(defaultInfo.height, scaledInfo.height * 2);
done();
});
});
});
it('Load multi-page TIFF from Buffer', function (done) {
const inputTiffBuffer = fs.readFileSync(fixtures.inputTiffMultipage);
sharp(inputTiffBuffer) // defaults to page 0
.jpeg()
.toBuffer(function (err, defaultData, defaultInfo) {
if (err) throw err;
assert.strictEqual(true, defaultData.length > 0);
assert.strictEqual(defaultData.length, defaultInfo.size);
assert.strictEqual('jpeg', defaultInfo.format);
sharp(inputTiffBuffer, { page: 1 }) // 50%-scale copy of page 0
.jpeg()
.toBuffer(function (err, scaledData, scaledInfo) {
if (err) throw err;
assert.strictEqual(true, scaledData.length > 0);
assert.strictEqual(scaledData.length, scaledInfo.size);
assert.strictEqual('jpeg', scaledInfo.format);
assert.strictEqual(defaultInfo.width, scaledInfo.width * 2);
assert.strictEqual(defaultInfo.height, scaledInfo.height * 2);
done();
});
});
});
it('Save TIFF to Buffer', function (done) {
sharp(fixtures.inputTiff)
.resize(320, 240)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual(data.length, info.size);
assert.strictEqual('tiff', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
done();
});
});
it('Invalid TIFF quality throws error', function () {
assert.throws(function () {
sharp().tiff({ quality: 101 });
});
});
it('Missing TIFF quality does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff();
});
});
it('Not squashing TIFF to a bit depth of 1 should not change the file size', function (done) {
const startSize = fs.statSync(fixtures.inputTiff8BitDepth).size;
sharp(fixtures.inputTiff8BitDepth)
.toColourspace('b-w') // can only squash 1 band uchar images
.tiff({
squash: false,
compression: 'none',
predictor: 'none'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size === startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('Squashing TIFF to a bit depth of 1 should significantly reduce file size', function (done) {
const startSize = fs.statSync(fixtures.inputTiff8BitDepth).size;
sharp(fixtures.inputTiff8BitDepth)
.toColourspace('b-w') // can only squash 1 band uchar images
.tiff({
squash: true,
compression: 'none',
predictor: 'none'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < (startSize / 2));
rimraf(fixtures.outputTiff, done);
});
});
it('Invalid TIFF squash value throws error', function () {
assert.throws(function () {
sharp().tiff({ squash: 'true' });
});
});
it('TIFF setting xres and yres on file', function (done) {
const res = 1000.0; // inputTiff has a dpi of 300 (res*2.54)
sharp(fixtures.inputTiff)
.tiff({
xres: (res),
yres: (res)
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
sharp(fixtures.outputTiff).metadata(function (err, metadata) {
if (err) throw err;
assert.strictEqual(metadata.density, res * 2.54); // convert to dpi
rimraf(fixtures.outputTiff, done);
});
});
});
it('TIFF setting xres and yres on buffer', function (done) {
const res = 1000.0; // inputTiff has a dpi of 300 (res*2.54)
sharp(fixtures.inputTiff)
.tiff({
xres: (res),
yres: (res)
})
.toBuffer(function (err, data, info) {
if (err) throw err;
sharp(data).metadata(function (err, metadata) {
if (err) throw err;
assert.strictEqual(metadata.density, res * 2.54); // convert to dpi
done();
});
});
});
it('TIFF invalid xres value should throw an error', function () {
assert.throws(function () {
sharp().tiff({ xres: '1000.0' });
});
});
it('TIFF invalid yres value should throw an error', function () {
assert.throws(function () {
sharp().tiff({ yres: '1000.0' });
});
});
it('TIFF lzw compression with horizontal predictor shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'lzw',
predictor: 'horizontal'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF ccittfax4 compression shrinks b-w test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiff).size;
sharp(fixtures.inputTiff)
.toColourspace('b-w')
.tiff({
squash: true,
compression: 'ccittfax4'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF deflate compression with horizontal predictor shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'deflate',
predictor: 'horizontal'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF deflate compression with float predictor shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'deflate',
predictor: 'float'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF deflate compression without predictor shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'deflate',
predictor: 'none'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF jpeg compression shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'jpeg'
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size < startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF none compression does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ compression: 'none' });
});
});
it('TIFF lzw compression does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ compression: 'lzw' });
});
});
it('TIFF deflate compression does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ compression: 'deflate' });
});
});
it('TIFF invalid compression option throws', function () {
assert.throws(function () {
sharp().tiff({ compression: 0 });
});
});
it('TIFF invalid compression option throws', function () {
assert.throws(function () {
sharp().tiff({ compression: 'a' });
});
});
it('TIFF invalid predictor option throws', function () {
assert.throws(function () {
sharp().tiff({ predictor: 'a' });
});
});
it('TIFF horizontal predictor does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ predictor: 'horizontal' });
});
});
it('TIFF float predictor does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ predictor: 'float' });
});
});
it('TIFF none predictor does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ predictor: 'none' });
});
});
it('TIFF tiled pyramid image without compression enlarges test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'none',
pyramid: true,
tile: true,
tileHeight: 256,
tileWidth: 256
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size > startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF pyramid true value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ pyramid: true });
});
});
it('Invalid TIFF pyramid value throws error', function () {
assert.throws(function () {
sharp().tiff({ pyramid: 'true' });
});
});
it('Invalid TIFF tile value throws error', function () {
assert.throws(function () {
sharp().tiff({ tile: 'true' });
});
});
it('TIFF tile true value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ tile: true });
});
});
it('Valid TIFF tileHeight value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ tileHeight: 512 });
});
});
it('Valid TIFF tileWidth value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ tileWidth: 512 });
});
});
it('Invalid TIFF tileHeight value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileHeight: '256' });
});
});
it('Invalid TIFF tileWidth value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileWidth: '256' });
});
});
it('Invalid TIFF tileHeight value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileHeight: 0 });
});
});
it('Invalid TIFF tileWidth value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileWidth: 0 });
});
});
it('TIFF file input with invalid page fails gracefully', function (done) {
sharp(fixtures.inputTiffMultipage, { page: 2 })
.toBuffer(function (err) {
assert.strictEqual(true, !!err);
done();
});
});
it('TIFF buffer input with invalid page fails gracefully', function (done) {
sharp(fs.readFileSync(fixtures.inputTiffMultipage), { page: 2 })
.toBuffer(function (err) {
assert.strictEqual(true, !!err);
done();
});
});
});

78
test/unit/webp.js Normal file
View File

@ -0,0 +1,78 @@
'use strict';
const assert = require('assert');
const sharp = require('../../');
const fixtures = require('../fixtures');
describe('WebP', function () {
it('WebP output', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.toFormat(sharp.format.webp)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual('webp', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
done();
});
});
it('Invalid WebP quality throws error', function () {
assert.throws(function () {
sharp().webp({ quality: 101 });
});
});
it('Invalid WebP alpha quality throws error', function () {
assert.throws(function () {
sharp().webp({ alphaQuality: 101 });
});
});
it('should work for webp alpha quality', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({ alphaQuality: 80 })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual('webp', info.format);
fixtures.assertSimilar(fixtures.expected('webp-alpha-80.webp'), data, done);
});
});
it('should work for webp lossless', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({ lossless: true })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual('webp', info.format);
fixtures.assertSimilar(fixtures.expected('webp-lossless.webp'), data, done);
});
});
it('should work for webp near-lossless', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({ nearLossless: true, quality: 50 })
.toBuffer(function (err50, data50, info50) {
if (err50) throw err50;
assert.strictEqual(true, data50.length > 0);
assert.strictEqual('webp', info50.format);
fixtures.assertSimilar(fixtures.expected('webp-near-lossless-50.webp'), data50, done);
});
});
it('should use near-lossless when both lossless and nearLossless are specified', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({ nearLossless: true, quality: 50, lossless: true })
.toBuffer(function (err50, data50, info50) {
if (err50) throw err50;
assert.strictEqual(true, data50.length > 0);
assert.strictEqual('webp', info50.format);
fixtures.assertSimilar(fixtures.expected('webp-near-lossless-50.webp'), data50, done);
});
});
});