sharp 0.31.3 → 0.32.1

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');
@@ -85,8 +88,7 @@ const hasVendoredLibvips = function () {
85
88
 
86
89
  /* istanbul ignore next */
87
90
  const removeVendoredLibvips = function () {
88
- const rm = fs.rmSync ? fs.rmSync : fs.rmdirSync;
89
- rm(vendorPath, { recursive: true, maxRetries: 3, force: true });
91
+ fs.rmSync(vendorPath, { recursive: true, maxRetries: 3, force: true });
90
92
  };
91
93
 
92
94
  /* istanbul ignore next */
@@ -115,6 +117,7 @@ const useGlobalLibvips = function () {
115
117
  }
116
118
  /* istanbul ignore next */
117
119
  if (isRosetta()) {
120
+ log('Detected Rosetta, skipping search for globally-installed libvips');
118
121
  return false;
119
122
  }
120
123
  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');
@@ -111,7 +114,7 @@ function flop (flop) {
111
114
  *
112
115
  * You must provide an array of length 4 or a 2x2 affine transformation matrix.
113
116
  * By default, new pixels are filled with a black background. You can provide a background color with the `background` option.
114
- * A particular interpolator may also be specified. Set the `interpolator` option to an attribute of the `sharp.interpolator` Object e.g. `sharp.interpolator.nohalo`.
117
+ * A particular interpolator may also be specified. Set the `interpolator` option to an attribute of the `sharp.interpolators` Object e.g. `sharp.interpolators.nohalo`.
115
118
  *
116
119
  * In the case of a 2x2 matrix, the transform is:
117
120
  * - X = `matrix[0, 0]` \* (x + `idx`) + `matrix[0, 1]` \* (y + `idy`) + `odx`
@@ -128,7 +131,7 @@ function flop (flop) {
128
131
  * const pipeline = sharp()
129
132
  * .affine([[1, 0.3], [0.1, 0.7]], {
130
133
  * background: 'white',
131
- * interpolate: sharp.interpolators.nohalo
134
+ * interpolator: sharp.interpolators.nohalo
132
135
  * })
133
136
  * .toBuffer((err, outputBuffer, info) => {
134
137
  * // outputBuffer contains the transformed image
@@ -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)) {
@@ -402,6 +405,32 @@ function flatten (options) {
402
405
  return this;
403
406
  }
404
407
 
408
+ /**
409
+ * Ensure the image has an alpha channel
410
+ * with all white pixel values made fully transparent.
411
+ *
412
+ * Existing alpha channel values for non-white pixels remain unchanged.
413
+ *
414
+ * This feature is experimental and the API may change.
415
+ *
416
+ * @since 0.32.1
417
+ *
418
+ * @example
419
+ * await sharp(rgbInput)
420
+ * .unflatten()
421
+ * .toBuffer();
422
+ *
423
+ * @example
424
+ * await sharp(rgbInput)
425
+ * .threshold(128, { grayscale: false }) // converter bright pixels to white
426
+ * .unflatten()
427
+ * .toBuffer();
428
+ */
429
+ function unflatten () {
430
+ this.options.unflatten = true;
431
+ return this;
432
+ }
433
+
405
434
  /**
406
435
  * Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma`
407
436
  * then increasing the encoding (brighten) post-resize at a factor of `gamma`.
@@ -466,16 +495,50 @@ function negate (options) {
466
495
  }
467
496
 
468
497
  /**
469
- * Enhance output image contrast by stretching its luminance to cover the full dynamic range.
498
+ * Enhance output image contrast by stretching its luminance to cover a full dynamic range.
499
+ *
500
+ * Uses a histogram-based approach, taking a default range of 1% to 99% to reduce sensitivity to noise at the extremes.
501
+ *
502
+ * Luminance values below the `lower` percentile will be underexposed by clipping to zero.
503
+ * Luminance values above the `upper` percentile will be overexposed by clipping to the max pixel value.
470
504
  *
471
505
  * @example
472
- * const output = await sharp(input).normalise().toBuffer();
506
+ * const output = await sharp(input)
507
+ * .normalise()
508
+ * .toBuffer();
509
+ *
510
+ * @example
511
+ * const output = await sharp(input)
512
+ * .normalise({ lower: 0, upper: 100 })
513
+ * .toBuffer();
473
514
  *
474
- * @param {Boolean} [normalise=true]
515
+ * @param {Object} [options]
516
+ * @param {number} [options.lower=1] - Percentile below which luminance values will be underexposed.
517
+ * @param {number} [options.upper=99] - Percentile above which luminance values will be overexposed.
475
518
  * @returns {Sharp}
476
519
  */
477
- function normalise (normalise) {
478
- this.options.normalise = is.bool(normalise) ? normalise : true;
520
+ function normalise (options) {
521
+ if (is.plainObject(options)) {
522
+ if (is.defined(options.lower)) {
523
+ if (is.number(options.lower) && is.inRange(options.lower, 0, 99)) {
524
+ this.options.normaliseLower = options.lower;
525
+ } else {
526
+ throw is.invalidParameterError('lower', 'number between 0 and 99', options.lower);
527
+ }
528
+ }
529
+ if (is.defined(options.upper)) {
530
+ if (is.number(options.upper) && is.inRange(options.upper, 1, 100)) {
531
+ this.options.normaliseUpper = options.upper;
532
+ } else {
533
+ throw is.invalidParameterError('upper', 'number between 1 and 100', options.upper);
534
+ }
535
+ }
536
+ }
537
+ if (this.options.normaliseLower >= this.options.normaliseUpper) {
538
+ throw is.invalidParameterError('range', 'lower to be less than upper',
539
+ `${this.options.normaliseLower} >= ${this.options.normaliseUpper}`);
540
+ }
541
+ this.options.normalise = true;
479
542
  return this;
480
543
  }
481
544
 
@@ -483,13 +546,17 @@ function normalise (normalise) {
483
546
  * Alternative spelling of normalise.
484
547
  *
485
548
  * @example
486
- * const output = await sharp(input).normalize().toBuffer();
549
+ * const output = await sharp(input)
550
+ * .normalize()
551
+ * .toBuffer();
487
552
  *
488
- * @param {Boolean} [normalize=true]
553
+ * @param {Object} [options]
554
+ * @param {number} [options.lower=1] - Percentile below which luminance values will be underexposed.
555
+ * @param {number} [options.upper=99] - Percentile above which luminance values will be overexposed.
489
556
  * @returns {Sharp}
490
557
  */
491
- function normalize (normalize) {
492
- return this.normalise(normalize);
558
+ function normalize (options) {
559
+ return this.normalise(options);
493
560
  }
494
561
 
495
562
  /**
@@ -509,34 +576,33 @@ function normalize (normalize) {
509
576
  * .toBuffer();
510
577
  *
511
578
  * @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)
579
+ * @param {number} options.width - Integral width of the search window, in pixels.
580
+ * @param {number} options.height - Integral height of the search window, in pixels.
581
+ * @param {number} [options.maxSlope=3] - Integral level of brightening, between 0 and 100, where 0 disables contrast limiting.
517
582
  * @returns {Sharp}
518
583
  * @throws {Error} Invalid parameters
519
584
  */
520
585
  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);
586
+ if (is.plainObject(options)) {
587
+ if (is.integer(options.width) && options.width > 0) {
588
+ this.options.claheWidth = options.width;
589
+ } else {
590
+ throw is.invalidParameterError('width', 'integer greater than zero', options.width);
591
+ }
592
+ if (is.integer(options.height) && options.height > 0) {
593
+ this.options.claheHeight = options.height;
594
+ } else {
595
+ throw is.invalidParameterError('height', 'integer greater than zero', options.height);
596
+ }
597
+ if (is.defined(options.maxSlope)) {
598
+ if (is.integer(options.maxSlope) && is.inRange(options.maxSlope, 0, 100)) {
599
+ this.options.claheMaxSlope = options.maxSlope;
600
+ } else {
601
+ throw is.invalidParameterError('maxSlope', 'integer between 0 and 100', options.maxSlope);
602
+ }
603
+ }
538
604
  } else {
539
- this.options.claheMaxSlope = options.maxSlope;
605
+ throw is.invalidParameterError('options', 'plain object', options);
540
606
  }
541
607
  return this;
542
608
  }
@@ -835,6 +901,7 @@ module.exports = function (Sharp) {
835
901
  median,
836
902
  blur,
837
903
  flatten,
904
+ unflatten,
838
905
  gamma,
839
906
  negate,
840
907
  normalise,
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');
@@ -40,7 +43,7 @@ const bitdepthFromColourCount = (colours) => 1 << 31 - Math.clz32(Math.ceil(Math
40
43
  * Note that raw pixel data is only supported for buffer output.
41
44
  *
42
45
  * By default all metadata will be removed, which includes EXIF-based orientation.
43
- * See {@link withMetadata} for control over this.
46
+ * See {@link #withmetadata|withMetadata} for control over this.
44
47
  *
45
48
  * The caller is responsible for ensuring directory structures and permissions exist.
46
49
  *
@@ -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
@@ -91,12 +95,12 @@ function toFile (fileOut, callback) {
91
95
  * Write output to a Buffer.
92
96
  * JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
93
97
  *
94
- * Use {@link toFormat} or one of the format-specific functions such as {@link jpeg}, {@link png} etc. to set the output format.
98
+ * Use {@link #toformat|toFormat} or one of the format-specific functions such as {@link jpeg}, {@link png} etc. to set the output format.
95
99
  *
96
100
  * If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.
97
101
  *
98
102
  * By default all metadata will be removed, which includes EXIF-based orientation.
99
- * See {@link withMetadata} for control over this.
103
+ * See {@link #withmetadata|withMetadata} for control over this.
100
104
  *
101
105
  * `callback`, if present, gets three arguments `(err, data, info)` where:
102
106
  * - `err` is an error, if any.
@@ -173,12 +177,18 @@ function toBuffer (options, callback) {
173
177
  * .then(info => { ... });
174
178
  *
175
179
  * @example
176
- * // Set "IFD0-Copyright" in output EXIF metadata
180
+ * // Set output EXIF metadata
177
181
  * const data = await sharp(input)
178
182
  * .withMetadata({
179
183
  * exif: {
180
184
  * IFD0: {
181
- * Copyright: 'Wernham Hogg'
185
+ * Copyright: 'The National Gallery'
186
+ * },
187
+ * IFD3: {
188
+ * GPSLatitudeRef: 'N',
189
+ * GPSLatitude: '51/1 30/1 3230/100',
190
+ * GPSLongitudeRef: 'W',
191
+ * GPSLongitude: '0/1 7/1 4366/100'
182
192
  * }
183
193
  * }
184
194
  * })
@@ -192,7 +202,7 @@ function toBuffer (options, callback) {
192
202
  *
193
203
  * @param {Object} [options]
194
204
  * @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.
205
+ * @param {string} [options.icc='srgb'] Filesystem path to output ICC profile, relative to `process.cwd()`, defaults to built-in sRGB.
196
206
  * @param {Object<Object>} [options.exif={}] Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
197
207
  * @param {number} [options.density] Number of pixels per inch (DPI).
198
208
  * @returns {Sharp}
@@ -559,8 +569,8 @@ function webp (options) {
559
569
  * .toFile('optim.gif');
560
570
  *
561
571
  * @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`
572
+ * @param {boolean} [options.reuse=true] - re-use existing palette, otherwise generate new (slow)
573
+ * @param {boolean} [options.progressive=false] - use progressive (interlace) scan
564
574
  * @param {number} [options.colours=256] - maximum number of palette entries, including transparency, between 2 and 256
565
575
  * @param {number} [options.colors=256] - alternative spelling of `options.colours`
566
576
  * @param {number} [options.effort=7] - CPU effort, between 1 (fastest) and 10 (slowest)
@@ -575,10 +585,11 @@ function webp (options) {
575
585
  */
576
586
  function gif (options) {
577
587
  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);
588
+ if (is.defined(options.reuse)) {
589
+ this._setBooleanOption('gifReuse', options.reuse);
590
+ }
591
+ if (is.defined(options.progressive)) {
592
+ this._setBooleanOption('gifProgressive', options.progressive);
582
593
  }
583
594
  const colours = options.colours || options.colors;
584
595
  if (is.defined(colours)) {
@@ -621,6 +632,7 @@ function gif (options) {
621
632
  return this._updateFormatOut('gif', options);
622
633
  }
623
634
 
635
+ /* istanbul ignore next */
624
636
  /**
625
637
  * Use these JP2 options for output image.
626
638
  *
@@ -654,7 +666,6 @@ function gif (options) {
654
666
  * @returns {Sharp}
655
667
  * @throws {Error} Invalid options
656
668
  */
657
- /* istanbul ignore next */
658
669
  function jp2 (options) {
659
670
  if (!this.constructor.format.jp2k.output.buffer) {
660
671
  throw errJp2Save();
@@ -690,7 +701,7 @@ function jp2 (options) {
690
701
  }
691
702
  if (is.defined(options.chromaSubsampling)) {
692
703
  if (is.string(options.chromaSubsampling) && is.inArray(options.chromaSubsampling, ['4:2:0', '4:4:4'])) {
693
- this.options.heifChromaSubsampling = options.chromaSubsampling;
704
+ this.options.jp2ChromaSubsampling = options.chromaSubsampling;
694
705
  } else {
695
706
  throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling);
696
707
  }
@@ -735,7 +746,8 @@ function trySetAnimationOptions (source, target) {
735
746
  /**
736
747
  * Use these TIFF options for output image.
737
748
  *
738
- * The `density` can be set in pixels/inch via {@link withMetadata} instead of providing `xres` and `yres` in pixels/mm.
749
+ * The `density` can be set in pixels/inch via {@link #withmetadata|withMetadata}
750
+ * instead of providing `xres` and `yres` in pixels/mm.
739
751
  *
740
752
  * @example
741
753
  * // Convert SVG input to LZW-compressed, 1 bit per pixel TIFF output
@@ -1051,6 +1063,10 @@ function raw (options) {
1051
1063
  *
1052
1064
  * The container will be set to `zip` when the output is a Buffer or Stream, otherwise it will default to `fs`.
1053
1065
  *
1066
+ * Requires libvips compiled with support for libgsf.
1067
+ * The prebuilt binaries do not include this - see
1068
+ * {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}.
1069
+ *
1054
1070
  * @example
1055
1071
  * sharp('input.tiff')
1056
1072
  * .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')();