sharp 0.33.5 → 0.35.3

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.
Files changed (49) hide show
  1. package/README.md +12 -18
  2. package/dist/channel.cjs +177 -0
  3. package/{lib/channel.js → dist/channel.mjs} +11 -8
  4. package/dist/colour.cjs +199 -0
  5. package/{lib/colour.js → dist/colour.mjs} +42 -23
  6. package/dist/composite.cjs +213 -0
  7. package/{lib/composite.js → dist/composite.mjs} +14 -11
  8. package/{lib/constructor.js → dist/constructor.cjs} +102 -43
  9. package/dist/constructor.mjs +511 -0
  10. package/dist/index.cjs +25 -0
  11. package/dist/index.d.cts +1999 -0
  12. package/dist/index.d.mts +2046 -0
  13. package/dist/index.mjs +25 -0
  14. package/dist/input.cjs +814 -0
  15. package/{lib/input.js → dist/input.mjs} +232 -76
  16. package/{lib/is.js → dist/is.cjs} +19 -45
  17. package/dist/is.mjs +143 -0
  18. package/{lib/libvips.js → dist/libvips.cjs} +52 -43
  19. package/dist/libvips.mjs +212 -0
  20. package/dist/operation.cjs +998 -0
  21. package/{lib/operation.js → dist/operation.mjs} +131 -91
  22. package/{lib/output.js → dist/output.cjs} +262 -61
  23. package/dist/output.mjs +1788 -0
  24. package/dist/resize.cjs +617 -0
  25. package/{lib/resize.js → dist/resize.mjs} +65 -35
  26. package/dist/sharp.cjs +174 -0
  27. package/dist/sharp.mjs +174 -0
  28. package/{lib/utility.js → dist/utility.cjs} +30 -25
  29. package/dist/utility.mjs +301 -0
  30. package/install/build.js +38 -0
  31. package/lib/index.d.ts +387 -142
  32. package/package.json +90 -85
  33. package/src/binding.gyp +49 -26
  34. package/src/common.cc +203 -111
  35. package/src/common.h +68 -40
  36. package/src/metadata.cc +106 -22
  37. package/src/metadata.h +15 -5
  38. package/src/operations.cc +62 -21
  39. package/src/operations.h +15 -3
  40. package/src/pipeline.cc +391 -201
  41. package/src/pipeline.h +36 -7
  42. package/src/sharp.cc +11 -8
  43. package/src/stats.cc +16 -13
  44. package/src/stats.h +6 -3
  45. package/src/utilities.cc +35 -15
  46. package/src/utilities.h +5 -2
  47. package/install/check.js +0 -41
  48. package/lib/index.js +0 -16
  49. package/lib/sharp.js +0 -114
@@ -1,11 +1,11 @@
1
- // Copyright 2013 Lovell Fuller and others.
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- 'use strict';
1
+ /*!
2
+ Copyright 2013 Lovell Fuller and others.
3
+ SPDX-License-Identifier: Apache-2.0
4
+ */
5
5
 
6
6
  const path = require('node:path');
7
- const is = require('./is');
8
- const sharp = require('./sharp');
7
+ const is = require('./is.cjs');
8
+ const sharp = require('./sharp.cjs');
9
9
 
10
10
  const formats = new Map([
11
11
  ['heic', 'heif'],
@@ -43,7 +43,7 @@ const bitdepthFromColourCount = (colours) => 1 << 31 - Math.clz32(Math.ceil(Math
43
43
  * Note that raw pixel data is only supported for buffer output.
44
44
  *
45
45
  * By default all metadata will be removed, which includes EXIF-based orientation.
46
- * See {@link #withmetadata|withMetadata} for control over this.
46
+ * See {@link #withmetadata withMetadata} for control over this.
47
47
  *
48
48
  * The caller is responsible for ensuring directory structures and permissions exist.
49
49
  *
@@ -76,7 +76,7 @@ function toFile (fileOut, callback) {
76
76
  err = new Error('Missing output file path');
77
77
  } else if (is.string(this.options.input.file) && path.resolve(this.options.input.file) === path.resolve(fileOut)) {
78
78
  err = new Error('Cannot use same file for input and output');
79
- } else if (jp2Regex.test(path.extname(fileOut)) && !this.constructor.format.jp2k.output.file) {
79
+ } else if (jp2Regex.test(path.extname(fileOut)) && !this.constructor.format.jp2.output.file) {
80
80
  err = errJp2Save();
81
81
  }
82
82
  if (err) {
@@ -97,12 +97,12 @@ function toFile (fileOut, callback) {
97
97
  * Write output to a Buffer.
98
98
  * JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
99
99
  *
100
- * Use {@link #toformat|toFormat} or one of the format-specific functions such as {@link jpeg}, {@link png} etc. to set the output format.
100
+ * Use {@link #toformat toFormat} or one of the format-specific functions such as {@link #jpeg jpeg}, {@link #png png} etc. to set the output format.
101
101
  *
102
102
  * If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.
103
103
  *
104
104
  * By default all metadata will be removed, which includes EXIF-based orientation.
105
- * See {@link #withmetadata|withMetadata} for control over this.
105
+ * See {@link #withmetadata withMetadata} for control over this.
106
106
  *
107
107
  * `callback`, if present, gets three arguments `(err, data, info)` where:
108
108
  * - `err` is an error, if any.
@@ -113,24 +113,20 @@ function toFile (fileOut, callback) {
113
113
  * Animated output will also contain `pageHeight` and `pages`.
114
114
  * May also contain `textAutofitDpi` (dpi the font was rendered at) if image was created from text.
115
115
  *
116
- * A `Promise` is returned when `callback` is not provided.
116
+ * The underlying `ArrayBuffer` may be marked as non-transferable by some JavaScript runtimes.
117
+ * Use {@link #touint8array toUint8Array} for a guaranteed transferable `ArrayBuffer`.
117
118
  *
118
- * @example
119
- * sharp(input)
120
- * .toBuffer((err, data, info) => { ... });
119
+ * A `Promise` is returned when `callback` is not provided.
121
120
  *
122
121
  * @example
123
- * sharp(input)
124
- * .toBuffer()
125
- * .then(data => { ... })
126
- * .catch(err => { ... });
122
+ * const data = await sharp(input)
123
+ * .png()
124
+ * .toBuffer();
127
125
  *
128
126
  * @example
129
- * sharp(input)
127
+ * const { data, info } = await sharp(input)
130
128
  * .png()
131
- * .toBuffer({ resolveWithObject: true })
132
- * .then(({ data, info }) => { ... })
133
- * .catch(err => { ... });
129
+ * .toBuffer({ resolveWithObject: true });
134
130
  *
135
131
  * @example
136
132
  * const { data, info } = await sharp('my-image.jpg')
@@ -164,6 +160,64 @@ function toBuffer (options, callback) {
164
160
  return this._pipeline(is.fn(options) ? options : callback, stack);
165
161
  }
166
162
 
163
+ /**
164
+ * Write output to a `Uint8Array` backed by a transferable `ArrayBuffer`.
165
+ * JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
166
+ *
167
+ * Use {@link #toformat toFormat} or one of the format-specific functions such as {@link #jpeg jpeg}, {@link #png png} etc. to set the output format.
168
+ *
169
+ * If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.
170
+ *
171
+ * By default all metadata will be removed, which includes EXIF-based orientation.
172
+ * See {@link #keepexif keepExif} and similar methods for control over this.
173
+ *
174
+ * Resolves with an `Object` containing:
175
+ * - `data` is the output image as a `Uint8Array` backed by a transferable `ArrayBuffer`.
176
+ * - `info` contains properties relating to the output image such as `width` and `height`.
177
+ *
178
+ * @since v0.35.0
179
+ *
180
+ * @example
181
+ * const { data, info } = await sharp(input).toUint8Array();
182
+ *
183
+ * @example
184
+ * const { data } = await sharp(input)
185
+ * .avif()
186
+ * .toUint8Array();
187
+ * const base64String = data.toBase64();
188
+ *
189
+ * @returns {Promise<{ data: Uint8Array, info: Object }>}
190
+ */
191
+ function toUint8Array () {
192
+ this.options.resolveWithObject = true;
193
+ this.options.typedArrayOut = true;
194
+ const stack = Error();
195
+ return this._pipeline(null, stack);
196
+ }
197
+
198
+ /**
199
+ * Set output density (DPI) in EXIF metadata.
200
+ *
201
+ * @since 0.35.0
202
+ *
203
+ * @example
204
+ * const data = await sharp(input)
205
+ * .withDensity(96)
206
+ * .toBuffer();
207
+ *
208
+ * @param {number} density Number of pixels per inch (DPI).
209
+ * @returns {Sharp}
210
+ * @throws {Error} Invalid parameters
211
+ */
212
+ function withDensity (density) {
213
+ if (is.number(density) && density > 0) {
214
+ this.options.withMetadataDensity = density;
215
+ } else {
216
+ throw is.invalidParameterError('density', 'positive number', density);
217
+ }
218
+ return this.keepExif();
219
+ }
220
+
167
221
  /**
168
222
  * Keep all EXIF metadata from the input image in the output image.
169
223
  *
@@ -256,7 +310,7 @@ function withExifMerge (exif) {
256
310
  /**
257
311
  * Keep ICC profile from the input image in the output image.
258
312
  *
259
- * Where necessary, will attempt to convert the output colour space to match the profile.
313
+ * When input and output colour spaces differ, use with {@link /api-colour/#tocolourspace toColourspace} and optionally {@link /api-colour/#pipelinecolourspace pipelineColourspace}.
260
314
  *
261
315
  * @since 0.33.0
262
316
  *
@@ -265,6 +319,13 @@ function withExifMerge (exif) {
265
319
  * .keepIccProfile()
266
320
  * .toBuffer();
267
321
  *
322
+ * @example
323
+ * const cmykOutputWithIccProfile = await sharp(cmykInputWithIccProfile)
324
+ * .pipelineColourspace('cmyk')
325
+ * .toColourspace('cmyk')
326
+ * .keepIccProfile()
327
+ * .toBuffer();
328
+ *
268
329
  * @returns {Sharp}
269
330
  */
270
331
  function keepIccProfile () {
@@ -312,6 +373,113 @@ function withIccProfile (icc, options) {
312
373
  return this;
313
374
  }
314
375
 
376
+ /**
377
+ * If the input contains gain map metadata, attempt to process the image and gain map separately,
378
+ * recombining them into a single output image.
379
+ *
380
+ * This approach is faster and should produce better results than {@link #withgainmap withGainMap},
381
+ * however not all operations are supported.
382
+ *
383
+ * Only JPEG input and output are supported.
384
+ * JPEG output options other than `quality` are ignored.
385
+ *
386
+ * This feature is experimental and the API may change.
387
+ *
388
+ * @since 0.35.0
389
+ *
390
+ * @example
391
+ * const outputWithResizedGainMap = await sharp(inputWithGainMap)
392
+ * .keepGainMap()
393
+ * .resize({ width: 64 })
394
+ * .toBuffer();
395
+ *
396
+ * @returns {Sharp}
397
+ */
398
+ function keepGainMap() {
399
+ this.options.keepGainMap = true;
400
+ this.options.withGainMap = false;
401
+ this.options.keepMetadata |= 0b100000;
402
+ return this;
403
+ }
404
+
405
+ /**
406
+ * If the input contains gain map metadata, use it to convert the main image to HDR (High Dynamic Range) before further processing.
407
+ * The input gain map is discarded.
408
+ *
409
+ * If the output is JPEG, generate and attach a new ISO 21496-1 gain map.
410
+ * JPEG output options other than `quality` are ignored.
411
+ *
412
+ * This feature is experimental and the API may change.
413
+ *
414
+ * @since 0.35.0
415
+ *
416
+ * @example
417
+ * const outputWithRegeneratedGainMap = await sharp(inputWithGainMap)
418
+ * .withGainMap()
419
+ * .toBuffer();
420
+ *
421
+ * @returns {Sharp}
422
+ */
423
+ function withGainMap() {
424
+ this.options.withGainMap = true;
425
+ this.options.keepGainMap = false;
426
+ this.options.colourspace = 'scrgb';
427
+ return this;
428
+ }
429
+
430
+ /**
431
+ * Keep XMP metadata from the input image in the output image.
432
+ *
433
+ * @since 0.34.3
434
+ *
435
+ * @example
436
+ * const outputWithXmp = await sharp(inputWithXmp)
437
+ * .keepXmp()
438
+ * .toBuffer();
439
+ *
440
+ * @returns {Sharp}
441
+ */
442
+ function keepXmp () {
443
+ this.options.keepMetadata |= 0b00010;
444
+ return this;
445
+ }
446
+
447
+ /**
448
+ * Set XMP metadata in the output image.
449
+ *
450
+ * Supported by PNG, JPEG, WebP, and TIFF output.
451
+ *
452
+ * @since 0.34.3
453
+ *
454
+ * @example
455
+ * const xmpString = `
456
+ * <?xml version="1.0"?>
457
+ * <x:xmpmeta xmlns:x="adobe:ns:meta/">
458
+ * <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
459
+ * <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">
460
+ * <dc:creator><rdf:Seq><rdf:li>John Doe</rdf:li></rdf:Seq></dc:creator>
461
+ * </rdf:Description>
462
+ * </rdf:RDF>
463
+ * </x:xmpmeta>`;
464
+ *
465
+ * const data = await sharp(input)
466
+ * .withXmp(xmpString)
467
+ * .toBuffer();
468
+ *
469
+ * @param {string} xmp String containing XMP metadata to be embedded in the output image.
470
+ * @returns {Sharp}
471
+ * @throws {Error} Invalid parameters
472
+ */
473
+ function withXmp (xmp) {
474
+ if (is.string(xmp) && xmp.length > 0) {
475
+ this.options.withXmp = xmp;
476
+ this.options.keepMetadata |= 0b00010;
477
+ } else {
478
+ throw is.invalidParameterError('xmp', 'non-empty string', xmp);
479
+ }
480
+ return this;
481
+ }
482
+
315
483
  /**
316
484
  * Keep all metadata (EXIF, ICC, XMP, IPTC) from the input image in the output image.
317
485
  *
@@ -328,7 +496,7 @@ function withIccProfile (icc, options) {
328
496
  * @returns {Sharp}
329
497
  */
330
498
  function keepMetadata () {
331
- this.options.keepMetadata = 0b11111;
499
+ this.options.keepMetadata |= 0b11111;
332
500
  return this;
333
501
  }
334
502
 
@@ -512,7 +680,7 @@ function jpeg (options) {
512
680
  * Set `palette` to `true` for slower, indexed PNG output.
513
681
  *
514
682
  * For 16 bits per pixel output, convert to `rgb16` via
515
- * {@link /api-colour#tocolourspace|toColourspace}.
683
+ * {@link /api-colour/#tocolourspace toColourspace}.
516
684
  *
517
685
  * @example
518
686
  * // Convert any input to full colour PNG output
@@ -623,12 +791,14 @@ function png (options) {
623
791
  * @param {boolean} [options.lossless=false] - use lossless compression mode
624
792
  * @param {boolean} [options.nearLossless=false] - use near_lossless compression mode
625
793
  * @param {boolean} [options.smartSubsample=false] - use high quality chroma subsampling
794
+ * @param {boolean} [options.smartDeblock=false] - auto-adjust the deblocking filter, can improve low contrast edges (slow)
626
795
  * @param {string} [options.preset='default'] - named preset for preprocessing/filtering, one of: default, photo, picture, drawing, icon, text
627
796
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 6 (slowest)
628
797
  * @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation
629
798
  * @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
630
799
  * @param {boolean} [options.minSize=false] - prevent use of animation key frames to minimise file size (slow)
631
800
  * @param {boolean} [options.mixed=false] - allow mixture of lossy and lossless animation frames (slow)
801
+ * @param {boolean} [options.exact=false] - preserve the colour data in transparent pixels
632
802
  * @param {boolean} [options.force=true] - force WebP output, otherwise attempt to use input format
633
803
  * @returns {Sharp}
634
804
  * @throws {Error} Invalid options
@@ -658,6 +828,9 @@ function webp (options) {
658
828
  if (is.defined(options.smartSubsample)) {
659
829
  this._setBooleanOption('webpSmartSubsample', options.smartSubsample);
660
830
  }
831
+ if (is.defined(options.smartDeblock)) {
832
+ this._setBooleanOption('webpSmartDeblock', options.smartDeblock);
833
+ }
661
834
  if (is.defined(options.preset)) {
662
835
  if (is.string(options.preset) && is.inArray(options.preset, ['default', 'photo', 'picture', 'drawing', 'icon', 'text'])) {
663
836
  this.options.webpPreset = options.preset;
@@ -678,6 +851,9 @@ function webp (options) {
678
851
  if (is.defined(options.mixed)) {
679
852
  this._setBooleanOption('webpMixed', options.mixed);
680
853
  }
854
+ if (is.defined(options.exact)) {
855
+ this._setBooleanOption('webpExact', options.exact);
856
+ }
681
857
  }
682
858
  trySetAnimationOptions(options, this.options);
683
859
  return this._updateFormatOut('webp', options);
@@ -725,6 +901,7 @@ function webp (options) {
725
901
  * @param {number} [options.dither=1.0] - level of Floyd-Steinberg error diffusion, between 0 (least) and 1 (most)
726
902
  * @param {number} [options.interFrameMaxError=0] - maximum inter-frame error for transparency, between 0 (lossless) and 32
727
903
  * @param {number} [options.interPaletteMaxError=3] - maximum inter-palette error for palette reuse, between 0 and 256
904
+ * @param {boolean} [options.keepDuplicateFrames=false] - keep duplicate frames in the output instead of combining them
728
905
  * @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation
729
906
  * @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
730
907
  * @param {boolean} [options.force=true] - force GIF output, otherwise attempt to use input format
@@ -748,7 +925,7 @@ function gif (options) {
748
925
  }
749
926
  }
750
927
  if (is.defined(options.effort)) {
751
- if (is.number(options.effort) && is.inRange(options.effort, 1, 10)) {
928
+ if (is.integer(options.effort) && is.inRange(options.effort, 1, 10)) {
752
929
  this.options.gifEffort = options.effort;
753
930
  } else {
754
931
  throw is.invalidParameterError('effort', 'integer between 1 and 10', options.effort);
@@ -775,18 +952,24 @@ function gif (options) {
775
952
  throw is.invalidParameterError('interPaletteMaxError', 'number between 0.0 and 256.0', options.interPaletteMaxError);
776
953
  }
777
954
  }
955
+ if (is.defined(options.keepDuplicateFrames)) {
956
+ if (is.bool(options.keepDuplicateFrames)) {
957
+ this._setBooleanOption('gifKeepDuplicateFrames', options.keepDuplicateFrames);
958
+ } else {
959
+ throw is.invalidParameterError('keepDuplicateFrames', 'boolean', options.keepDuplicateFrames);
960
+ }
961
+ }
778
962
  }
779
963
  trySetAnimationOptions(options, this.options);
780
964
  return this._updateFormatOut('gif', options);
781
965
  }
782
966
 
783
- /* istanbul ignore next */
784
967
  /**
785
968
  * Use these JP2 options for output image.
786
969
  *
787
970
  * Requires libvips compiled with support for OpenJPEG.
788
971
  * The prebuilt binaries do not include this - see
789
- * {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}.
972
+ * {@link /install#custom-libvips installing a custom libvips}.
790
973
  *
791
974
  * @example
792
975
  * // Convert any input to lossless JP2 output
@@ -815,7 +998,8 @@ function gif (options) {
815
998
  * @throws {Error} Invalid options
816
999
  */
817
1000
  function jp2 (options) {
818
- if (!this.constructor.format.jp2k.output.buffer) {
1001
+ /* node:coverage ignore next 41 */
1002
+ if (!this.constructor.format.jp2.output.buffer) {
819
1003
  throw errJp2Save();
820
1004
  }
821
1005
  if (is.object(options)) {
@@ -894,7 +1078,7 @@ function trySetAnimationOptions (source, target) {
894
1078
  /**
895
1079
  * Use these TIFF options for output image.
896
1080
  *
897
- * The `density` can be set in pixels/inch via {@link #withmetadata|withMetadata}
1081
+ * The `density` can be set in pixels/inch via {@link #withmetadata withMetadata}
898
1082
  * instead of providing `xres` and `yres` in pixels/mm.
899
1083
  *
900
1084
  * @example
@@ -911,15 +1095,16 @@ function trySetAnimationOptions (source, target) {
911
1095
  * @param {number} [options.quality=80] - quality, integer 1-100
912
1096
  * @param {boolean} [options.force=true] - force TIFF output, otherwise attempt to use input format
913
1097
  * @param {string} [options.compression='jpeg'] - compression options: none, jpeg, deflate, packbits, ccittfax4, lzw, webp, zstd, jp2k
1098
+ * @param {boolean} [options.bigtiff=false] - use BigTIFF variant (has no effect when compression is none)
914
1099
  * @param {string} [options.predictor='horizontal'] - compression predictor options: none, horizontal, float
915
1100
  * @param {boolean} [options.pyramid=false] - write an image pyramid
916
1101
  * @param {boolean} [options.tile=false] - write a tiled tiff
917
- * @param {number} [options.tileWidth=256] - horizontal tile size
918
- * @param {number} [options.tileHeight=256] - vertical tile size
919
- * @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm
920
- * @param {number} [options.yres=1.0] - vertical resolution in pixels/mm
1102
+ * @param {number} [options.tileWidth=256] - horizontal tile size, valid values are integers in the range 1-32768
1103
+ * @param {number} [options.tileHeight=256] - vertical tile size, valid values are integers in the range 1-32768
1104
+ * @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm, valid values are numbers in the range 0.001-1000000
1105
+ * @param {number} [options.yres=1.0] - vertical resolution in pixels/mm, valid values are numbers in the range 0.001-1000000
921
1106
  * @param {string} [options.resolutionUnit='inch'] - resolution unit options: inch, cm
922
- * @param {number} [options.bitdepth=8] - reduce bitdepth to 1, 2 or 4 bit
1107
+ * @param {number} [options.bitdepth=0] - reduce bitdepth to 1, 2 or 4 bit
923
1108
  * @param {boolean} [options.miniswhite=false] - write 1-bit images as miniswhite
924
1109
  * @returns {Sharp}
925
1110
  * @throws {Error} Invalid options
@@ -934,10 +1119,10 @@ function tiff (options) {
934
1119
  }
935
1120
  }
936
1121
  if (is.defined(options.bitdepth)) {
937
- if (is.integer(options.bitdepth) && is.inArray(options.bitdepth, [1, 2, 4, 8])) {
1122
+ if (is.integer(options.bitdepth) && is.inArray(options.bitdepth, [1, 2, 4])) {
938
1123
  this.options.tiffBitdepth = options.bitdepth;
939
1124
  } else {
940
- throw is.invalidParameterError('bitdepth', '1, 2, 4 or 8', options.bitdepth);
1125
+ throw is.invalidParameterError('bitdepth', '1, 2 or 4', options.bitdepth);
941
1126
  }
942
1127
  }
943
1128
  // tiling
@@ -945,17 +1130,17 @@ function tiff (options) {
945
1130
  this._setBooleanOption('tiffTile', options.tile);
946
1131
  }
947
1132
  if (is.defined(options.tileWidth)) {
948
- if (is.integer(options.tileWidth) && options.tileWidth > 0) {
1133
+ if (is.integer(options.tileWidth) && is.inRange(options.tileWidth, 1, 32768)) {
949
1134
  this.options.tiffTileWidth = options.tileWidth;
950
1135
  } else {
951
- throw is.invalidParameterError('tileWidth', 'integer greater than zero', options.tileWidth);
1136
+ throw is.invalidParameterError('tileWidth', 'integer between 1 and 32768', options.tileWidth);
952
1137
  }
953
1138
  }
954
1139
  if (is.defined(options.tileHeight)) {
955
- if (is.integer(options.tileHeight) && options.tileHeight > 0) {
1140
+ if (is.integer(options.tileHeight) && is.inRange(options.tileHeight, 1, 32768)) {
956
1141
  this.options.tiffTileHeight = options.tileHeight;
957
1142
  } else {
958
- throw is.invalidParameterError('tileHeight', 'integer greater than zero', options.tileHeight);
1143
+ throw is.invalidParameterError('tileHeight', 'integer between 1 and 32768', options.tileHeight);
959
1144
  }
960
1145
  }
961
1146
  // miniswhite
@@ -968,17 +1153,17 @@ function tiff (options) {
968
1153
  }
969
1154
  // resolution
970
1155
  if (is.defined(options.xres)) {
971
- if (is.number(options.xres) && options.xres > 0) {
1156
+ if (is.number(options.xres) && is.inRange(options.xres, 0.001, 1000000)) {
972
1157
  this.options.tiffXres = options.xres;
973
1158
  } else {
974
- throw is.invalidParameterError('xres', 'number greater than zero', options.xres);
1159
+ throw is.invalidParameterError('xres', 'number between 0.001 and 1000000', options.xres);
975
1160
  }
976
1161
  }
977
1162
  if (is.defined(options.yres)) {
978
- if (is.number(options.yres) && options.yres > 0) {
1163
+ if (is.number(options.yres) && is.inRange(options.yres, 0.001, 1000000)) {
979
1164
  this.options.tiffYres = options.yres;
980
1165
  } else {
981
- throw is.invalidParameterError('yres', 'number greater than zero', options.yres);
1166
+ throw is.invalidParameterError('yres', 'number between 0.001 and 1000000', options.yres);
982
1167
  }
983
1168
  }
984
1169
  // compression
@@ -989,6 +1174,10 @@ function tiff (options) {
989
1174
  throw is.invalidParameterError('compression', 'one of: none, jpeg, deflate, packbits, ccittfax4, lzw, webp, zstd, jp2k', options.compression);
990
1175
  }
991
1176
  }
1177
+ // bigtiff
1178
+ if (is.defined(options.bigtiff)) {
1179
+ this._setBooleanOption('tiffBigtiff', options.bigtiff);
1180
+ }
992
1181
  // predictor
993
1182
  if (is.defined(options.predictor)) {
994
1183
  if (is.string(options.predictor) && is.inArray(options.predictor, ['none', 'horizontal', 'float'])) {
@@ -1013,7 +1202,6 @@ function tiff (options) {
1013
1202
  * Use these AVIF options for output image.
1014
1203
  *
1015
1204
  * AVIF image sequences are not supported.
1016
- * Prebuilt binaries support a bitdepth of 8 only.
1017
1205
  *
1018
1206
  * @example
1019
1207
  * const data = await sharp(input)
@@ -1033,6 +1221,7 @@ function tiff (options) {
1033
1221
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
1034
1222
  * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
1035
1223
  * @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
1224
+ * @param {string} [options.tune='auto'] - tune output for a quality metric, one of 'auto' (default), 'iq', 'psnr' or 'ssim'
1036
1225
  * @returns {Sharp}
1037
1226
  * @throws {Error} Invalid options
1038
1227
  */
@@ -1060,6 +1249,7 @@ function avif (options) {
1060
1249
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
1061
1250
  * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
1062
1251
  * @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
1252
+ * @param {string} [options.tune='auto'] - tune output for a quality metric, one of 'auto' (default), 'iq', 'psnr' or 'ssim'
1063
1253
  * @returns {Sharp}
1064
1254
  * @throws {Error} Invalid options
1065
1255
  */
@@ -1100,14 +1290,22 @@ function heif (options) {
1100
1290
  }
1101
1291
  if (is.defined(options.bitdepth)) {
1102
1292
  if (is.integer(options.bitdepth) && is.inArray(options.bitdepth, [8, 10, 12])) {
1103
- if (options.bitdepth !== 8 && this.constructor.versions.heif) {
1104
- throw is.invalidParameterError('bitdepth when using prebuilt binaries', 8, options.bitdepth);
1105
- }
1106
1293
  this.options.heifBitdepth = options.bitdepth;
1107
1294
  } else {
1108
1295
  throw is.invalidParameterError('bitdepth', '8, 10 or 12', options.bitdepth);
1109
1296
  }
1110
1297
  }
1298
+ if (is.defined(options.tune)) {
1299
+ if (is.string(options.tune) && is.inArray(options.tune, ['auto', 'iq', 'psnr', 'ssim'])) {
1300
+ if (this.options.heifLossless && options.tune === 'iq') {
1301
+ this.options.heifTune = 'ssim';
1302
+ } else {
1303
+ this.options.heifTune = options.tune;
1304
+ }
1305
+ } else {
1306
+ throw is.invalidParameterError('tune', 'one of: auto, iq, psnr, ssim', options.tune);
1307
+ }
1308
+ }
1111
1309
  } else {
1112
1310
  throw is.invalidParameterError('options', 'Object', options);
1113
1311
  }
@@ -1121,9 +1319,7 @@ function heif (options) {
1121
1319
  *
1122
1320
  * Requires libvips compiled with support for libjxl.
1123
1321
  * The prebuilt binaries do not include this - see
1124
- * {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}.
1125
- *
1126
- * Image metadata (EXIF, XMP) is unsupported.
1322
+ * {@link /install/#custom-libvips installing a custom libvips}.
1127
1323
  *
1128
1324
  * @since 0.31.3
1129
1325
  *
@@ -1132,7 +1328,9 @@ function heif (options) {
1132
1328
  * @param {number} [options.quality] - calculate `distance` based on JPEG-like quality, between 1 and 100, overrides distance if specified
1133
1329
  * @param {number} [options.decodingTier=0] - target decode speed tier, between 0 (highest quality) and 4 (lowest quality)
1134
1330
  * @param {boolean} [options.lossless=false] - use lossless compression
1135
- * @param {number} [options.effort=7] - CPU effort, between 3 (fastest) and 9 (slowest)
1331
+ * @param {number} [options.effort=7] - CPU effort, between 1 (fastest) and 9 (slowest)
1332
+ * @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation
1333
+ * @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
1136
1334
  * @returns {Sharp}
1137
1335
  * @throws {Error} Invalid options
1138
1336
  */
@@ -1169,13 +1367,14 @@ function jxl (options) {
1169
1367
  }
1170
1368
  }
1171
1369
  if (is.defined(options.effort)) {
1172
- if (is.integer(options.effort) && is.inRange(options.effort, 3, 9)) {
1370
+ if (is.integer(options.effort) && is.inRange(options.effort, 1, 9)) {
1173
1371
  this.options.jxlEffort = options.effort;
1174
1372
  } else {
1175
- throw is.invalidParameterError('effort', 'integer between 3 and 9', options.effort);
1373
+ throw is.invalidParameterError('effort', 'integer between 1 and 9', options.effort);
1176
1374
  }
1177
1375
  }
1178
1376
  }
1377
+ trySetAnimationOptions(options, this.options);
1179
1378
  return this._updateFormatOut('jxl', options);
1180
1379
  }
1181
1380
 
@@ -1227,10 +1426,6 @@ function raw (options) {
1227
1426
  *
1228
1427
  * The container will be set to `zip` when the output is a Buffer or Stream, otherwise it will default to `fs`.
1229
1428
  *
1230
- * Requires libvips compiled with support for libgsf.
1231
- * The prebuilt binaries do not include this - see
1232
- * {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}.
1233
- *
1234
1429
  * @example
1235
1430
  * sharp('input.tiff')
1236
1431
  * .png()
@@ -1437,7 +1632,6 @@ function _setBooleanOption (key, val) {
1437
1632
  * @private
1438
1633
  */
1439
1634
  function _read () {
1440
- /* istanbul ignore else */
1441
1635
  if (!this.options.streamOut) {
1442
1636
  this.options.streamOut = true;
1443
1637
  const stack = Error();
@@ -1551,18 +1745,25 @@ function _pipeline (callback, stack) {
1551
1745
 
1552
1746
  /**
1553
1747
  * Decorate the Sharp prototype with output-related functions.
1748
+ * @module Sharp
1554
1749
  * @private
1555
1750
  */
1556
- module.exports = function (Sharp) {
1751
+ module.exports = (Sharp) => {
1557
1752
  Object.assign(Sharp.prototype, {
1558
1753
  // Public
1559
1754
  toFile,
1560
1755
  toBuffer,
1756
+ toUint8Array,
1757
+ withDensity,
1561
1758
  keepExif,
1562
1759
  withExif,
1563
1760
  withExifMerge,
1564
1761
  keepIccProfile,
1565
1762
  withIccProfile,
1763
+ keepGainMap,
1764
+ withGainMap,
1765
+ keepXmp,
1766
+ withXmp,
1566
1767
  keepMetadata,
1567
1768
  withMetadata,
1568
1769
  toFormat,