mirror of
https://github.com/lovell/sharp.git
synced 2025-12-06 20:11:40 +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.
290 lines
8.4 KiB
JavaScript
290 lines
8.4 KiB
JavaScript
// Copyright 2013 Lovell Fuller and others.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
const assert = require('node:assert');
|
|
|
|
const sharp = require('../../');
|
|
const inRange = require('../../lib/is').inRange;
|
|
const fixtures = require('../fixtures');
|
|
|
|
describe('Trim borders', function () {
|
|
it('Skip shrink-on-load', function (done) {
|
|
const expected = fixtures.expected('alpha-layer-2-trim-resize.jpg');
|
|
sharp(fixtures.inputJpgOverlayLayer2)
|
|
.trim()
|
|
.resize({
|
|
width: 300,
|
|
fastShrinkOnLoad: false
|
|
})
|
|
.toBuffer(function (err, data, info) {
|
|
if (err) throw err;
|
|
assert.strictEqual('jpeg', info.format);
|
|
assert.strictEqual(300, info.width);
|
|
assert.strictEqual(true, inRange(info.trimOffsetLeft, -873, -870));
|
|
assert.strictEqual(-554, info.trimOffsetTop);
|
|
fixtures.assertSimilar(expected, data, done);
|
|
});
|
|
});
|
|
|
|
it('Single colour PNG where alpha channel provides the image', () =>
|
|
sharp(fixtures.inputPngImageInAlpha)
|
|
.trim()
|
|
.toBuffer({ resolveWithObject: true })
|
|
.then(({ data, info }) => {
|
|
assert.strictEqual(true, data.length > 0);
|
|
assert.strictEqual('png', info.format);
|
|
assert.strictEqual(916, info.width);
|
|
assert.strictEqual(137, info.height);
|
|
assert.strictEqual(4, info.channels);
|
|
assert.strictEqual(-6, info.trimOffsetLeft);
|
|
assert.strictEqual(-20, info.trimOffsetTop);
|
|
})
|
|
);
|
|
|
|
it('16-bit PNG with alpha channel', function (done) {
|
|
sharp(fixtures.inputPngWithTransparency16bit)
|
|
.resize(32, 32)
|
|
.trim({
|
|
threshold: 20
|
|
})
|
|
.toBuffer(function (err, data, info) {
|
|
if (err) throw err;
|
|
assert.strictEqual(true, data.length > 0);
|
|
assert.strictEqual('png', info.format);
|
|
assert.strictEqual(32, info.width);
|
|
assert.strictEqual(32, info.height);
|
|
assert.strictEqual(4, info.channels);
|
|
assert.strictEqual(-2, info.trimOffsetLeft);
|
|
assert.strictEqual(-2, info.trimOffsetTop);
|
|
fixtures.assertSimilar(fixtures.expected('trim-16bit-rgba.png'), data, done);
|
|
});
|
|
});
|
|
|
|
it('Attempt to trim 2x2 pixel image fails', function (done) {
|
|
sharp({
|
|
create: {
|
|
width: 2,
|
|
height: 2,
|
|
channels: 3,
|
|
background: 'red'
|
|
}
|
|
})
|
|
.trim()
|
|
.toBuffer()
|
|
.then(() => {
|
|
done(new Error('Expected an error'));
|
|
})
|
|
.catch(err => {
|
|
assert.strictEqual('Image to trim must be at least 3x3 pixels', err.message);
|
|
done();
|
|
})
|
|
.catch(done);
|
|
});
|
|
|
|
it('Should rotate before trim', () =>
|
|
sharp({
|
|
create: {
|
|
width: 20,
|
|
height: 30,
|
|
channels: 3,
|
|
background: 'white'
|
|
}
|
|
})
|
|
.rotate(30)
|
|
.png()
|
|
.toBuffer()
|
|
.then(rotated30 =>
|
|
sharp(rotated30)
|
|
.rotate(-30)
|
|
.trim({
|
|
threshold: 128
|
|
})
|
|
.toBuffer({ resolveWithObject: true })
|
|
.then(({ info }) => {
|
|
assert.strictEqual(20, info.width);
|
|
assert.strictEqual(31, info.height);
|
|
assert.strictEqual(-8, info.trimOffsetTop);
|
|
assert.strictEqual(-13, info.trimOffsetLeft);
|
|
})
|
|
)
|
|
);
|
|
|
|
it('Animated image rejects', () =>
|
|
assert.rejects(() => sharp(fixtures.inputGifAnimated, { animated: true })
|
|
.trim()
|
|
.toBuffer(),
|
|
/Trim is not supported for multi-page images/
|
|
)
|
|
);
|
|
|
|
it('Ensure trim uses bounding box of alpha and non-alpha channels', async () => {
|
|
const { info } = await sharp(fixtures.inputPngTrimIncludeAlpha)
|
|
.trim()
|
|
.toBuffer({ resolveWithObject: true });
|
|
|
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
|
assert.strictEqual(width, 179);
|
|
assert.strictEqual(height, 123);
|
|
assert.strictEqual(trimOffsetTop, -44);
|
|
assert.strictEqual(trimOffsetLeft, -13);
|
|
});
|
|
|
|
it('Ensure greyscale image can be trimmed', async () => {
|
|
const greyscale = await sharp({
|
|
create: {
|
|
width: 16,
|
|
height: 8,
|
|
channels: 3,
|
|
background: 'silver'
|
|
}
|
|
})
|
|
.extend({ left: 12, right: 24, background: 'gray' })
|
|
.toColourspace('b-w')
|
|
.png({ compressionLevel: 0 })
|
|
.toBuffer();
|
|
|
|
const { info } = await sharp(greyscale)
|
|
.trim()
|
|
.raw()
|
|
.toBuffer({ resolveWithObject: true });
|
|
|
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
|
assert.strictEqual(width, 16);
|
|
assert.strictEqual(height, 8);
|
|
assert.strictEqual(trimOffsetTop, 0);
|
|
assert.strictEqual(trimOffsetLeft, -12);
|
|
});
|
|
|
|
it('Ensure CMYK image can be trimmed', async () => {
|
|
const cmyk = await sharp({
|
|
create: {
|
|
width: 16,
|
|
height: 8,
|
|
channels: 3,
|
|
background: 'red'
|
|
}
|
|
})
|
|
.extend({ left: 12, right: 24, background: 'blue' })
|
|
.toColourspace('cmyk')
|
|
.jpeg()
|
|
.toBuffer();
|
|
|
|
const { info } = await sharp(cmyk)
|
|
.trim()
|
|
.raw()
|
|
.toBuffer({ resolveWithObject: true });
|
|
|
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
|
assert.strictEqual(width, 16);
|
|
assert.strictEqual(height, 8);
|
|
assert.strictEqual(trimOffsetTop, 0);
|
|
assert.strictEqual(trimOffsetLeft, -12);
|
|
});
|
|
|
|
it('Ensure trim of image with all pixels same is no-op', async () => {
|
|
const { info } = await sharp({
|
|
create: {
|
|
width: 5,
|
|
height: 5,
|
|
channels: 3,
|
|
background: 'red'
|
|
}
|
|
})
|
|
.trim()
|
|
.toBuffer({ resolveWithObject: true });
|
|
|
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
|
assert.strictEqual(width, 5);
|
|
assert.strictEqual(height, 5);
|
|
assert.strictEqual(trimOffsetTop, 0);
|
|
assert.strictEqual(trimOffsetLeft, 0);
|
|
});
|
|
|
|
it('Works with line-art', async () => {
|
|
const { info } = await sharp(fixtures.inputJpgOverlayLayer2)
|
|
.trim({ lineArt: true })
|
|
.toBuffer({ resolveWithObject: true });
|
|
|
|
assert.strictEqual(info.trimOffsetTop, -552);
|
|
});
|
|
|
|
describe('Invalid parameters', function () {
|
|
Object.entries({
|
|
'Invalid string': 'fail',
|
|
'Invalid background option': {
|
|
background: 'fail'
|
|
},
|
|
'Negative threshold option': {
|
|
threshold: -1
|
|
},
|
|
'Invalid lineArt': {
|
|
lineArt: 'fail'
|
|
}
|
|
}).forEach(function ([description, parameter]) {
|
|
it(description, function () {
|
|
assert.throws(function () {
|
|
sharp().trim(parameter);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Specific background colour', function () {
|
|
it('Doesn\'t trim at all', async () => {
|
|
const { info } = await sharp(fixtures.inputPngTrimSpecificColour)
|
|
.trim({
|
|
background: 'yellow'
|
|
})
|
|
.toBuffer({ resolveWithObject: true });
|
|
|
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
|
assert.strictEqual(width, 900);
|
|
assert.strictEqual(height, 600);
|
|
assert.strictEqual(trimOffsetTop, 0);
|
|
assert.strictEqual(trimOffsetLeft, 0);
|
|
});
|
|
|
|
it('Only trims the bottom', async () => {
|
|
const { info } = await sharp(fixtures.inputPngTrimSpecificColour)
|
|
.trim({
|
|
background: '#21468B'
|
|
})
|
|
.toBuffer({ resolveWithObject: true });
|
|
|
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
|
assert.strictEqual(width, 900);
|
|
assert.strictEqual(height, 401);
|
|
assert.strictEqual(trimOffsetTop, 0);
|
|
assert.strictEqual(trimOffsetLeft, 0);
|
|
});
|
|
|
|
it('Only trims the bottom, in 16-bit', async () => {
|
|
const { info } = await sharp(fixtures.inputPngTrimSpecificColour16bit)
|
|
.trim({
|
|
background: '#21468B'
|
|
})
|
|
.toBuffer({ resolveWithObject: true });
|
|
|
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
|
assert.strictEqual(width, 900);
|
|
assert.strictEqual(height, 401);
|
|
assert.strictEqual(trimOffsetTop, 0);
|
|
assert.strictEqual(trimOffsetLeft, 0);
|
|
});
|
|
|
|
it('Only trims the bottom, including alpha', async () => {
|
|
const { info } = await sharp(fixtures.inputPngTrimSpecificColourIncludeAlpha)
|
|
.trim({
|
|
background: '#21468B80'
|
|
})
|
|
.toBuffer({ resolveWithObject: true });
|
|
|
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
|
assert.strictEqual(width, 900);
|
|
assert.strictEqual(height, 401);
|
|
assert.strictEqual(trimOffsetTop, 0);
|
|
assert.strictEqual(trimOffsetLeft, 0);
|
|
});
|
|
});
|
|
});
|