mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Add mixed and minSize animation options for WebP output
This commit is contained in:
parent
1b84ccbbe9
commit
d247c02762
@ -291,6 +291,8 @@ Use these WebP options for output image.
|
||||
* `options.effort` **[number][12]** CPU effort, between 0 (fastest) and 6 (slowest) (optional, default `4`)
|
||||
* `options.loop` **[number][12]** number of animation iterations, use 0 for infinite animation (optional, default `0`)
|
||||
* `options.delay` **([number][12] | [Array][13]<[number][12]>)?** delay(s) between animation frames (in milliseconds)
|
||||
* `options.minSize` **[boolean][10]** prevent use of animation key frames to minimise file size (slow) (optional, default `false`)
|
||||
* `options.mixed` **[boolean][10]** allow mixture of lossy and lossless animation frames (slow) (optional, default `false`)
|
||||
* `options.force` **[boolean][10]** force WebP output, otherwise attempt to use input format (optional, default `true`)
|
||||
|
||||
### Examples
|
||||
|
@ -8,6 +8,8 @@ Requires libvips v8.13.0
|
||||
|
||||
* Drop support for Node.js 12, now requires Node.js >= 14.15.0.
|
||||
|
||||
* 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.
|
||||
[#2166](https://github.com/lovell/sharp/issues/2166)
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -251,6 +251,8 @@ const Sharp = function (input, options) {
|
||||
webpNearLossless: false,
|
||||
webpSmartSubsample: false,
|
||||
webpEffort: 4,
|
||||
webpMinSize: false,
|
||||
webpMixed: false,
|
||||
gifBitdepth: 8,
|
||||
gifEffort: 7,
|
||||
gifDither: 1,
|
||||
|
@ -469,6 +469,8 @@ function png (options) {
|
||||
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 6 (slowest)
|
||||
* @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation
|
||||
* @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
|
||||
* @param {boolean} [options.minSize=false] - prevent use of animation key frames to minimise file size (slow)
|
||||
* @param {boolean} [options.mixed=false] - allow mixture of lossy and lossless animation frames (slow)
|
||||
* @param {boolean} [options.force=true] - force WebP output, otherwise attempt to use input format
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid options
|
||||
@ -506,6 +508,12 @@ function webp (options) {
|
||||
throw is.invalidParameterError('effort', 'integer between 0 and 6', effort);
|
||||
}
|
||||
}
|
||||
if (is.defined(options.minSize)) {
|
||||
this._setBooleanOption('webpMinSize', options.minSize);
|
||||
}
|
||||
if (is.defined(options.mixed)) {
|
||||
this._setBooleanOption('webpMixed', options.mixed);
|
||||
}
|
||||
}
|
||||
trySetAnimationOptions(options, this.options);
|
||||
return this._updateFormatOut('webp', options);
|
||||
|
@ -872,6 +872,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
->set("near_lossless", baton->webpNearLossless)
|
||||
->set("smart_subsample", baton->webpSmartSubsample)
|
||||
->set("effort", baton->webpEffort)
|
||||
->set("min_size", baton->webpMinSize)
|
||||
->set("mixed", baton->webpMixed)
|
||||
->set("alpha_q", baton->webpAlphaQuality)));
|
||||
baton->bufferOut = static_cast<char*>(area->data);
|
||||
baton->bufferOutLength = area->length;
|
||||
@ -1039,6 +1041,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
->set("near_lossless", baton->webpNearLossless)
|
||||
->set("smart_subsample", baton->webpSmartSubsample)
|
||||
->set("effort", baton->webpEffort)
|
||||
->set("min_size", baton->webpMinSize)
|
||||
->set("mixed", baton->webpMixed)
|
||||
->set("alpha_q", baton->webpAlphaQuality));
|
||||
baton->formatOut = "webp";
|
||||
} else if (baton->formatOut == "gif" || (mightMatchInput && isGif) ||
|
||||
@ -1109,6 +1113,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
{"lossless", baton->webpLossless ? "TRUE" : "FALSE"},
|
||||
{"near_lossless", baton->webpNearLossless ? "TRUE" : "FALSE"},
|
||||
{"smart_subsample", baton->webpSmartSubsample ? "TRUE" : "FALSE"},
|
||||
{"min_size", baton->webpMinSize ? "TRUE" : "FALSE"},
|
||||
{"mixed", baton->webpMixed ? "TRUE" : "FALSE"},
|
||||
{"effort", std::to_string(baton->webpEffort)}
|
||||
};
|
||||
suffix = AssembleSuffixString(".webp", options);
|
||||
@ -1526,6 +1532,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
||||
baton->webpNearLossless = sharp::AttrAsBool(options, "webpNearLossless");
|
||||
baton->webpSmartSubsample = sharp::AttrAsBool(options, "webpSmartSubsample");
|
||||
baton->webpEffort = sharp::AttrAsUint32(options, "webpEffort");
|
||||
baton->webpMinSize = sharp::AttrAsBool(options, "webpMinSize");
|
||||
baton->webpMixed = sharp::AttrAsBool(options, "webpMixed");
|
||||
baton->gifBitdepth = sharp::AttrAsUint32(options, "gifBitdepth");
|
||||
baton->gifEffort = sharp::AttrAsUint32(options, "gifEffort");
|
||||
baton->gifDither = sharp::AttrAsDouble(options, "gifDither");
|
||||
|
@ -157,6 +157,8 @@ struct PipelineBaton {
|
||||
bool webpLossless;
|
||||
bool webpSmartSubsample;
|
||||
int webpEffort;
|
||||
bool webpMinSize;
|
||||
bool webpMixed;
|
||||
int gifBitdepth;
|
||||
int gifEffort;
|
||||
double gifDither;
|
||||
@ -302,6 +304,8 @@ struct PipelineBaton {
|
||||
webpLossless(false),
|
||||
webpSmartSubsample(false),
|
||||
webpEffort(4),
|
||||
webpMinSize(false),
|
||||
webpMixed(false),
|
||||
tiffQuality(80),
|
||||
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
|
||||
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|
||||
|
@ -139,6 +139,28 @@ describe('WebP', function () {
|
||||
assert.strictEqual(effort, 0);
|
||||
});
|
||||
|
||||
it('valid minSize', () => {
|
||||
assert.doesNotThrow(() => sharp().webp({ minSize: true }));
|
||||
});
|
||||
|
||||
it('invalid minSize throws', () => {
|
||||
assert.throws(
|
||||
() => sharp().webp({ minSize: 1 }),
|
||||
/Expected boolean for webpMinSize but received 1 of type number/
|
||||
);
|
||||
});
|
||||
|
||||
it('valid mixed', () => {
|
||||
assert.doesNotThrow(() => sharp().webp({ mixed: true }));
|
||||
});
|
||||
|
||||
it('invalid mixed throws', () => {
|
||||
assert.throws(
|
||||
() => sharp().webp({ mixed: 'fail' }),
|
||||
/Expected boolean for webpMixed but received fail of type string/
|
||||
);
|
||||
});
|
||||
|
||||
it('invalid loop throws', () => {
|
||||
assert.throws(() => {
|
||||
sharp().webp({ loop: -1 });
|
||||
|
Loading…
x
Reference in New Issue
Block a user