From 6147491d9e003affdc079cf5ea247e4611c29729 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 25 Mar 2021 16:34:02 +0000 Subject: [PATCH] Extend: default missing edge props to zero #2578 --- docs/api-resize.md | 18 ++++++++++---- docs/changelog.md | 3 +++ lib/resize.js | 57 +++++++++++++++++++++++++++++++++------------ test/unit/extend.js | 35 +++++++++++++++++++++------- 4 files changed, 85 insertions(+), 28 deletions(-) diff --git a/docs/api-resize.md b/docs/api-resize.md index f2dbbaee..5fac17f0 100644 --- a/docs/api-resize.md +++ b/docs/api-resize.md @@ -137,10 +137,10 @@ This operation will always occur after resizing and extraction, if any. ### Parameters - `extend` **([number][8] \| [Object][9])** single pixel count to add to all edges or an Object with per-edge counts - - `extend.top` **[number][8]?** - - `extend.left` **[number][8]?** - - `extend.bottom` **[number][8]?** - - `extend.right` **[number][8]?** + - `extend.top` **[number][8]** (optional, default `0`) + - `extend.left` **[number][8]** (optional, default `0`) + - `extend.bottom` **[number][8]** (optional, default `0`) + - `extend.right` **[number][8]** (optional, default `0`) - `extend.background` **([String][10] \| [Object][9])** background colour, parsed by the [color][11] module, defaults to black without transparency. (optional, default `{r:0,g:0,b:0,alpha:1}`) ### Examples @@ -160,6 +160,16 @@ sharp(input) ... ``` +```javascript +// Add a row of 10 red pixels to the bottom +sharp(input) + .extend({ + bottom: 10, + background: 'red' + }) + ... +``` + - Throws **[Error][13]** Invalid parameters Returns **Sharp** diff --git a/docs/changelog.md b/docs/changelog.md index 5a04ea7e..58452fc7 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -16,6 +16,9 @@ Requires libvips v8.10.6 * Reduce concurrency on glibc-based Linux when using the default memory allocator to help prevent fragmentation. +* Default missing edge properties of extend operation to zero. + [#2578](https://github.com/lovell/sharp/issues/2578) + * Ensure composite does not clip top and left offsets. [#2594](https://github.com/lovell/sharp/pull/2594) [@SHG42](https://github.com/SHG42) diff --git a/lib/resize.js b/lib/resize.js index ac9eef3f..9843910f 100644 --- a/lib/resize.js +++ b/lib/resize.js @@ -302,11 +302,20 @@ function resize (width, height, options) { * }) * ... * +* @example + * // Add a row of 10 red pixels to the bottom + * sharp(input) + * .extend({ + * bottom: 10, + * background: 'red' + * }) + * ... + * * @param {(number|Object)} extend - single pixel count to add to all edges or an Object with per-edge counts - * @param {number} [extend.top] - * @param {number} [extend.left] - * @param {number} [extend.bottom] - * @param {number} [extend.right] + * @param {number} [extend.top=0] + * @param {number} [extend.left=0] + * @param {number} [extend.bottom=0] + * @param {number} [extend.right=0] * @param {String|Object} [extend.background={r: 0, g: 0, b: 0, alpha: 1}] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black without transparency. * @returns {Sharp} * @throws {Error} Invalid parameters @@ -317,17 +326,35 @@ function extend (extend) { this.options.extendBottom = extend; this.options.extendLeft = extend; this.options.extendRight = extend; - } else if ( - is.object(extend) && - is.integer(extend.top) && extend.top >= 0 && - is.integer(extend.bottom) && extend.bottom >= 0 && - is.integer(extend.left) && extend.left >= 0 && - is.integer(extend.right) && extend.right >= 0 - ) { - this.options.extendTop = extend.top; - this.options.extendBottom = extend.bottom; - this.options.extendLeft = extend.left; - this.options.extendRight = extend.right; + } else if (is.object(extend)) { + if (is.defined(extend.top)) { + if (is.integer(extend.top) && extend.top >= 0) { + this.options.extendTop = extend.top; + } else { + throw is.invalidParameterError('top', 'positive integer', extend.top); + } + } + if (is.defined(extend.bottom)) { + if (is.integer(extend.bottom) && extend.bottom >= 0) { + this.options.extendBottom = extend.bottom; + } else { + throw is.invalidParameterError('bottom', 'positive integer', extend.bottom); + } + } + if (is.defined(extend.left)) { + if (is.integer(extend.left) && extend.left >= 0) { + this.options.extendLeft = extend.left; + } else { + throw is.invalidParameterError('left', 'positive integer', extend.left); + } + } + if (is.defined(extend.right)) { + if (is.integer(extend.right) && extend.right >= 0) { + this.options.extendRight = extend.right; + } else { + throw is.invalidParameterError('right', 'positive integer', extend.right); + } + } this._setBackgroundColourOption('extendBackground', extend.background); } else { throw is.invalidParameterError('extend', 'integer or object', extend); diff --git a/test/unit/extend.js b/test/unit/extend.js index fae8be87..8ab6d907 100644 --- a/test/unit/extend.js +++ b/test/unit/extend.js @@ -41,7 +41,6 @@ describe('Extend', function () { .resize(120) .extend({ top: 50, - bottom: 0, left: 10, right: 35, background: { r: 0, g: 0, b: 0, alpha: 0 } @@ -64,18 +63,38 @@ describe('Extend', function () { sharp().extend(-1); }); }); - it('partial object fails', function () { - assert.throws(function () { - sharp().extend({ top: 1 }); - }); + it('invalid top fails', () => { + assert.throws( + () => sharp().extend({ top: 'fail' }), + /Expected positive integer for top but received fail of type string/ + ); + }); + it('invalid bottom fails', () => { + assert.throws( + () => sharp().extend({ bottom: -1 }), + /Expected positive integer for bottom but received -1 of type number/ + ); + }); + it('invalid left fails', () => { + assert.throws( + () => sharp().extend({ left: 0.1 }), + /Expected positive integer for left but received 0.1 of type number/ + ); + }); + it('invalid right fails', () => { + assert.throws( + () => sharp().extend({ right: {} }), + /Expected positive integer for right but received \[object Object\] of type object/ + ); + }); + it('can set all edges apart from right', () => { + assert.doesNotThrow(() => sharp().extend({ top: 1, left: 2, bottom: 3 })); }); it('should add alpha channel before extending with a transparent Background', function (done) { sharp(fixtures.inputJpgWithLandscapeExif1) .extend({ - top: 0, bottom: 10, - left: 0, right: 10, background: { r: 0, g: 0, b: 0, alpha: 0 } }) @@ -91,9 +110,7 @@ describe('Extend', function () { it('PNG with 2 channels', function (done) { sharp(fixtures.inputPngWithGreyAlpha) .extend({ - top: 0, bottom: 20, - left: 0, right: 20, background: 'transparent' })