mirror of
https://github.com/lovell/sharp.git
synced 2025-12-06 12:01:41 +01:00
Uses the recommended rules apart from complexity/useArrowFunction, which would affect about 1700 lines of code with little benefit right now. This is something that can be addressed over time.
539 lines
16 KiB
JavaScript
539 lines
16 KiB
JavaScript
// Copyright 2013 Lovell Fuller and others.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
const fs = require('node:fs');
|
|
const assert = require('node:assert');
|
|
|
|
const sharp = require('../../');
|
|
const fixtures = require('../fixtures');
|
|
|
|
const outputTiff = fixtures.path('output.tiff');
|
|
|
|
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('Increasing TIFF quality increases file size', () =>
|
|
sharp(fixtures.inputJpgWithLandscapeExif1)
|
|
.resize(320, 240)
|
|
.tiff({ quality: 40 })
|
|
.toBuffer()
|
|
.then(tiff40 => sharp(fixtures.inputJpgWithLandscapeExif1)
|
|
.resize(320, 240)
|
|
.tiff({ quality: 90 })
|
|
.toBuffer()
|
|
.then(tiff90 =>
|
|
assert.strictEqual(true, tiff40.length < tiff90.length)
|
|
)
|
|
)
|
|
);
|
|
|
|
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({
|
|
bitdepth: 8,
|
|
compression: 'none',
|
|
predictor: 'none'
|
|
})
|
|
.toFile(outputTiff, (err, info) => {
|
|
if (err) throw err;
|
|
assert.strictEqual('tiff', info.format);
|
|
assert.strictEqual(startSize, info.size);
|
|
fs.rm(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({
|
|
bitdepth: 1,
|
|
compression: 'none',
|
|
predictor: 'none'
|
|
})
|
|
.toFile(outputTiff, (err, info) => {
|
|
if (err) throw err;
|
|
assert.strictEqual('tiff', info.format);
|
|
assert(info.size < (startSize / 2));
|
|
fs.rm(outputTiff, done);
|
|
});
|
|
});
|
|
|
|
it('Invalid TIFF bitdepth value throws error', function () {
|
|
assert.throws(function () {
|
|
sharp().tiff({ bitdepth: 3 });
|
|
}, /Error: Expected 1, 2, 4 or 8 for bitdepth but received 3 of type number/);
|
|
});
|
|
|
|
it('TIFF setting xres and yres on file', () =>
|
|
sharp(fixtures.inputTiff)
|
|
.resize(8, 8)
|
|
.tiff({
|
|
xres: 1000,
|
|
yres: 1000
|
|
})
|
|
.toFile(outputTiff)
|
|
.then(() => sharp(outputTiff)
|
|
.metadata()
|
|
.then(({ density }) => {
|
|
assert.strictEqual(25400, density);
|
|
return fs.promises.rm(outputTiff);
|
|
})
|
|
)
|
|
);
|
|
|
|
it('TIFF setting xres and yres on buffer', () =>
|
|
sharp(fixtures.inputTiff)
|
|
.resize(8, 8)
|
|
.tiff({
|
|
xres: 1000,
|
|
yres: 1000
|
|
})
|
|
.toBuffer()
|
|
.then(data => sharp(data)
|
|
.metadata()
|
|
.then(({ density }) => {
|
|
assert.strictEqual(25400, density);
|
|
})
|
|
)
|
|
);
|
|
|
|
it('TIFF imputes xres and yres from withMetadataDensity if not explicitly provided', async () => {
|
|
const data = await sharp(fixtures.inputTiff)
|
|
.resize(8, 8)
|
|
.tiff()
|
|
.withMetadata({ density: 600 })
|
|
.toBuffer();
|
|
const { density } = await sharp(data).metadata();
|
|
assert.strictEqual(600, density);
|
|
});
|
|
|
|
it('TIFF uses xres and yres over withMetadataDensity if explicitly provided', async () => {
|
|
const data = await sharp(fixtures.inputTiff)
|
|
.resize(8, 8)
|
|
.tiff({ xres: 1000, yres: 1000 })
|
|
.withMetadata({ density: 600 })
|
|
.toBuffer();
|
|
const { density } = await sharp(data).metadata();
|
|
assert.strictEqual(25400, density);
|
|
});
|
|
|
|
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(outputTiff, (err, info) => {
|
|
if (err) throw err;
|
|
assert.strictEqual('tiff', info.format);
|
|
assert.strictEqual(3, info.channels);
|
|
assert(info.size < startSize);
|
|
fs.rm(outputTiff, done);
|
|
});
|
|
});
|
|
|
|
it('TIFF LZW RGBA toFile', () =>
|
|
sharp({
|
|
create: {
|
|
width: 1,
|
|
height: 1,
|
|
channels: 4,
|
|
background: 'red'
|
|
}
|
|
})
|
|
.tiff({
|
|
compression: 'lzw'
|
|
})
|
|
.toFile(outputTiff)
|
|
.then(info => {
|
|
assert.strictEqual(4, info.channels);
|
|
})
|
|
);
|
|
|
|
it('TIFF LZW RGBA toBuffer', () =>
|
|
sharp({
|
|
create: {
|
|
width: 1,
|
|
height: 1,
|
|
channels: 4,
|
|
background: 'red'
|
|
}
|
|
})
|
|
.tiff({
|
|
compression: 'lzw'
|
|
})
|
|
.toBuffer({ resolveWithObject: true })
|
|
.then(({ info }) => {
|
|
assert.strictEqual(4, info.channels);
|
|
})
|
|
);
|
|
|
|
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({
|
|
bitdepth: 1,
|
|
compression: 'ccittfax4'
|
|
})
|
|
.toFile(outputTiff, (err, info) => {
|
|
if (err) throw err;
|
|
assert.strictEqual('tiff', info.format);
|
|
assert(info.size < startSize);
|
|
fs.rm(outputTiff, done);
|
|
});
|
|
});
|
|
|
|
it('TIFF resolutionUnit of inch (default)', async () => {
|
|
const data = await sharp({ create: { width: 8, height: 8, channels: 3, background: 'red' } })
|
|
.tiff()
|
|
.toBuffer();
|
|
const { resolutionUnit } = await sharp(data).metadata();
|
|
assert.strictEqual(resolutionUnit, 'inch');
|
|
});
|
|
|
|
it('TIFF resolutionUnit of inch', async () => {
|
|
const data = await sharp({ create: { width: 8, height: 8, channels: 3, background: 'red' } })
|
|
.tiff({ resolutionUnit: 'inch' })
|
|
.toBuffer();
|
|
const { resolutionUnit } = await sharp(data).metadata();
|
|
assert.strictEqual(resolutionUnit, 'inch');
|
|
});
|
|
|
|
it('TIFF resolutionUnit of cm', async () => {
|
|
const data = await sharp({ create: { width: 8, height: 8, channels: 3, background: 'red' } })
|
|
.tiff({ resolutionUnit: 'cm' })
|
|
.toBuffer();
|
|
const { resolutionUnit } = await sharp(data).metadata();
|
|
assert.strictEqual(resolutionUnit, 'cm');
|
|
});
|
|
|
|
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(outputTiff, (err, info) => {
|
|
if (err) throw err;
|
|
assert.strictEqual('tiff', info.format);
|
|
assert(info.size < startSize);
|
|
fs.rm(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(outputTiff, (err, info) => {
|
|
if (err) throw err;
|
|
assert.strictEqual('tiff', info.format);
|
|
assert(startSize > info.size);
|
|
fs.rm(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(outputTiff, (err, info) => {
|
|
if (err) throw err;
|
|
assert.strictEqual('tiff', info.format);
|
|
assert(info.size < startSize);
|
|
fs.rm(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(outputTiff, (err, info) => {
|
|
if (err) throw err;
|
|
assert.strictEqual('tiff', info.format);
|
|
assert(info.size < startSize);
|
|
fs.rm(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 invalid resolutionUnit option throws', function () {
|
|
assert.throws(function () {
|
|
sharp().tiff({ resolutionUnit: 'none' });
|
|
});
|
|
});
|
|
|
|
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(outputTiff, (err, info) => {
|
|
if (err) throw err;
|
|
assert.strictEqual('tiff', info.format);
|
|
assert(info.size > startSize);
|
|
fs.rm(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('TIFF miniswhite true value does not throw error', function () {
|
|
assert.doesNotThrow(function () {
|
|
sharp().tiff({ miniswhite: true });
|
|
});
|
|
});
|
|
|
|
it('Invalid TIFF miniswhite value throws error', function () {
|
|
assert.throws(function () {
|
|
sharp().tiff({ miniswhite: '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();
|
|
});
|
|
});
|
|
});
|