From db2af42ee7b68a44dcb55027a07a1e18797c8d3d Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 22 Sep 2018 14:52:08 +0100 Subject: [PATCH] File extend, extract and trim ops under 'resize' #1135 Should make them easier to find in the docs --- docs/api-operation.md | 110 ++++++---------------------------------- docs/api-resize.md | 82 ++++++++++++++++++++++++++++++ lib/operation.js | 111 ----------------------------------------- lib/resize.js | 113 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 208 insertions(+), 208 deletions(-) diff --git a/docs/api-operation.md b/docs/api-operation.md index ff4a478e..34391dc8 100644 --- a/docs/api-operation.md +++ b/docs/api-operation.md @@ -38,46 +38,6 @@ readableStream.pipe(pipeline); Returns **Sharp** -## extract - -Extract a region of the image. - -- Use `extract` before `resize` for pre-resize extraction. -- Use `extract` after `resize` for post-resize extraction. -- Use `extract` before and after for both. - -### Parameters - -- `options` **[Object][3]** - - `options.left` **[Number][1]** zero-indexed offset from left edge - - `options.top` **[Number][1]** zero-indexed offset from top edge - - `options.width` **[Number][1]** dimension of extracted image - - `options.height` **[Number][1]** dimension of extracted image - -### Examples - -```javascript -sharp(input) - .extract({ left: left, top: top, width: width, height: height }) - .toFile(output, function(err) { - // Extract a region of the input image, saving in the same format. - }); -``` - -```javascript -sharp(input) - .extract({ left: leftOffsetPre, top: topOffsetPre, width: widthPre, height: heightPre }) - .resize(width, height) - .extract({ left: leftOffsetPost, top: topOffsetPost, width: widthPost, height: heightPost }) - .toFile(output, function(err) { - // Extract a region, resize, then extract from the resized image - }); -``` - -- Throws **[Error][2]** Invalid parameters - -Returns **Sharp** - ## flip Flip the image about the vertical Y axis. This always occurs after rotation, if any. @@ -85,7 +45,7 @@ The use of `flip` implies the removal of the EXIF `Orientation` tag, if any. ### Parameters -- `flip` **[Boolean][4]** (optional, default `true`) +- `flip` **[Boolean][3]** (optional, default `true`) Returns **Sharp** @@ -96,7 +56,7 @@ The use of `flop` implies the removal of the EXIF `Orientation` tag, if any. ### Parameters -- `flop` **[Boolean][4]** (optional, default `true`) +- `flop` **[Boolean][3]** (optional, default `true`) Returns **Sharp** @@ -143,35 +103,6 @@ When a `sigma` is provided, performs a slower, more accurate Gaussian blur. - `sigma` **[Number][1]?** a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`. -- Throws **[Error][2]** Invalid parameters - -Returns **Sharp** - -## extend - -Extends/pads the edges of the image with the colour provided to the `background` method. -This operation will always occur after resizing and extraction, if any. - -### Parameters - -- `extend` **([Number][1] \| [Object][3])** single pixel count to add to all edges or an Object with per-edge counts - - `extend.top` **[Number][1]?** - - `extend.left` **[Number][1]?** - - `extend.bottom` **[Number][1]?** - - `extend.right` **[Number][1]?** - -### Examples - -```javascript -// Resize to 140 pixels wide, then add 10 transparent pixels -// to the top, left and right edges and 20 to the bottom edge -sharp(input) - .resize(140) - .background({r: 0, g: 0, b: 0, alpha: 0}) - .extend({top: 10, bottom: 20, left: 10, right: 10}) - ... -``` - - Throws **[Error][2]** Invalid parameters Returns **Sharp** @@ -182,20 +113,7 @@ Merge alpha transparency channel, if any, with `background`. ### Parameters -- `flatten` **[Boolean][4]** (optional, default `true`) - -Returns **Sharp** - -## trim - -Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel. - -### Parameters - -- `tolerance` **[Number][1]** value between 1 and 99 representing the percentage similarity. (optional, default `10`) - - -- Throws **[Error][2]** Invalid parameters +- `flatten` **[Boolean][3]** (optional, default `true`) Returns **Sharp** @@ -222,7 +140,7 @@ Produce the "negative" of the image. ### Parameters -- `negate` **[Boolean][4]** (optional, default `true`) +- `negate` **[Boolean][3]** (optional, default `true`) Returns **Sharp** @@ -232,7 +150,7 @@ Enhance output image contrast by stretching its luminance to cover the full dyna ### Parameters -- `normalise` **[Boolean][4]** (optional, default `true`) +- `normalise` **[Boolean][3]** (optional, default `true`) Returns **Sharp** @@ -242,7 +160,7 @@ Alternative spelling of normalise. ### Parameters -- `normalize` **[Boolean][4]** (optional, default `true`) +- `normalize` **[Boolean][3]** (optional, default `true`) Returns **Sharp** @@ -252,7 +170,7 @@ Convolve the image with the specified kernel. ### Parameters -- `kernel` **[Object][3]** +- `kernel` **[Object][4]** - `kernel.width` **[Number][1]** width of the kernel in pixels. - `kernel.height` **[Number][1]** width of the kernel in pixels. - `kernel.kernel` **[Array][5]<[Number][1]>** Array of length `width*height` containing the kernel values. @@ -286,9 +204,9 @@ Any pixel value greather than or equal to the threshold value will be set to 255 ### Parameters - `threshold` **[Number][1]** a value in the range 0-255 representing the level at which the threshold will be applied. (optional, default `128`) -- `options` **[Object][3]?** - - `options.greyscale` **[Boolean][4]** convert to single channel greyscale. (optional, default `true`) - - `options.grayscale` **[Boolean][4]** alternative spelling for greyscale. (optional, default `true`) +- `options` **[Object][4]?** + - `options.greyscale` **[Boolean][3]** convert to single channel greyscale. (optional, default `true`) + - `options.grayscale` **[Boolean][3]** alternative spelling for greyscale. (optional, default `true`) - Throws **[Error][2]** Invalid parameters @@ -306,8 +224,8 @@ the selected bitwise boolean `operation` between the corresponding pixels of the - `operand` **([Buffer][6] \| [String][7])** Buffer containing image data or String containing the path to an image file. - `operator` **[String][7]** one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively. -- `options` **[Object][3]?** - - `options.raw` **[Object][3]?** describes operand when using raw pixel data. +- `options` **[Object][4]?** + - `options.raw` **[Object][4]?** describes operand when using raw pixel data. - `options.raw.width` **[Number][1]?** - `options.raw.height` **[Number][1]?** - `options.raw.channels` **[Number][1]?** @@ -335,9 +253,9 @@ Returns **Sharp** [2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error -[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object +[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean -[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean +[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array diff --git a/docs/api-resize.md b/docs/api-resize.md index b2a979e0..242e9d52 100644 --- a/docs/api-resize.md +++ b/docs/api-resize.md @@ -163,6 +163,88 @@ The default behaviour _before_ function call is `false`, meaning the image will Returns **Sharp** +## extend + +Extends/pads the edges of the image with the colour provided to the `background` method. +This operation will always occur after resizing and extraction, if any. + +### Parameters + +- `extend` **([Number][4] \| [Object][5])** single pixel count to add to all edges or an Object with per-edge counts + - `extend.top` **[Number][4]?** + - `extend.left` **[Number][4]?** + - `extend.bottom` **[Number][4]?** + - `extend.right` **[Number][4]?** + +### Examples + +```javascript +// Resize to 140 pixels wide, then add 10 transparent pixels +// to the top, left and right edges and 20 to the bottom edge +sharp(input) + .resize(140) + .background({r: 0, g: 0, b: 0, alpha: 0}) + .extend({top: 10, bottom: 20, left: 10, right: 10}) + ... +``` + +- Throws **[Error][8]** Invalid parameters + +Returns **Sharp** + +## extract + +Extract a region of the image. + +- Use `extract` before `resize` for pre-resize extraction. +- Use `extract` after `resize` for post-resize extraction. +- Use `extract` before and after for both. + +### Parameters + +- `options` **[Object][5]** + - `options.left` **[Number][4]** zero-indexed offset from left edge + - `options.top` **[Number][4]** zero-indexed offset from top edge + - `options.width` **[Number][4]** dimension of extracted image + - `options.height` **[Number][4]** dimension of extracted image + +### Examples + +```javascript +sharp(input) + .extract({ left: left, top: top, width: width, height: height }) + .toFile(output, function(err) { + // Extract a region of the input image, saving in the same format. + }); +``` + +```javascript +sharp(input) + .extract({ left: leftOffsetPre, top: topOffsetPre, width: widthPre, height: heightPre }) + .resize(width, height) + .extract({ left: leftOffsetPost, top: topOffsetPost, width: widthPost, height: heightPost }) + .toFile(output, function(err) { + // Extract a region, resize, then extract from the resized image + }); +``` + +- Throws **[Error][8]** Invalid parameters + +Returns **Sharp** + +## trim + +Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel. + +### Parameters + +- `tolerance` **[Number][4]** value between 1 and 99 representing the percentage similarity. (optional, default `10`) + + +- Throws **[Error][8]** Invalid parameters + +Returns **Sharp** + [1]: http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation [2]: https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline diff --git a/lib/operation.js b/lib/operation.js index 710c2ac9..94ed74be 100644 --- a/lib/operation.js +++ b/lib/operation.js @@ -43,53 +43,6 @@ function rotate (angle) { return this; } -/** - * Extract a region of the image. - * - * - Use `extract` before `resize` for pre-resize extraction. - * - Use `extract` after `resize` for post-resize extraction. - * - Use `extract` before and after for both. - * - * @example - * sharp(input) - * .extract({ left: left, top: top, width: width, height: height }) - * .toFile(output, function(err) { - * // Extract a region of the input image, saving in the same format. - * }); - * @example - * sharp(input) - * .extract({ left: leftOffsetPre, top: topOffsetPre, width: widthPre, height: heightPre }) - * .resize(width, height) - * .extract({ left: leftOffsetPost, top: topOffsetPost, width: widthPost, height: heightPost }) - * .toFile(output, function(err) { - * // Extract a region, resize, then extract from the resized image - * }); - * - * @param {Object} options - * @param {Number} options.left - zero-indexed offset from left edge - * @param {Number} options.top - zero-indexed offset from top edge - * @param {Number} options.width - dimension of extracted image - * @param {Number} options.height - dimension of extracted image - * @returns {Sharp} - * @throws {Error} Invalid parameters - */ -function extract (options) { - const suffix = this.options.width === -1 && this.options.height === -1 ? 'Pre' : 'Post'; - ['left', 'top', 'width', 'height'].forEach(function (name) { - const value = options[name]; - if (is.integer(value) && value >= 0) { - this.options[name + (name === 'left' || name === 'top' ? 'Offset' : '') + suffix] = value; - } else { - throw new Error('Non-integer value for ' + name + ' of ' + value); - } - }, this); - // Ensure existing rotation occurs before pre-resize extraction - if (suffix === 'Pre' && ((this.options.angle % 360) !== 0 || this.options.useExifOrientation === true)) { - this.options.rotateBeforePreExtract = true; - } - return this; -} - /** * Flip the image about the vertical Y axis. This always occurs after rotation, if any. * The use of `flip` implies the removal of the EXIF `Orientation` tag, if any. @@ -200,50 +153,6 @@ function blur (sigma) { return this; } -/** - * Extends/pads the edges of the image with the colour provided to the `background` method. - * This operation will always occur after resizing and extraction, if any. - * - * @example - * // Resize to 140 pixels wide, then add 10 transparent pixels - * // to the top, left and right edges and 20 to the bottom edge - * sharp(input) - * .resize(140) - * .background({r: 0, g: 0, b: 0, alpha: 0}) - * .extend({top: 10, bottom: 20, left: 10, right: 10}) - * ... - * - * @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] - * @returns {Sharp} - * @throws {Error} Invalid parameters -*/ -function extend (extend) { - if (is.integer(extend) && extend > 0) { - this.options.extendTop = 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 { - throw new Error('Invalid edge extension ' + extend); - } - return this; -} - /** * Merge alpha transparency channel, if any, with `background`. * @param {Boolean} [flatten=true] @@ -254,23 +163,6 @@ function flatten (flatten) { return this; } -/** - * Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel. - * @param {Number} [tolerance=10] value between 1 and 99 representing the percentage similarity. - * @returns {Sharp} - * @throws {Error} Invalid parameters - */ -function trim (tolerance) { - if (!is.defined(tolerance)) { - this.options.trimTolerance = 10; - } else if (is.integer(tolerance) && is.inRange(tolerance, 1, 99)) { - this.options.trimTolerance = tolerance; - } else { - throw new Error('Invalid trim tolerance (1 to 99) ' + tolerance); - } - return this; -} - /** * Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma` * then increasing the encoding (brighten) post-resize at a factor of `gamma`. @@ -460,15 +352,12 @@ function linear (a, b) { module.exports = function (Sharp) { [ rotate, - extract, flip, flop, sharpen, median, blur, - extend, flatten, - trim, gamma, negate, normalise, diff --git a/lib/resize.js b/lib/resize.js index e4a8e2aa..1a4b3271 100644 --- a/lib/resize.js +++ b/lib/resize.js @@ -265,6 +265,114 @@ function withoutEnlargement (withoutEnlargement) { return this; } +/** + * Extends/pads the edges of the image with the colour provided to the `background` method. + * This operation will always occur after resizing and extraction, if any. + * + * @example + * // Resize to 140 pixels wide, then add 10 transparent pixels + * // to the top, left and right edges and 20 to the bottom edge + * sharp(input) + * .resize(140) + * .background({r: 0, g: 0, b: 0, alpha: 0}) + * .extend({top: 10, bottom: 20, left: 10, right: 10}) + * ... + * + * @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] + * @returns {Sharp} + * @throws {Error} Invalid parameters +*/ +function extend (extend) { + if (is.integer(extend) && extend > 0) { + this.options.extendTop = 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 { + throw new Error('Invalid edge extension ' + extend); + } + return this; +} + +/** + * Extract a region of the image. + * + * - Use `extract` before `resize` for pre-resize extraction. + * - Use `extract` after `resize` for post-resize extraction. + * - Use `extract` before and after for both. + * + * @example + * sharp(input) + * .extract({ left: left, top: top, width: width, height: height }) + * .toFile(output, function(err) { + * // Extract a region of the input image, saving in the same format. + * }); + * @example + * sharp(input) + * .extract({ left: leftOffsetPre, top: topOffsetPre, width: widthPre, height: heightPre }) + * .resize(width, height) + * .extract({ left: leftOffsetPost, top: topOffsetPost, width: widthPost, height: heightPost }) + * .toFile(output, function(err) { + * // Extract a region, resize, then extract from the resized image + * }); + * + * @param {Object} options + * @param {Number} options.left - zero-indexed offset from left edge + * @param {Number} options.top - zero-indexed offset from top edge + * @param {Number} options.width - dimension of extracted image + * @param {Number} options.height - dimension of extracted image + * @returns {Sharp} + * @throws {Error} Invalid parameters + */ +function extract (options) { + const suffix = this.options.width === -1 && this.options.height === -1 ? 'Pre' : 'Post'; + ['left', 'top', 'width', 'height'].forEach(function (name) { + const value = options[name]; + if (is.integer(value) && value >= 0) { + this.options[name + (name === 'left' || name === 'top' ? 'Offset' : '') + suffix] = value; + } else { + throw new Error('Non-integer value for ' + name + ' of ' + value); + } + }, this); + // Ensure existing rotation occurs before pre-resize extraction + if (suffix === 'Pre' && ((this.options.angle % 360) !== 0 || this.options.useExifOrientation === true)) { + this.options.rotateBeforePreExtract = true; + } + return this; +} + +/** + * Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel. + * @param {Number} [tolerance=10] value between 1 and 99 representing the percentage similarity. + * @returns {Sharp} + * @throws {Error} Invalid parameters + */ +function trim (tolerance) { + if (!is.defined(tolerance)) { + this.options.trimTolerance = 10; + } else if (is.integer(tolerance) && is.inRange(tolerance, 1, 99)) { + this.options.trimTolerance = tolerance; + } else { + throw new Error('Invalid trim tolerance (1 to 99) ' + tolerance); + } + return this; +} + /** * Decorate the Sharp prototype with resize-related functions. * @private @@ -277,7 +385,10 @@ module.exports = function (Sharp) { max, min, ignoreAspectRatio, - withoutEnlargement + withoutEnlargement, + extend, + extract, + trim ].forEach(function (f) { Sharp.prototype[f.name] = f; });