mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Expose reoptimise palette option for GIF output
This commit is contained in:
parent
d247c02762
commit
6288c7bced
@ -321,10 +321,14 @@ Use these GIF options for the output image.
|
|||||||
|
|
||||||
The first entry in the palette is reserved for transparency.
|
The first entry in the palette is reserved for transparency.
|
||||||
|
|
||||||
|
The palette of the input image will be re-used if possible.
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
* `options` **[Object][6]?** output options
|
* `options` **[Object][6]?** output options
|
||||||
|
|
||||||
|
* `options.reoptimise` **[boolean][10]** always generate new palettes (slow), re-use existing by default (optional, default `false`)
|
||||||
|
* `options.reoptimize` **[boolean][10]** alternative spelling of `options.reoptimise` (optional, default `false`)
|
||||||
* `options.colours` **[number][12]** maximum number of palette entries, including transparency, between 2 and 256 (optional, default `256`)
|
* `options.colours` **[number][12]** maximum number of palette entries, including transparency, between 2 and 256 (optional, default `256`)
|
||||||
* `options.colors` **[number][12]** alternative spelling of `options.colours` (optional, default `256`)
|
* `options.colors` **[number][12]** alternative spelling of `options.colours` (optional, default `256`)
|
||||||
* `options.effort` **[number][12]** CPU effort, between 1 (fastest) and 10 (slowest) (optional, default `7`)
|
* `options.effort` **[number][12]** CPU effort, between 1 (fastest) and 10 (slowest) (optional, default `7`)
|
||||||
|
@ -8,6 +8,8 @@ Requires libvips v8.13.0
|
|||||||
|
|
||||||
* Drop support for Node.js 12, now requires Node.js >= 14.15.0.
|
* Drop support for Node.js 12, now requires Node.js >= 14.15.0.
|
||||||
|
|
||||||
|
* GIF output now re-uses input palette if possible. Use `reoptimise` option to generate a new palette.
|
||||||
|
|
||||||
* Add WebP `minSize` and `mixed` options for greater control over animation frames.
|
* Add WebP `minSize` and `mixed` options for greater control over animation frames.
|
||||||
|
|
||||||
* Use combined bounding box of alpha and non-alpha channels for `trim` operation.
|
* Use combined bounding box of alpha and non-alpha channels for `trim` operation.
|
||||||
|
@ -256,6 +256,7 @@ const Sharp = function (input, options) {
|
|||||||
gifBitdepth: 8,
|
gifBitdepth: 8,
|
||||||
gifEffort: 7,
|
gifEffort: 7,
|
||||||
gifDither: 1,
|
gifDither: 1,
|
||||||
|
gifReoptimise: false,
|
||||||
tiffQuality: 80,
|
tiffQuality: 80,
|
||||||
tiffCompression: 'jpeg',
|
tiffCompression: 'jpeg',
|
||||||
tiffPredictor: 'horizontal',
|
tiffPredictor: 'horizontal',
|
||||||
|
@ -524,6 +524,8 @@ function webp (options) {
|
|||||||
*
|
*
|
||||||
* The first entry in the palette is reserved for transparency.
|
* The first entry in the palette is reserved for transparency.
|
||||||
*
|
*
|
||||||
|
* The palette of the input image will be re-used if possible.
|
||||||
|
*
|
||||||
* @since 0.30.0
|
* @since 0.30.0
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@ -545,6 +547,8 @@ function webp (options) {
|
|||||||
* .toBuffer();
|
* .toBuffer();
|
||||||
*
|
*
|
||||||
* @param {Object} [options] - output options
|
* @param {Object} [options] - output options
|
||||||
|
* @param {boolean} [options.reoptimise=false] - always generate new palettes (slow), re-use existing by default
|
||||||
|
* @param {boolean} [options.reoptimize=false] - alternative spelling of `options.reoptimise`
|
||||||
* @param {number} [options.colours=256] - maximum number of palette entries, including transparency, between 2 and 256
|
* @param {number} [options.colours=256] - maximum number of palette entries, including transparency, between 2 and 256
|
||||||
* @param {number} [options.colors=256] - alternative spelling of `options.colours`
|
* @param {number} [options.colors=256] - alternative spelling of `options.colours`
|
||||||
* @param {number} [options.effort=7] - CPU effort, between 1 (fastest) and 10 (slowest)
|
* @param {number} [options.effort=7] - CPU effort, between 1 (fastest) and 10 (slowest)
|
||||||
@ -557,6 +561,11 @@ function webp (options) {
|
|||||||
*/
|
*/
|
||||||
function gif (options) {
|
function gif (options) {
|
||||||
if (is.object(options)) {
|
if (is.object(options)) {
|
||||||
|
if (is.defined(options.reoptimise)) {
|
||||||
|
this._setBooleanOption('gifReoptimise', options.reoptimise);
|
||||||
|
} else if (is.defined(options.reoptimize)) {
|
||||||
|
this._setBooleanOption('gifReoptimise', options.reoptimize);
|
||||||
|
}
|
||||||
const colours = options.colours || options.colors;
|
const colours = options.colours || options.colors;
|
||||||
if (is.defined(colours)) {
|
if (is.defined(colours)) {
|
||||||
if (is.integer(colours) && is.inRange(colours, 2, 256)) {
|
if (is.integer(colours) && is.inRange(colours, 2, 256)) {
|
||||||
|
@ -888,6 +888,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("strip", !baton->withMetadata)
|
->set("strip", !baton->withMetadata)
|
||||||
->set("bitdepth", baton->gifBitdepth)
|
->set("bitdepth", baton->gifBitdepth)
|
||||||
->set("effort", baton->gifEffort)
|
->set("effort", baton->gifEffort)
|
||||||
|
->set("reoptimise", baton->gifReoptimise)
|
||||||
->set("dither", baton->gifDither)));
|
->set("dither", baton->gifDither)));
|
||||||
baton->bufferOut = static_cast<char*>(area->data);
|
baton->bufferOut = static_cast<char*>(area->data);
|
||||||
baton->bufferOutLength = area->length;
|
baton->bufferOutLength = area->length;
|
||||||
@ -1053,6 +1054,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("strip", !baton->withMetadata)
|
->set("strip", !baton->withMetadata)
|
||||||
->set("bitdepth", baton->gifBitdepth)
|
->set("bitdepth", baton->gifBitdepth)
|
||||||
->set("effort", baton->gifEffort)
|
->set("effort", baton->gifEffort)
|
||||||
|
->set("reoptimise", baton->gifReoptimise)
|
||||||
->set("dither", baton->gifDither));
|
->set("dither", baton->gifDither));
|
||||||
baton->formatOut = "gif";
|
baton->formatOut = "gif";
|
||||||
} else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
|
} else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
|
||||||
@ -1537,6 +1539,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->gifBitdepth = sharp::AttrAsUint32(options, "gifBitdepth");
|
baton->gifBitdepth = sharp::AttrAsUint32(options, "gifBitdepth");
|
||||||
baton->gifEffort = sharp::AttrAsUint32(options, "gifEffort");
|
baton->gifEffort = sharp::AttrAsUint32(options, "gifEffort");
|
||||||
baton->gifDither = sharp::AttrAsDouble(options, "gifDither");
|
baton->gifDither = sharp::AttrAsDouble(options, "gifDither");
|
||||||
|
baton->gifReoptimise = sharp::AttrAsBool(options, "gifReoptimise");
|
||||||
baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
|
baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
|
||||||
baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid");
|
baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid");
|
||||||
baton->tiffBitdepth = sharp::AttrAsUint32(options, "tiffBitdepth");
|
baton->tiffBitdepth = sharp::AttrAsUint32(options, "tiffBitdepth");
|
||||||
|
@ -162,6 +162,7 @@ struct PipelineBaton {
|
|||||||
int gifBitdepth;
|
int gifBitdepth;
|
||||||
int gifEffort;
|
int gifEffort;
|
||||||
double gifDither;
|
double gifDither;
|
||||||
|
bool gifReoptimise;
|
||||||
int tiffQuality;
|
int tiffQuality;
|
||||||
VipsForeignTiffCompression tiffCompression;
|
VipsForeignTiffCompression tiffCompression;
|
||||||
VipsForeignTiffPredictor tiffPredictor;
|
VipsForeignTiffPredictor tiffPredictor;
|
||||||
@ -306,6 +307,10 @@ struct PipelineBaton {
|
|||||||
webpEffort(4),
|
webpEffort(4),
|
||||||
webpMinSize(false),
|
webpMinSize(false),
|
||||||
webpMixed(false),
|
webpMixed(false),
|
||||||
|
gifBitdepth(8),
|
||||||
|
gifEffort(7),
|
||||||
|
gifDither(1.0),
|
||||||
|
gifReoptimise(false),
|
||||||
tiffQuality(80),
|
tiffQuality(80),
|
||||||
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
|
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
|
||||||
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|
||||||
|
@ -80,6 +80,22 @@ describe('GIF input', () => {
|
|||||||
assert.strictEqual(true, reduced.length < original.length);
|
assert.strictEqual(true, reduced.length < original.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('valid optimise', () => {
|
||||||
|
assert.doesNotThrow(() => sharp().gif({ reoptimise: true }));
|
||||||
|
assert.doesNotThrow(() => sharp().gif({ reoptimize: true }));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('invalid reoptimise throws', () => {
|
||||||
|
assert.throws(
|
||||||
|
() => sharp().gif({ reoptimise: -1 }),
|
||||||
|
/Expected boolean for gifReoptimise but received -1 of type number/
|
||||||
|
);
|
||||||
|
assert.throws(
|
||||||
|
() => sharp().gif({ reoptimize: 'fail' }),
|
||||||
|
/Expected boolean for gifReoptimise but received fail of type string/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('invalid loop throws', () => {
|
it('invalid loop throws', () => {
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
sharp().gif({ loop: -1 });
|
sharp().gif({ loop: -1 });
|
||||||
|
Loading…
x
Reference in New Issue
Block a user