From 4beae0de7119c1a1348844291eca80075c298d98 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 18 Aug 2020 20:28:25 +0100 Subject: [PATCH] Add 'animated' constructor property as shortcut for 'pages' Provides easier-to-understand API when handling animated images --- docs/api-constructor.md | 6 ++++++ lib/constructor.js | 5 +++++ lib/input.js | 7 +++++++ lib/output.js | 1 + test/unit/io.js | 9 +++++++++ 5 files changed, 28 insertions(+) diff --git a/docs/api-constructor.md b/docs/api-constructor.md index c80da42c..28c9a1db 100644 --- a/docs/api-constructor.md +++ b/docs/api-constructor.md @@ -29,6 +29,7 @@ Implements the [stream.Duplex][1] class. - `options.pages` **[number][6]** number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages. (optional, default `1`) - `options.page` **[number][6]** page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. (optional, default `0`) - `options.level` **[number][6]** level to extract from a multi-level input (OpenSlide), zero based. (optional, default `0`) + - `options.animated` **[boolean][5]** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default `false`) - `options.raw` **[Object][4]?** describes raw pixel input image data. See `raw()` for pixel ordering. - `options.raw.width` **[number][6]?** - `options.raw.height` **[number][6]?** @@ -78,6 +79,11 @@ sharp({ .then( ... ); ``` +```javascript +// Convert an animated GIF to an animated WebP +await sharp('in.gif', { animated: true }).toFile('out.webp'); +``` + - Throws **[Error][8]** Invalid parameters Returns **[Sharp][9]** diff --git a/lib/constructor.js b/lib/constructor.js index d9cb63ec..ee941b74 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -86,6 +86,10 @@ const debuglog = util.debuglog('sharp'); * .toBuffer() * .then( ... ); * + * @example + * // Convert an animated GIF to an animated WebP + * await sharp('in.gif', { animated: true }).toFile('out.webp'); + * * @param {(Buffer|string)} [input] - if present, can be * a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or * a String containing the filesystem path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file. @@ -102,6 +106,7 @@ const debuglog = util.debuglog('sharp'); * @param {number} [options.pages=1] - number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages. * @param {number} [options.page=0] - page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. * @param {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based. + * @param {boolean} [options.animated=false] - Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). * @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering. * @param {number} [options.raw.width] * @param {number} [options.raw.height] diff --git a/lib/input.js b/lib/input.js index 9f2a3f2a..a3ca117e 100644 --- a/lib/input.js +++ b/lib/input.js @@ -99,6 +99,13 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { } } // Multi-page input (GIF, TIFF, PDF) + if (is.defined(inputOptions.animated)) { + if (is.bool(inputOptions.animated)) { + inputDescriptor.pages = inputOptions.animated ? -1 : 1; + } else { + throw is.invalidParameterError('animated', 'boolean', inputOptions.animated); + } + } if (is.defined(inputOptions.pages)) { if (is.integer(inputOptions.pages) && is.inRange(inputOptions.pages, -1, 100000)) { inputDescriptor.pages = inputOptions.pages; diff --git a/lib/output.js b/lib/output.js index 737a684b..047876f8 100644 --- a/lib/output.js +++ b/lib/output.js @@ -399,6 +399,7 @@ function webp (options) { * @returns {Sharp} * @throws {Error} Invalid options */ +/* istanbul ignore next */ function gif (options) { if (!this.constructor.format.magick.output.buffer) { throw new Error('The gif operation requires libvips to have been installed with support for ImageMagick'); diff --git a/test/unit/io.js b/test/unit/io.js index 41ff62d6..ad19964f 100644 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -649,6 +649,15 @@ describe('Input/output', function () { sharp({ density: 'zoinks' }); }, /Expected number between 1 and 2400 for density but received zoinks of type string/); }); + it('Setting animated property updates pages property', function () { + assert.strictEqual(sharp({ animated: false }).options.input.pages, 1); + assert.strictEqual(sharp({ animated: true }).options.input.pages, -1); + }); + it('Invalid animated property throws', function () { + assert.throws(function () { + sharp({ animated: -1 }); + }, /Expected boolean for animated but received -1 of type number/); + }); it('Invalid page property throws', function () { assert.throws(function () { sharp({ page: -1 });