mirror of
https://github.com/lovell/sharp.git
synced 2025-12-06 03:51: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.
251 lines
8.5 KiB
JavaScript
251 lines
8.5 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');
|
|
|
|
describe('PNG', function () {
|
|
it('compression level is valid', function () {
|
|
assert.doesNotThrow(function () {
|
|
sharp().png({ compressionLevel: 0 });
|
|
});
|
|
});
|
|
|
|
it('compression level is invalid', function () {
|
|
assert.throws(function () {
|
|
sharp().png({ compressionLevel: -1 });
|
|
});
|
|
});
|
|
|
|
it('default compressionLevel generates smaller file than compressionLevel=0', function (done) {
|
|
// First generate with default compressionLevel
|
|
sharp(fixtures.inputPng)
|
|
.resize(320, 240)
|
|
.png()
|
|
.toBuffer(function (err, defaultData, defaultInfo) {
|
|
if (err) throw err;
|
|
assert.strictEqual(true, defaultData.length > 0);
|
|
assert.strictEqual('png', defaultInfo.format);
|
|
// Then generate with compressionLevel=6
|
|
sharp(fixtures.inputPng)
|
|
.resize(320, 240)
|
|
.png({ compressionLevel: 0 })
|
|
.toBuffer(function (err, largerData, largerInfo) {
|
|
if (err) throw err;
|
|
assert.strictEqual(true, largerData.length > 0);
|
|
assert.strictEqual('png', largerInfo.format);
|
|
assert.strictEqual(true, defaultData.length < largerData.length);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
it('without adaptiveFiltering generates smaller file', function (done) {
|
|
// First generate with adaptive filtering
|
|
sharp(fixtures.inputPng)
|
|
.resize(320, 240)
|
|
.png({ adaptiveFiltering: true })
|
|
.toBuffer(function (err, adaptiveData, adaptiveInfo) {
|
|
if (err) throw err;
|
|
assert.strictEqual(true, adaptiveData.length > 0);
|
|
assert.strictEqual(adaptiveData.length, adaptiveInfo.size);
|
|
assert.strictEqual('png', adaptiveInfo.format);
|
|
assert.strictEqual(320, adaptiveInfo.width);
|
|
assert.strictEqual(240, adaptiveInfo.height);
|
|
// Then generate without
|
|
sharp(fixtures.inputPng)
|
|
.resize(320, 240)
|
|
.png({ adaptiveFiltering: false })
|
|
.toBuffer(function (err, withoutAdaptiveData, withoutAdaptiveInfo) {
|
|
if (err) throw err;
|
|
assert.strictEqual(true, withoutAdaptiveData.length > 0);
|
|
assert.strictEqual(withoutAdaptiveData.length, withoutAdaptiveInfo.size);
|
|
assert.strictEqual('png', withoutAdaptiveInfo.format);
|
|
assert.strictEqual(320, withoutAdaptiveInfo.width);
|
|
assert.strictEqual(240, withoutAdaptiveInfo.height);
|
|
assert.strictEqual(true, withoutAdaptiveData.length < adaptiveData.length);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
it('Invalid PNG adaptiveFiltering value throws error', function () {
|
|
assert.throws(function () {
|
|
sharp().png({ adaptiveFiltering: 1 });
|
|
});
|
|
});
|
|
|
|
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('16-bit grey+alpha PNG identity transform', function () {
|
|
const actual = fixtures.path('output.16-bit-grey-alpha-identity.png');
|
|
return sharp(fixtures.inputPng16BitGreyAlpha)
|
|
.toFile(actual)
|
|
.then(function () {
|
|
fixtures.assertMaxColourDistance(actual, fixtures.expected('16-bit-grey-alpha-identity.png'));
|
|
});
|
|
});
|
|
|
|
it('16-bit grey+alpha PNG roundtrip', async () => {
|
|
const after = await sharp(fixtures.inputPng16BitGreyAlpha)
|
|
.toColourspace('grey16')
|
|
.toBuffer();
|
|
|
|
const [alphaMeanBefore, alphaMeanAfter] = (
|
|
await Promise.all([
|
|
sharp(fixtures.inputPng16BitGreyAlpha).stats(),
|
|
sharp(after).stats()
|
|
])
|
|
)
|
|
.map(stats => stats.channels[1].mean);
|
|
|
|
assert.strictEqual(alphaMeanAfter, alphaMeanBefore);
|
|
});
|
|
|
|
it('palette decode/encode roundtrip', async () => {
|
|
const data = await sharp(fixtures.inputPngPalette)
|
|
.png({ effort: 1, palette: true })
|
|
.toBuffer();
|
|
|
|
const { size, ...metadata } = await sharp(data).metadata();
|
|
void size;
|
|
assert.deepStrictEqual(metadata, {
|
|
autoOrient: {
|
|
height: 68,
|
|
width: 68
|
|
},
|
|
format: 'png',
|
|
width: 68,
|
|
height: 68,
|
|
space: 'srgb',
|
|
channels: 3,
|
|
density: 72,
|
|
depth: 'uchar',
|
|
isProgressive: false,
|
|
isPalette: true,
|
|
bitsPerSample: 8,
|
|
paletteBitDepth: 8,
|
|
hasProfile: false,
|
|
hasAlpha: false
|
|
});
|
|
});
|
|
|
|
it('Valid PNG libimagequant palette value does not throw error', function () {
|
|
assert.doesNotThrow(function () {
|
|
sharp().png({ palette: false });
|
|
});
|
|
});
|
|
|
|
it('Invalid PNG libimagequant palette value throws error', function () {
|
|
assert.throws(function () {
|
|
sharp().png({ palette: 'fail' });
|
|
});
|
|
});
|
|
|
|
it('Valid PNG libimagequant quality value produces image of same size or smaller', function () {
|
|
const inputPngBuffer = fs.readFileSync(fixtures.inputPng);
|
|
return Promise.all([
|
|
sharp(inputPngBuffer).resize(10).png({ effort: 1, quality: 80 }).toBuffer(),
|
|
sharp(inputPngBuffer).resize(10).png({ effort: 1, quality: 100 }).toBuffer()
|
|
]).then(function (data) {
|
|
assert.strictEqual(true, data[0].length <= data[1].length);
|
|
});
|
|
});
|
|
|
|
it('Invalid PNG libimagequant quality value throws error', function () {
|
|
assert.throws(function () {
|
|
sharp().png({ quality: 101 });
|
|
});
|
|
});
|
|
|
|
it('Invalid effort value throws error', () => {
|
|
assert.throws(() => {
|
|
sharp().png({ effort: 0.1 });
|
|
});
|
|
});
|
|
|
|
it('Valid PNG libimagequant colours value produces image of same size or smaller', function () {
|
|
const inputPngBuffer = fs.readFileSync(fixtures.inputPng);
|
|
return Promise.all([
|
|
sharp(inputPngBuffer).resize(10).png({ colours: 100 }).toBuffer(),
|
|
sharp(inputPngBuffer).resize(10).png({ colours: 200 }).toBuffer()
|
|
]).then(function (data) {
|
|
assert.strictEqual(true, data[0].length <= data[1].length);
|
|
});
|
|
});
|
|
|
|
it('Invalid PNG libimagequant colours value throws error', function () {
|
|
assert.throws(function () {
|
|
sharp().png({ colours: -1 });
|
|
});
|
|
});
|
|
|
|
it('Invalid PNG libimagequant colors value throws error', function () {
|
|
assert.throws(function () {
|
|
sharp().png({ colors: 0.1 });
|
|
});
|
|
});
|
|
|
|
it('Can set bitdepth of PNG without palette', async () => {
|
|
const data = await sharp({
|
|
create: {
|
|
width: 8, height: 8, channels: 3, background: 'red'
|
|
}
|
|
})
|
|
.toColourspace('b-w')
|
|
.png({ colours: 2, palette: false })
|
|
.toBuffer();
|
|
|
|
const { channels, isPalette, bitsPerSample, paletteBitDepth, size, space } = await sharp(data).metadata();
|
|
assert.strictEqual(channels, 1);
|
|
assert.strictEqual(isPalette, false);
|
|
assert.strictEqual(bitsPerSample, 1);
|
|
assert.strictEqual(paletteBitDepth, undefined);
|
|
assert.strictEqual(size, 89);
|
|
assert.strictEqual(space, 'b-w');
|
|
});
|
|
|
|
it('Valid PNG libimagequant dither value produces image of same size or smaller', function () {
|
|
const inputPngBuffer = fs.readFileSync(fixtures.inputPng);
|
|
return Promise.all([
|
|
sharp(inputPngBuffer).resize(10).png({ dither: 0.1 }).toBuffer(),
|
|
sharp(inputPngBuffer).resize(10).png({ dither: 0.9 }).toBuffer()
|
|
]).then(function (data) {
|
|
assert.strictEqual(true, data[0].length <= data[1].length);
|
|
});
|
|
});
|
|
|
|
it('Invalid PNG libimagequant dither value throws error', function () {
|
|
assert.throws(function () {
|
|
sharp().png({ dither: 'fail' });
|
|
});
|
|
});
|
|
});
|