sharp 0.31.3 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  const Sharp = require('./constructor');
package/lib/input.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  const color = require('color');
@@ -21,9 +24,9 @@ const align = {
21
24
  * @private
22
25
  */
23
26
  function _inputOptionsFromObject (obj) {
24
- const { raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd } = obj;
25
- return [raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd].some(is.defined)
26
- ? { raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd }
27
+ const { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd } = obj;
28
+ return [raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd].some(is.defined)
29
+ ? { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd }
27
30
  : undefined;
28
31
  }
29
32
 
@@ -35,8 +38,9 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
35
38
  const inputDescriptor = {
36
39
  failOn: 'warning',
37
40
  limitInputPixels: Math.pow(0x3FFF, 2),
41
+ ignoreIcc: false,
38
42
  unlimited: false,
39
- sequentialRead: false
43
+ sequentialRead: true
40
44
  };
41
45
  if (is.string(input)) {
42
46
  // filesystem
@@ -47,6 +51,11 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
47
51
  throw Error('Input Buffer is empty');
48
52
  }
49
53
  inputDescriptor.buffer = input;
54
+ } else if (is.arrayBuffer(input)) {
55
+ if (input.byteLength === 0) {
56
+ throw Error('Input bit Array is empty');
57
+ }
58
+ inputDescriptor.buffer = Buffer.from(input, 0, input.byteLength);
50
59
  } else if (is.typedArray(input)) {
51
60
  if (input.length === 0) {
52
61
  throw Error('Input Bit Array is empty');
@@ -92,6 +101,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
92
101
  throw is.invalidParameterError('density', 'number between 1 and 100000', inputOptions.density);
93
102
  }
94
103
  }
104
+ // Ignore embeddded ICC profile
105
+ if (is.defined(inputOptions.ignoreIcc)) {
106
+ if (is.bool(inputOptions.ignoreIcc)) {
107
+ inputDescriptor.ignoreIcc = inputOptions.ignoreIcc;
108
+ } else {
109
+ throw is.invalidParameterError('ignoreIcc', 'boolean', inputOptions.ignoreIcc);
110
+ }
111
+ }
95
112
  // limitInputPixels
96
113
  if (is.defined(inputOptions.limitInputPixels)) {
97
114
  if (is.bool(inputOptions.limitInputPixels)) {
@@ -327,6 +344,13 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
327
344
  throw is.invalidParameterError('text.spacing', 'number', inputOptions.text.spacing);
328
345
  }
329
346
  }
347
+ if (is.defined(inputOptions.text.wrap)) {
348
+ if (is.string(inputOptions.text.wrap) && is.inArray(inputOptions.text.wrap, ['word', 'char', 'wordChar', 'none'])) {
349
+ inputDescriptor.textWrap = inputOptions.text.wrap;
350
+ } else {
351
+ throw is.invalidParameterError('text.wrap', 'one of: word, char, wordChar, none', inputOptions.text.wrap);
352
+ }
353
+ }
330
354
  delete inputDescriptor.buffer;
331
355
  } else {
332
356
  throw new Error('Expected a valid string to create an image with text.');
@@ -387,8 +411,9 @@ function _isStreamInput () {
387
411
  /**
388
412
  * Fast access to (uncached) image metadata without decoding any compressed pixel data.
389
413
  *
390
- * This is taken from the header of the input image.
391
- * It does not include operations, such as resize, to be applied to the output image.
414
+ * This is read from the header of the input image.
415
+ * It does not take into consideration any operations to be applied to the output image,
416
+ * such as resize or rotate.
392
417
  *
393
418
  * Dimensions in the response will respect the `page` and `pages` properties of the
394
419
  * {@link /api-constructor#parameters|constructor parameters}.
@@ -423,6 +448,7 @@ function _isStreamInput () {
423
448
  * - `iptc`: Buffer containing raw IPTC data, if present
424
449
  * - `xmp`: Buffer containing raw XMP data, if present
425
450
  * - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
451
+ * - `formatMagick`: String containing format for images loaded via *magick
426
452
  *
427
453
  * @example
428
454
  * const metadata = await sharp(input).metadata();
package/lib/is.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  /**
@@ -71,6 +74,14 @@ const typedArray = function (val) {
71
74
  return false;
72
75
  };
73
76
 
77
+ /**
78
+ * Is this value an ArrayBuffer object?
79
+ * @private
80
+ */
81
+ const arrayBuffer = function (val) {
82
+ return val instanceof ArrayBuffer;
83
+ };
84
+
74
85
  /**
75
86
  * Is this value a non-empty string?
76
87
  * @private
@@ -134,6 +145,7 @@ module.exports = {
134
145
  bool: bool,
135
146
  buffer: buffer,
136
147
  typedArray: typedArray,
148
+ arrayBuffer: arrayBuffer,
137
149
  string: string,
138
150
  number: number,
139
151
  integer: integer,
package/lib/libvips.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  const fs = require('fs');
@@ -115,6 +118,7 @@ const useGlobalLibvips = function () {
115
118
  }
116
119
  /* istanbul ignore next */
117
120
  if (isRosetta()) {
121
+ log('Detected Rosetta, skipping search for globally-installed libvips');
118
122
  return false;
119
123
  }
120
124
  const globalVipsVersion = globalLibvipsVersion();
package/lib/operation.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  const color = require('color');
@@ -232,7 +235,7 @@ function affine (matrix, options) {
232
235
  * .toBuffer();
233
236
  *
234
237
  * @param {Object|number} [options] - if present, is an Object with attributes
235
- * @param {number} [options.sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`, between 0.000001 and 10000
238
+ * @param {number} [options.sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`, between 0.000001 and 10
236
239
  * @param {number} [options.m1=1.0] - the level of sharpening to apply to "flat" areas, between 0 and 1000000
237
240
  * @param {number} [options.m2=2.0] - the level of sharpening to apply to "jagged" areas, between 0 and 1000000
238
241
  * @param {number} [options.x1=2.0] - threshold between "flat" and "jagged", between 0 and 1000000
@@ -270,10 +273,10 @@ function sharpen (options, flat, jagged) {
270
273
  }
271
274
  }
272
275
  } else if (is.plainObject(options)) {
273
- if (is.number(options.sigma) && is.inRange(options.sigma, 0.000001, 10000)) {
276
+ if (is.number(options.sigma) && is.inRange(options.sigma, 0.000001, 10)) {
274
277
  this.options.sharpenSigma = options.sigma;
275
278
  } else {
276
- throw is.invalidParameterError('options.sigma', 'number between 0.000001 and 10000', options.sigma);
279
+ throw is.invalidParameterError('options.sigma', 'number between 0.000001 and 10', options.sigma);
277
280
  }
278
281
  if (is.defined(options.m1)) {
279
282
  if (is.number(options.m1) && is.inRange(options.m1, 0, 1000000)) {
@@ -466,16 +469,50 @@ function negate (options) {
466
469
  }
467
470
 
468
471
  /**
469
- * Enhance output image contrast by stretching its luminance to cover the full dynamic range.
472
+ * Enhance output image contrast by stretching its luminance to cover a full dynamic range.
473
+ *
474
+ * Uses a histogram-based approach, taking a default range of 1% to 99% to reduce sensitivity to noise at the extremes.
475
+ *
476
+ * Luminance values below the `lower` percentile will be underexposed by clipping to zero.
477
+ * Luminance values above the `upper` percentile will be overexposed by clipping to the max pixel value.
470
478
  *
471
479
  * @example
472
- * const output = await sharp(input).normalise().toBuffer();
480
+ * const output = await sharp(input)
481
+ * .normalise()
482
+ * .toBuffer();
483
+ *
484
+ * @example
485
+ * const output = await sharp(input)
486
+ * .normalise({ lower: 0, upper: 100 })
487
+ * .toBuffer();
473
488
  *
474
- * @param {Boolean} [normalise=true]
489
+ * @param {Object} [options]
490
+ * @param {number} [options.lower=1] - Percentile below which luminance values will be underexposed.
491
+ * @param {number} [options.upper=99] - Percentile above which luminance values will be overexposed.
475
492
  * @returns {Sharp}
476
493
  */
477
- function normalise (normalise) {
478
- this.options.normalise = is.bool(normalise) ? normalise : true;
494
+ function normalise (options) {
495
+ if (is.plainObject(options)) {
496
+ if (is.defined(options.lower)) {
497
+ if (is.number(options.lower) && is.inRange(options.lower, 0, 99)) {
498
+ this.options.normaliseLower = options.lower;
499
+ } else {
500
+ throw is.invalidParameterError('lower', 'number between 0 and 99', options.lower);
501
+ }
502
+ }
503
+ if (is.defined(options.upper)) {
504
+ if (is.number(options.upper) && is.inRange(options.upper, 1, 100)) {
505
+ this.options.normaliseUpper = options.upper;
506
+ } else {
507
+ throw is.invalidParameterError('upper', 'number between 1 and 100', options.upper);
508
+ }
509
+ }
510
+ }
511
+ if (this.options.normaliseLower >= this.options.normaliseUpper) {
512
+ throw is.invalidParameterError('range', 'lower to be less than upper',
513
+ `${this.options.normaliseLower} >= ${this.options.normaliseUpper}`);
514
+ }
515
+ this.options.normalise = true;
479
516
  return this;
480
517
  }
481
518
 
@@ -483,13 +520,17 @@ function normalise (normalise) {
483
520
  * Alternative spelling of normalise.
484
521
  *
485
522
  * @example
486
- * const output = await sharp(input).normalize().toBuffer();
523
+ * const output = await sharp(input)
524
+ * .normalize()
525
+ * .toBuffer();
487
526
  *
488
- * @param {Boolean} [normalize=true]
527
+ * @param {Object} [options]
528
+ * @param {number} [options.lower=1] - Percentile below which luminance values will be underexposed.
529
+ * @param {number} [options.upper=99] - Percentile above which luminance values will be overexposed.
489
530
  * @returns {Sharp}
490
531
  */
491
- function normalize (normalize) {
492
- return this.normalise(normalize);
532
+ function normalize (options) {
533
+ return this.normalise(options);
493
534
  }
494
535
 
495
536
  /**
@@ -509,34 +550,33 @@ function normalize (normalize) {
509
550
  * .toBuffer();
510
551
  *
511
552
  * @param {Object} options
512
- * @param {number} options.width - integer width of the region in pixels.
513
- * @param {number} options.height - integer height of the region in pixels.
514
- * @param {number} [options.maxSlope=3] - maximum value for the slope of the
515
- * cumulative histogram. A value of 0 disables contrast limiting. Valid values
516
- * are integers in the range 0-100 (inclusive)
553
+ * @param {number} options.width - Integral width of the search window, in pixels.
554
+ * @param {number} options.height - Integral height of the search window, in pixels.
555
+ * @param {number} [options.maxSlope=3] - Integral level of brightening, between 0 and 100, where 0 disables contrast limiting.
517
556
  * @returns {Sharp}
518
557
  * @throws {Error} Invalid parameters
519
558
  */
520
559
  function clahe (options) {
521
- if (!is.plainObject(options)) {
522
- throw is.invalidParameterError('options', 'plain object', options);
523
- }
524
- if (!('width' in options) || !is.integer(options.width) || options.width <= 0) {
525
- throw is.invalidParameterError('width', 'integer above zero', options.width);
526
- } else {
527
- this.options.claheWidth = options.width;
528
- }
529
- if (!('height' in options) || !is.integer(options.height) || options.height <= 0) {
530
- throw is.invalidParameterError('height', 'integer above zero', options.height);
531
- } else {
532
- this.options.claheHeight = options.height;
533
- }
534
- if (!is.defined(options.maxSlope)) {
535
- this.options.claheMaxSlope = 3;
536
- } else if (!is.integer(options.maxSlope) || options.maxSlope < 0 || options.maxSlope > 100) {
537
- throw is.invalidParameterError('maxSlope', 'integer 0-100', options.maxSlope);
560
+ if (is.plainObject(options)) {
561
+ if (is.integer(options.width) && options.width > 0) {
562
+ this.options.claheWidth = options.width;
563
+ } else {
564
+ throw is.invalidParameterError('width', 'integer greater than zero', options.width);
565
+ }
566
+ if (is.integer(options.height) && options.height > 0) {
567
+ this.options.claheHeight = options.height;
568
+ } else {
569
+ throw is.invalidParameterError('height', 'integer greater than zero', options.height);
570
+ }
571
+ if (is.defined(options.maxSlope)) {
572
+ if (is.integer(options.maxSlope) && is.inRange(options.maxSlope, 0, 100)) {
573
+ this.options.claheMaxSlope = options.maxSlope;
574
+ } else {
575
+ throw is.invalidParameterError('maxSlope', 'integer between 0 and 100', options.maxSlope);
576
+ }
577
+ }
538
578
  } else {
539
- this.options.claheMaxSlope = options.maxSlope;
579
+ throw is.invalidParameterError('options', 'plain object', options);
540
580
  }
541
581
  return this;
542
582
  }
package/lib/output.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  const path = require('path');
@@ -61,6 +64,7 @@ const bitdepthFromColourCount = (colours) => 1 << 31 - Math.clz32(Math.ceil(Math
61
64
  * `info` contains the output image `format`, `size` (bytes), `width`, `height`,
62
65
  * `channels` and `premultiplied` (indicating if premultiplication was used).
63
66
  * When using a crop strategy also contains `cropOffsetLeft` and `cropOffsetTop`.
67
+ * When using the attention crop strategy also contains `attentionX` and `attentionY`, the focal point of the cropped region.
64
68
  * May also contain `textAutofitDpi` (dpi the font was rendered at) if image was created from text.
65
69
  * @returns {Promise<Object>} - when no callback is provided
66
70
  * @throws {Error} Invalid parameters
@@ -192,7 +196,7 @@ function toBuffer (options, callback) {
192
196
  *
193
197
  * @param {Object} [options]
194
198
  * @param {number} [options.orientation] value between 1 and 8, used to update the EXIF `Orientation` tag.
195
- * @param {string} [options.icc] filesystem path to output ICC profile, defaults to sRGB.
199
+ * @param {string} [options.icc='srgb'] Filesystem path to output ICC profile, relative to `process.cwd()`, defaults to built-in sRGB.
196
200
  * @param {Object<Object>} [options.exif={}] Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
197
201
  * @param {number} [options.density] Number of pixels per inch (DPI).
198
202
  * @returns {Sharp}
@@ -559,8 +563,8 @@ function webp (options) {
559
563
  * .toFile('optim.gif');
560
564
  *
561
565
  * @param {Object} [options] - output options
562
- * @param {boolean} [options.reoptimise=false] - always generate new palettes (slow), re-use existing by default
563
- * @param {boolean} [options.reoptimize=false] - alternative spelling of `options.reoptimise`
566
+ * @param {boolean} [options.reuse=true] - re-use existing palette, otherwise generate new (slow)
567
+ * @param {boolean} [options.progressive=false] - use progressive (interlace) scan
564
568
  * @param {number} [options.colours=256] - maximum number of palette entries, including transparency, between 2 and 256
565
569
  * @param {number} [options.colors=256] - alternative spelling of `options.colours`
566
570
  * @param {number} [options.effort=7] - CPU effort, between 1 (fastest) and 10 (slowest)
@@ -575,10 +579,11 @@ function webp (options) {
575
579
  */
576
580
  function gif (options) {
577
581
  if (is.object(options)) {
578
- if (is.defined(options.reoptimise)) {
579
- this._setBooleanOption('gifReoptimise', options.reoptimise);
580
- } else if (is.defined(options.reoptimize)) {
581
- this._setBooleanOption('gifReoptimise', options.reoptimize);
582
+ if (is.defined(options.reuse)) {
583
+ this._setBooleanOption('gifReuse', options.reuse);
584
+ }
585
+ if (is.defined(options.progressive)) {
586
+ this._setBooleanOption('gifProgressive', options.progressive);
582
587
  }
583
588
  const colours = options.colours || options.colors;
584
589
  if (is.defined(colours)) {
@@ -690,7 +695,7 @@ function jp2 (options) {
690
695
  }
691
696
  if (is.defined(options.chromaSubsampling)) {
692
697
  if (is.string(options.chromaSubsampling) && is.inArray(options.chromaSubsampling, ['4:2:0', '4:4:4'])) {
693
- this.options.heifChromaSubsampling = options.chromaSubsampling;
698
+ this.options.jp2ChromaSubsampling = options.chromaSubsampling;
694
699
  } else {
695
700
  throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling);
696
701
  }
@@ -1051,6 +1056,10 @@ function raw (options) {
1051
1056
  *
1052
1057
  * The container will be set to `zip` when the output is a Buffer or Stream, otherwise it will default to `fs`.
1053
1058
  *
1059
+ * Requires libvips compiled with support for libgsf.
1060
+ * The prebuilt binaries do not include this - see
1061
+ * {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}.
1062
+ *
1054
1063
  * @example
1055
1064
  * sharp('input.tiff')
1056
1065
  * .png()
package/lib/platform.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  const detectLibc = require('detect-libc');
package/lib/resize.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  const is = require('./is');
@@ -36,6 +39,18 @@ const position = {
36
39
  'left top': 8
37
40
  };
38
41
 
42
+ /**
43
+ * How to extend the image.
44
+ * @member
45
+ * @private
46
+ */
47
+ const extendWith = {
48
+ background: 'background',
49
+ copy: 'copy',
50
+ repeat: 'repeat',
51
+ mirror: 'mirror'
52
+ };
53
+
39
54
  /**
40
55
  * Strategies for automagic cover behaviour.
41
56
  * @member
@@ -103,7 +118,7 @@ function isResizeExpected (options) {
103
118
  * Resize image to `width`, `height` or `width x height`.
104
119
  *
105
120
  * When both a `width` and `height` are provided, the possible methods by which the image should **fit** these are:
106
- * - `cover`: (default) Preserving aspect ratio, ensure the image covers both provided dimensions by cropping/clipping to fit.
121
+ * - `cover`: (default) Preserving aspect ratio, attempt to ensure the image covers both provided dimensions by cropping/clipping to fit.
107
122
  * - `contain`: Preserving aspect ratio, contain within both provided dimensions using "letterboxing" where necessary.
108
123
  * - `fill`: Ignore the aspect ratio of the input and stretch to both provided dimensions.
109
124
  * - `inside`: Preserving aspect ratio, resize the image to be as large as possible while ensuring its dimensions are less than or equal to both those specified.
@@ -216,32 +231,32 @@ function isResizeExpected (options) {
216
231
  * .toBuffer()
217
232
  * );
218
233
  *
219
- * @param {number} [width] - pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
220
- * @param {number} [height] - pixels high the resultant image should be. Use `null` or `undefined` to auto-scale the height to match the width.
234
+ * @param {number} [width] - How many pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
235
+ * @param {number} [height] - How many pixels high the resultant image should be. Use `null` or `undefined` to auto-scale the height to match the width.
221
236
  * @param {Object} [options]
222
- * @param {String} [options.width] - alternative means of specifying `width`. If both are present this takes priority.
223
- * @param {String} [options.height] - alternative means of specifying `height`. If both are present this takes priority.
224
- * @param {String} [options.fit='cover'] - how the image should be resized to fit both provided dimensions, one of `cover`, `contain`, `fill`, `inside` or `outside`.
225
- * @param {String} [options.position='centre'] - position, gravity or strategy to use when `fit` is `cover` or `contain`.
237
+ * @param {number} [options.width] - An alternative means of specifying `width`. If both are present this takes priority.
238
+ * @param {number} [options.height] - An alternative means of specifying `height`. If both are present this takes priority.
239
+ * @param {String} [options.fit='cover'] - How the image should be resized/cropped to fit the target dimension(s), one of `cover`, `contain`, `fill`, `inside` or `outside`.
240
+ * @param {String} [options.position='centre'] - A position, gravity or strategy to use when `fit` is `cover` or `contain`.
226
241
  * @param {String|Object} [options.background={r: 0, g: 0, b: 0, alpha: 1}] - background colour when `fit` is `contain`, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black without transparency.
227
- * @param {String} [options.kernel='lanczos3'] - the kernel to use for image reduction.
228
- * @param {Boolean} [options.withoutEnlargement=false] - do not enlarge if the width *or* height are already less than the specified dimensions, equivalent to GraphicsMagick's `>` geometry option.
229
- * @param {Boolean} [options.withoutReduction=false] - do not reduce if the width *or* height are already greater than the specified dimensions, equivalent to GraphicsMagick's `<` geometry option.
230
- * @param {Boolean} [options.fastShrinkOnLoad=true] - take greater advantage of the JPEG and WebP shrink-on-load feature, which can lead to a slight moiré pattern on some images.
242
+ * @param {String} [options.kernel='lanczos3'] - The kernel to use for image reduction. Use the `fastShrinkOnLoad` option to control kernel vs shrink-on-load.
243
+ * @param {Boolean} [options.withoutEnlargement=false] - Do not scale up if the width *or* height are already less than the target dimensions, equivalent to GraphicsMagick's `>` geometry option. This may result in output dimensions smaller than the target dimensions.
244
+ * @param {Boolean} [options.withoutReduction=false] - Do not scale down if the width *or* height are already greater than the target dimensions, equivalent to GraphicsMagick's `<` geometry option. This may still result in a crop to reach the target dimensions.
245
+ * @param {Boolean} [options.fastShrinkOnLoad=true] - Take greater advantage of the JPEG and WebP shrink-on-load feature, which can lead to a slight moiré pattern or round-down of an auto-scaled dimension.
231
246
  * @returns {Sharp}
232
247
  * @throws {Error} Invalid parameters
233
248
  */
234
- function resize (width, height, options) {
249
+ function resize (widthOrOptions, height, options) {
235
250
  if (isResizeExpected(this.options)) {
236
251
  this.options.debuglog('ignoring previous resize options');
237
252
  }
238
- if (is.defined(width)) {
239
- if (is.object(width) && !is.defined(options)) {
240
- options = width;
241
- } else if (is.integer(width) && width > 0) {
242
- this.options.width = width;
253
+ if (is.defined(widthOrOptions)) {
254
+ if (is.object(widthOrOptions) && !is.defined(options)) {
255
+ options = widthOrOptions;
256
+ } else if (is.integer(widthOrOptions) && widthOrOptions > 0) {
257
+ this.options.width = widthOrOptions;
243
258
  } else {
244
- throw is.invalidParameterError('width', 'positive integer', width);
259
+ throw is.invalidParameterError('width', 'positive integer', widthOrOptions);
245
260
  }
246
261
  } else {
247
262
  this.options.width = -1;
@@ -322,7 +337,8 @@ function resize (width, height, options) {
322
337
  }
323
338
 
324
339
  /**
325
- * Extends/pads the edges of the image with the provided background colour.
340
+ * Extend / pad / extrude one or more edges of the image with either
341
+ * the provided background colour or pixels derived from the image.
326
342
  * This operation will always occur after resizing and extraction, if any.
327
343
  *
328
344
  * @example
@@ -348,11 +364,21 @@ function resize (width, height, options) {
348
364
  * })
349
365
  * ...
350
366
  *
367
+ * @example
368
+ * // Extrude image by 8 pixels to the right, mirroring existing right hand edge
369
+ * sharp(input)
370
+ * .extend({
371
+ * right: 8,
372
+ * background: 'mirror'
373
+ * })
374
+ * ...
375
+ *
351
376
  * @param {(number|Object)} extend - single pixel count to add to all edges or an Object with per-edge counts
352
377
  * @param {number} [extend.top=0]
353
378
  * @param {number} [extend.left=0]
354
379
  * @param {number} [extend.bottom=0]
355
380
  * @param {number} [extend.right=0]
381
+ * @param {String} [extend.extendWith='background'] - populate new pixels using this method, one of: background, copy, repeat, mirror.
356
382
  * @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.
357
383
  * @returns {Sharp}
358
384
  * @throws {Error} Invalid parameters
@@ -393,6 +419,13 @@ function extend (extend) {
393
419
  }
394
420
  }
395
421
  this._setBackgroundColourOption('extendBackground', extend.background);
422
+ if (is.defined(extend.extendWith)) {
423
+ if (is.string(extendWith[extend.extendWith])) {
424
+ this.options.extendWith = extendWith[extend.extendWith];
425
+ } else {
426
+ throw is.invalidParameterError('extendWith', 'one of: background, copy, repeat, mirror', extend.extendWith);
427
+ }
428
+ }
396
429
  } else {
397
430
  throw is.invalidParameterError('extend', 'integer or object', extend);
398
431
  }
package/lib/sharp.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  const platformAndArch = require('./platform')();
package/lib/utility.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  const fs = require('fs');
@@ -43,7 +46,7 @@ const interpolators = {
43
46
  };
44
47
 
45
48
  /**
46
- * An Object containing the version numbers of libvips and its dependencies.
49
+ * An Object containing the version numbers of sharp, libvips and its dependencies.
47
50
  * @member
48
51
  * @example
49
52
  * console.log(sharp.versions);
@@ -54,6 +57,7 @@ let versions = {
54
57
  try {
55
58
  versions = require(`../vendor/${versions.vips}/${platformAndArch}/versions.json`);
56
59
  } catch (_err) { /* ignore */ }
60
+ versions.sharp = require('../package.json').version;
57
61
 
58
62
  /**
59
63
  * An Object containing the platform and architecture
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sharp",
3
3
  "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
4
- "version": "0.31.3",
4
+ "version": "0.32.0",
5
5
  "author": "Lovell Fuller <npm@lovell.info>",
6
6
  "homepage": "https://github.com/lovell/sharp",
7
7
  "contributors": [
@@ -85,21 +85,24 @@
85
85
  "Brodan <christopher.hranj@gmail.com",
86
86
  "Ankur Parihar <ankur.github@gmail.com>",
87
87
  "Brahim Ait elhaj <brahima@gmail.com>",
88
- "Mart Jansink <m.jansink@gmail.com>"
88
+ "Mart Jansink <m.jansink@gmail.com>",
89
+ "Lachlan Newman <lachnewman007@gmail.com>"
89
90
  ],
90
91
  "scripts": {
91
92
  "install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild && node install/dll-copy)",
92
93
  "clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
93
- "test": "npm run test-lint && npm run test-unit && npm run test-licensing",
94
+ "test": "npm run test-lint && npm run test-unit && npm run test-licensing && npm run test-types",
94
95
  "test-lint": "semistandard && cpplint",
95
96
  "test-unit": "nyc --reporter=lcov --reporter=text --check-coverage --branches=100 mocha",
96
97
  "test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;MIT\"",
97
98
  "test-leak": "./test/leak/leak.sh",
98
- "docs-build": "documentation lint lib && node docs/build && node docs/search-index/build",
99
+ "test-types": "tsd",
100
+ "docs-build": "node docs/build && node docs/search-index/build",
99
101
  "docs-serve": "cd docs && npx serve",
100
102
  "docs-publish": "cd docs && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp"
101
103
  },
102
104
  "main": "lib/index.js",
105
+ "types": "lib/index.d.ts",
103
106
  "files": [
104
107
  "binding.gyp",
105
108
  "install/**",
@@ -131,7 +134,7 @@
131
134
  "dependencies": {
132
135
  "color": "^4.2.3",
133
136
  "detect-libc": "^2.0.1",
134
- "node-addon-api": "^5.0.0",
137
+ "node-addon-api": "^6.0.0",
135
138
  "prebuild-install": "^7.1.1",
136
139
  "semver": "^7.3.8",
137
140
  "simple-get": "^4.0.1",
@@ -139,35 +142,36 @@
139
142
  "tunnel-agent": "^0.6.0"
140
143
  },
141
144
  "devDependencies": {
145
+ "@types/node": "*",
142
146
  "async": "^3.2.4",
143
147
  "cc": "^3.0.1",
144
- "documentation": "^14.0.1",
145
- "exif-reader": "^1.0.3",
148
+ "exif-reader": "^1.2.0",
146
149
  "extract-zip": "^2.0.1",
147
150
  "icc": "^2.0.0",
151
+ "jsdoc-to-markdown": "^8.0.0",
148
152
  "license-checker": "^25.0.1",
149
153
  "mocha": "^10.2.0",
150
154
  "mock-fs": "^5.2.0",
151
155
  "nyc": "^15.1.0",
152
156
  "prebuild": "^11.0.4",
153
- "rimraf": "^3.0.2",
154
- "semistandard": "^16.0.1"
157
+ "semistandard": "^16.0.1",
158
+ "tsd": "^0.28.0"
155
159
  },
156
160
  "license": "Apache-2.0",
157
161
  "config": {
158
- "libvips": "8.13.3",
162
+ "libvips": "8.14.2",
159
163
  "integrity": {
160
- "darwin-arm64v8": "sha512-xFgYt7CtQSZcWoyUdzPTDNHbioZIrZSEU+gkMxzH4Cgjhi4/N49UsonnIZhKQoTBGloAqEexHeMx4rYTQ2Kgvw==",
161
- "darwin-x64": "sha512-6SivWKzu15aUMMohe0wg7sNYMPETVnOe40BuWsnKOgzl3o5FpQqNSgs+68Mi8Za3Qti9/DaR+H/fyD0x48Af2w==",
162
- "linux-arm64v8": "sha512-b+iI9V/ehgDabXYRQcvqa5CEysh+1FQsgFmYc358StCrJCDahwNmsQdsiH1GOVd5WaWh5wHUGByPwMmFOO16Aw==",
163
- "linux-armv6": "sha512-zRP2F+EiustLE4bXSH8AHCxwfemh9d+QuvmPjira/HL6uJOUuA7SyQgVV1TPwTQle2ioCNnKPm7FEB/MAiT+ug==",
164
- "linux-armv7": "sha512-6OCChowE5lBXXXAZrnGdA9dVktg7UdODEBpE5qTroiAJYZv4yXRMgyDFYajok7du2NTgoklhxGk8d9+4vGv5hg==",
165
- "linux-x64": "sha512-OTmlmP2r8ozGKdB96X+K5oQE1ojVZanqLqqKlwDpEnfixyIaDGYbVzcjWBNGU3ai/26bvkaCkjynnc2ecYcsuA==",
166
- "linuxmusl-arm64v8": "sha512-Qh5Wi+bkKTohFYHzSPssfjMhIkD6z6EHbVmnwmWSsgY9zsUBStFp6+mKcNTQfP5YM5Mz06vJOkLHX2OzEr5TzA==",
167
- "linuxmusl-x64": "sha512-DwB4Fs3+ISw9etaLCANkueZDdk758iOS+wNp4TKZkHdq0al6B/3Pk7OHLR8a9E3H6wYDD328u++dcJzip5tacA==",
168
- "win32-arm64v8": "sha512-96r3W+O4BtX602B1MtxU5Ru4lKzRRTZqM4OQEBJ//TNL3fiCZdd9agD+RQBjaeR4KFIyBSt3F7IE425ZWmxz+w==",
169
- "win32-ia32": "sha512-qfN1MsfQGek1QQd1UNW7JT+5K5Ne1suFQ2GpgpYm3JLSpIve/tz2vOGEGzvTVssOBADJvAkTDFt+yIi3PgU9pA==",
170
- "win32-x64": "sha512-eb3aAmjbVVBVRbiYgebQwoxkAt69WI8nwmKlilSQ3kWqoc0pXfIe322rF2UR8ebbISCGvYRUfzD2r1k92RXISQ=="
164
+ "darwin-arm64v8": "sha512-eUuxg6H0tXgX4z2lsaGtZ4cbPAm7yoFgkvPDd4csxoiVt+QUB25pEJwiXw7oB53VlBFIp3O8lbydSFS5zH8MQQ==",
165
+ "darwin-x64": "sha512-cMT4v76IgzSR0VoXqLk/yftRyzMEZ+SBVMLzXCgqP/lmnYisrpmHHNqrWnoZbUUBXbPXLn6KMultYOJHe/c9ZQ==",
166
+ "linux-arm64v8": "sha512-OcDJ/ly80pxwaKnw0W91sSvZczPtWsjmzrY/+6NMiQZT84LkmeaRuwErbHhorKDxnl7iZuNn9Uj5V25Xmj+LDQ==",
167
+ "linux-armv6": "sha512-hk2ohSOYTJEtVQxEQFyQ+tuayKpYqx6NiXa7AE+8MF+yscxt+g+mLJ7TjDqtmb4ttFGH4IVfsEfU2YXIqWqkpg==",
168
+ "linux-armv7": "sha512-/5Ci2Cd+yLZmTaEt9lVJ89elxX3RMJpps0ESjj43X40yrwka51QfXeg1QV38uNzZpCDIZkrbXZK0lyKldjpLuA==",
169
+ "linux-x64": "sha512-wjCKmWfBb0uz1UB7rPDLvO0s+VWuoAY/Vv/YGCRFEQUkdSLQUgHExrOMMbOM3FleuYfQqznDYCXXphkl7X44+w==",
170
+ "linuxmusl-arm64v8": "sha512-QtD2n90yi+rLE65C0gksFUU5uMUFPICI/pS3A0bgthpIcoCejAOYs3ZjVWpZbHQuV/lWahIUYO78MB9CzY860A==",
171
+ "linuxmusl-x64": "sha512-TokQ/ETCJAsPYuxIMOPYDp25rlcwtpmIMtRUR9PB75TmZEJe7abRfCEInIPYeD8F/HxxnJSLiEdlbn1z1Jfzng==",
172
+ "win32-arm64v8": "sha512-IIuj4EAgLqEVAoOuYH79C61a7TcJXlU/RBwk+5JsGWc2mr4J/Ar5J01e6XBvU4Lu3eqcU+3GPaACZEa1511buA==",
173
+ "win32-ia32": "sha512-CsZi7lrReX3B6tmYgOGJ0IiAfcN5APDC6l+3gdosxfTfwpLLO+jXaSmyNwIGeMqrdgckG/gwwc+IrUZmkmjJ/A==",
174
+ "win32-x64": "sha512-J7znmNKUK4ZKo6SnSnEtzT1xRAwvkGXxIx9/QihAadu1TFdS06yNhcENmwC4973+KZBlAdVpWbZ8sLrEoWkdCA=="
171
175
  },
172
176
  "runtime": "napi",
173
177
  "target": 7
@@ -193,5 +197,8 @@
193
197
  "filter": [
194
198
  "build/include"
195
199
  ]
200
+ },
201
+ "tsd": {
202
+ "directory": "test/types/"
196
203
  }
197
204
  }