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,32 +1,48 @@
1
- // Copyright 2013 Lovell Fuller and others.
2
- // SPDX-License-Identifier: Apache-2.0
1
+ /*!
2
+ Copyright 2013 Lovell Fuller and others.
3
+ SPDX-License-Identifier: Apache-2.0
4
+ */
3
5
 
4
- 'use strict';
5
-
6
- const color = require('color');
7
- const is = require('./is');
8
- const sharp = require('./sharp');
6
+ import is from './is.mjs';
7
+ import sharp from './sharp.mjs';
9
8
 
10
9
  /**
11
- * Justication alignment
10
+ * Justification alignment
12
11
  * @member
13
12
  * @private
14
13
  */
15
14
  const align = {
16
15
  left: 'low',
16
+ top: 'low',
17
+ low: 'low',
17
18
  center: 'centre',
18
19
  centre: 'centre',
19
- right: 'high'
20
+ right: 'high',
21
+ bottom: 'high',
22
+ high: 'high'
20
23
  };
21
24
 
25
+ const inputStreamParameters = [
26
+ // Limits and error handling
27
+ 'failOn', 'limitInputPixels', 'limitInputChannels', 'unlimited',
28
+ // Format-generic
29
+ 'animated', 'autoOrient', 'density', 'ignoreIcc', 'page', 'pages', 'sequentialRead',
30
+ // Format-specific
31
+ 'jp2', 'openSlide', 'pdf', 'raw', 'svg', 'tiff',
32
+ // Deprecated
33
+ 'openSlideLevel', 'pdfBackground', 'tiffSubifd'
34
+ ];
35
+
22
36
  /**
23
37
  * Extract input options, if any, from an object.
24
38
  * @private
25
39
  */
26
40
  function _inputOptionsFromObject (obj) {
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 }
41
+ const params = inputStreamParameters
42
+ .filter(p => is.defined(obj[p]))
43
+ .map(p => ([p, obj[p]]));
44
+ return params.length
45
+ ? Object.fromEntries(params)
30
46
  : undefined;
31
47
  }
32
48
 
@@ -36,8 +52,10 @@ function _inputOptionsFromObject (obj) {
36
52
  */
37
53
  function _createInputDescriptor (input, inputOptions, containerOptions) {
38
54
  const inputDescriptor = {
55
+ autoOrient: false,
39
56
  failOn: 'warning',
40
- limitInputPixels: Math.pow(0x3FFF, 2),
57
+ limitInputPixels: 0x3FFF ** 2,
58
+ limitInputChannels: 5,
41
59
  ignoreIcc: false,
42
60
  unlimited: false,
43
61
  sequentialRead: true
@@ -71,20 +89,24 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
71
89
  } else if (!is.defined(input) && !is.defined(inputOptions) && is.object(containerOptions) && containerOptions.allowStream) {
72
90
  // Stream without options
73
91
  inputDescriptor.buffer = [];
92
+ } else if (Array.isArray(input)) {
93
+ if (input.length > 1) {
94
+ // Join images together
95
+ if (!this.options.joining) {
96
+ this.options.joining = true;
97
+ this.options.join = input.map(i => this._createInputDescriptor(i));
98
+ } else {
99
+ throw new Error('Recursive join is unsupported');
100
+ }
101
+ } else {
102
+ throw new Error('Expected at least two images to join');
103
+ }
74
104
  } else {
75
105
  throw new Error(`Unsupported input '${input}' of type ${typeof input}${
76
106
  is.defined(inputOptions) ? ` when also providing options of type ${typeof inputOptions}` : ''
77
107
  }`);
78
108
  }
79
109
  if (is.object(inputOptions)) {
80
- // Deprecated: failOnError
81
- if (is.defined(inputOptions.failOnError)) {
82
- if (is.bool(inputOptions.failOnError)) {
83
- inputDescriptor.failOn = inputOptions.failOnError ? 'warning' : 'none';
84
- } else {
85
- throw is.invalidParameterError('failOnError', 'boolean', inputOptions.failOnError);
86
- }
87
- }
88
110
  // failOn
89
111
  if (is.defined(inputOptions.failOn)) {
90
112
  if (is.string(inputOptions.failOn) && is.inArray(inputOptions.failOn, ['none', 'truncated', 'error', 'warning'])) {
@@ -93,9 +115,17 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
93
115
  throw is.invalidParameterError('failOn', 'one of: none, truncated, error, warning', inputOptions.failOn);
94
116
  }
95
117
  }
118
+ // autoOrient
119
+ if (is.defined(inputOptions.autoOrient)) {
120
+ if (is.bool(inputOptions.autoOrient)) {
121
+ inputDescriptor.autoOrient = inputOptions.autoOrient;
122
+ } else {
123
+ throw is.invalidParameterError('autoOrient', 'boolean', inputOptions.autoOrient);
124
+ }
125
+ }
96
126
  // Density
97
127
  if (is.defined(inputOptions.density)) {
98
- if (is.inRange(inputOptions.density, 1, 100000)) {
128
+ if (is.number(inputOptions.density) && is.inRange(inputOptions.density, 1, 100000)) {
99
129
  inputDescriptor.density = inputOptions.density;
100
130
  } else {
101
131
  throw is.invalidParameterError('density', 'number between 1 and 100000', inputOptions.density);
@@ -113,7 +143,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
113
143
  if (is.defined(inputOptions.limitInputPixels)) {
114
144
  if (is.bool(inputOptions.limitInputPixels)) {
115
145
  inputDescriptor.limitInputPixels = inputOptions.limitInputPixels
116
- ? Math.pow(0x3FFF, 2)
146
+ ? 0x3FFF ** 2
117
147
  : 0;
118
148
  } else if (is.integer(inputOptions.limitInputPixels) && is.inRange(inputOptions.limitInputPixels, 0, Number.MAX_SAFE_INTEGER)) {
119
149
  inputDescriptor.limitInputPixels = inputOptions.limitInputPixels;
@@ -121,6 +151,16 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
121
151
  throw is.invalidParameterError('limitInputPixels', 'positive integer', inputOptions.limitInputPixels);
122
152
  }
123
153
  }
154
+ // limitInputChannels
155
+ if (is.defined(inputOptions.limitInputChannels)) {
156
+ if (is.bool(inputOptions.limitInputChannels)) {
157
+ inputDescriptor.limitInputChannels = inputOptions.limitInputChannels ? 5 : 0;
158
+ } else if (is.integer(inputOptions.limitInputChannels) && is.inRange(inputOptions.limitInputChannels, 0, Number.MAX_SAFE_INTEGER)) {
159
+ inputDescriptor.limitInputChannels = inputOptions.limitInputChannels;
160
+ } else {
161
+ throw is.invalidParameterError('limitInputChannels', 'positive integer', inputOptions.limitInputChannels);
162
+ }
163
+ }
124
164
  // unlimited
125
165
  if (is.defined(inputOptions.unlimited)) {
126
166
  if (is.bool(inputOptions.unlimited)) {
@@ -141,15 +181,13 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
141
181
  if (is.defined(inputOptions.raw)) {
142
182
  if (
143
183
  is.object(inputOptions.raw) &&
144
- is.integer(inputOptions.raw.width) && inputOptions.raw.width > 0 &&
145
- is.integer(inputOptions.raw.height) && inputOptions.raw.height > 0 &&
184
+ is.integer(inputOptions.raw.width) && is.inRange(inputOptions.raw.width, 1, 100000000) &&
185
+ is.integer(inputOptions.raw.height) && is.inRange(inputOptions.raw.height, 1, 100000000) &&
146
186
  is.integer(inputOptions.raw.channels) && is.inRange(inputOptions.raw.channels, 1, 4)
147
187
  ) {
148
188
  inputDescriptor.rawWidth = inputOptions.raw.width;
149
189
  inputDescriptor.rawHeight = inputOptions.raw.height;
150
190
  inputDescriptor.rawChannels = inputOptions.raw.channels;
151
- inputDescriptor.rawPremultiplied = !!inputOptions.raw.premultiplied;
152
-
153
191
  switch (input.constructor) {
154
192
  case Uint8Array:
155
193
  case Uint8ClampedArray:
@@ -183,6 +221,25 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
183
221
  } else {
184
222
  throw new Error('Expected width, height and channels for raw pixel input');
185
223
  }
224
+ inputDescriptor.rawPremultiplied = false;
225
+ if (is.defined(inputOptions.raw.premultiplied)) {
226
+ if (is.bool(inputOptions.raw.premultiplied)) {
227
+ inputDescriptor.rawPremultiplied = inputOptions.raw.premultiplied;
228
+ } else {
229
+ throw is.invalidParameterError('raw.premultiplied', 'boolean', inputOptions.raw.premultiplied);
230
+ }
231
+ }
232
+ inputDescriptor.rawPageHeight = 0;
233
+ if (is.defined(inputOptions.raw.pageHeight)) {
234
+ if (is.integer(inputOptions.raw.pageHeight) && inputOptions.raw.pageHeight > 0 && inputOptions.raw.pageHeight <= inputOptions.raw.height) {
235
+ if (inputOptions.raw.height % inputOptions.raw.pageHeight !== 0) {
236
+ throw new Error(`Expected raw.height ${inputOptions.raw.height} to be a multiple of raw.pageHeight ${inputOptions.raw.pageHeight}`);
237
+ }
238
+ inputDescriptor.rawPageHeight = inputOptions.raw.pageHeight;
239
+ } else {
240
+ throw is.invalidParameterError('raw.pageHeight', 'positive integer', inputOptions.raw.pageHeight);
241
+ }
242
+ }
186
243
  }
187
244
  // Multi-page input (GIF, TIFF, PDF)
188
245
  if (is.defined(inputOptions.animated)) {
@@ -206,66 +263,123 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
206
263
  throw is.invalidParameterError('page', 'integer between 0 and 100000', inputOptions.page);
207
264
  }
208
265
  }
209
- // Multi-level input (OpenSlide)
210
- if (is.defined(inputOptions.level)) {
266
+ // OpenSlide specific options
267
+ if (is.object(inputOptions.openSlide) && is.defined(inputOptions.openSlide.level)) {
268
+ if (is.integer(inputOptions.openSlide.level) && is.inRange(inputOptions.openSlide.level, 0, 256)) {
269
+ inputDescriptor.openSlideLevel = inputOptions.openSlide.level;
270
+ } else {
271
+ throw is.invalidParameterError('openSlide.level', 'integer between 0 and 256', inputOptions.openSlide.level);
272
+ }
273
+ } else if (is.defined(inputOptions.level)) {
274
+ // Deprecated
211
275
  if (is.integer(inputOptions.level) && is.inRange(inputOptions.level, 0, 256)) {
212
- inputDescriptor.level = inputOptions.level;
276
+ inputDescriptor.openSlideLevel = inputOptions.level;
213
277
  } else {
214
278
  throw is.invalidParameterError('level', 'integer between 0 and 256', inputOptions.level);
215
279
  }
216
280
  }
217
- // Sub Image File Directory (TIFF)
218
- if (is.defined(inputOptions.subifd)) {
281
+ // TIFF specific options
282
+ if (is.object(inputOptions.tiff) && is.defined(inputOptions.tiff.subifd)) {
283
+ if (is.integer(inputOptions.tiff.subifd) && is.inRange(inputOptions.tiff.subifd, -1, 100000)) {
284
+ inputDescriptor.tiffSubifd = inputOptions.tiff.subifd;
285
+ } else {
286
+ throw is.invalidParameterError('tiff.subifd', 'integer between -1 and 100000', inputOptions.tiff.subifd);
287
+ }
288
+ } else if (is.defined(inputOptions.subifd)) {
289
+ // Deprecated
219
290
  if (is.integer(inputOptions.subifd) && is.inRange(inputOptions.subifd, -1, 100000)) {
220
- inputDescriptor.subifd = inputOptions.subifd;
291
+ inputDescriptor.tiffSubifd = inputOptions.subifd;
221
292
  } else {
222
293
  throw is.invalidParameterError('subifd', 'integer between -1 and 100000', inputOptions.subifd);
223
294
  }
224
295
  }
296
+ // SVG specific options
297
+ if (is.object(inputOptions.svg)) {
298
+ if (is.defined(inputOptions.svg.stylesheet)) {
299
+ if (is.string(inputOptions.svg.stylesheet)) {
300
+ inputDescriptor.svgStylesheet = inputOptions.svg.stylesheet;
301
+ } else {
302
+ throw is.invalidParameterError('svg.stylesheet', 'string', inputOptions.svg.stylesheet);
303
+ }
304
+ }
305
+ if (is.defined(inputOptions.svg.highBitdepth)) {
306
+ if (is.bool(inputOptions.svg.highBitdepth)) {
307
+ inputDescriptor.svgHighBitdepth = inputOptions.svg.highBitdepth;
308
+ } else {
309
+ throw is.invalidParameterError('svg.highBitdepth', 'boolean', inputOptions.svg.highBitdepth);
310
+ }
311
+ }
312
+ }
313
+ // PDF specific options
314
+ if (is.object(inputOptions.pdf) && is.defined(inputOptions.pdf.background)) {
315
+ inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdf.background);
316
+ } else if (is.defined(inputOptions.pdfBackground)) {
317
+ // Deprecated
318
+ inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdfBackground);
319
+ }
320
+ // JPEG 2000 specific options
321
+ if (is.object(inputOptions.jp2) && is.defined(inputOptions.jp2.oneshot)) {
322
+ if (is.bool(inputOptions.jp2.oneshot)) {
323
+ inputDescriptor.jp2Oneshot = inputOptions.jp2.oneshot;
324
+ } else {
325
+ throw is.invalidParameterError('jp2.oneshot', 'boolean', inputOptions.jp2.oneshot);
326
+ }
327
+ }
225
328
  // Create new image
226
329
  if (is.defined(inputOptions.create)) {
227
330
  if (
228
331
  is.object(inputOptions.create) &&
229
- is.integer(inputOptions.create.width) && inputOptions.create.width > 0 &&
230
- is.integer(inputOptions.create.height) && inputOptions.create.height > 0 &&
332
+ is.integer(inputOptions.create.width) && is.inRange(inputOptions.create.width, 1, 100000000) &&
333
+ is.integer(inputOptions.create.height) && is.inRange(inputOptions.create.height, 1, 100000000) &&
231
334
  is.integer(inputOptions.create.channels)
232
335
  ) {
233
336
  inputDescriptor.createWidth = inputOptions.create.width;
234
337
  inputDescriptor.createHeight = inputOptions.create.height;
235
338
  inputDescriptor.createChannels = inputOptions.create.channels;
339
+ inputDescriptor.createPageHeight = 0;
340
+ if (is.defined(inputOptions.create.pageHeight)) {
341
+ if (is.integer(inputOptions.create.pageHeight) && inputOptions.create.pageHeight > 0 && inputOptions.create.pageHeight <= inputOptions.create.height) {
342
+ if (inputOptions.create.height % inputOptions.create.pageHeight !== 0) {
343
+ throw new Error(`Expected create.height ${inputOptions.create.height} to be a multiple of create.pageHeight ${inputOptions.create.pageHeight}`);
344
+ }
345
+ inputDescriptor.createPageHeight = inputOptions.create.pageHeight;
346
+ } else {
347
+ throw is.invalidParameterError('create.pageHeight', 'positive integer', inputOptions.create.pageHeight);
348
+ }
349
+ }
236
350
  // Noise
237
351
  if (is.defined(inputOptions.create.noise)) {
238
352
  if (!is.object(inputOptions.create.noise)) {
239
353
  throw new Error('Expected noise to be an object');
240
354
  }
241
- if (!is.inArray(inputOptions.create.noise.type, ['gaussian'])) {
355
+ if (inputOptions.create.noise.type !== 'gaussian') {
242
356
  throw new Error('Only gaussian noise is supported at the moment');
243
357
  }
358
+ inputDescriptor.createNoiseType = inputOptions.create.noise.type;
244
359
  if (!is.inRange(inputOptions.create.channels, 1, 4)) {
245
360
  throw is.invalidParameterError('create.channels', 'number between 1 and 4', inputOptions.create.channels);
246
361
  }
247
- inputDescriptor.createNoiseType = inputOptions.create.noise.type;
248
- if (is.number(inputOptions.create.noise.mean) && is.inRange(inputOptions.create.noise.mean, 0, 10000)) {
249
- inputDescriptor.createNoiseMean = inputOptions.create.noise.mean;
250
- } else {
251
- throw is.invalidParameterError('create.noise.mean', 'number between 0 and 10000', inputOptions.create.noise.mean);
362
+ inputDescriptor.createNoiseMean = 128;
363
+ if (is.defined(inputOptions.create.noise.mean)) {
364
+ if (is.number(inputOptions.create.noise.mean) && is.inRange(inputOptions.create.noise.mean, 0, 10000)) {
365
+ inputDescriptor.createNoiseMean = inputOptions.create.noise.mean;
366
+ } else {
367
+ throw is.invalidParameterError('create.noise.mean', 'number between 0 and 10000', inputOptions.create.noise.mean);
368
+ }
252
369
  }
253
- if (is.number(inputOptions.create.noise.sigma) && is.inRange(inputOptions.create.noise.sigma, 0, 10000)) {
254
- inputDescriptor.createNoiseSigma = inputOptions.create.noise.sigma;
255
- } else {
256
- throw is.invalidParameterError('create.noise.sigma', 'number between 0 and 10000', inputOptions.create.noise.sigma);
370
+ inputDescriptor.createNoiseSigma = 30;
371
+ if (is.defined(inputOptions.create.noise.sigma)) {
372
+ if (is.number(inputOptions.create.noise.sigma) && is.inRange(inputOptions.create.noise.sigma, 0, 10000)) {
373
+ inputDescriptor.createNoiseSigma = inputOptions.create.noise.sigma;
374
+ } else {
375
+ throw is.invalidParameterError('create.noise.sigma', 'number between 0 and 10000', inputOptions.create.noise.sigma);
376
+ }
257
377
  }
258
378
  } else if (is.defined(inputOptions.create.background)) {
259
379
  if (!is.inRange(inputOptions.create.channels, 3, 4)) {
260
380
  throw is.invalidParameterError('create.channels', 'number between 3 and 4', inputOptions.create.channels);
261
381
  }
262
- const background = color(inputOptions.create.background);
263
- inputDescriptor.createBackground = [
264
- background.red(),
265
- background.green(),
266
- background.blue(),
267
- Math.round(background.alpha() * 255)
268
- ];
382
+ inputDescriptor.createBackground = this._getBackgroundColourOption(inputOptions.create.background);
269
383
  } else {
270
384
  throw new Error('Expected valid noise or background to create a new input image');
271
385
  }
@@ -296,17 +410,17 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
296
410
  }
297
411
  }
298
412
  if (is.defined(inputOptions.text.width)) {
299
- if (is.integer(inputOptions.text.width) && inputOptions.text.width > 0) {
413
+ if (is.integer(inputOptions.text.width) && is.inRange(inputOptions.text.width, 1, 1000000)) {
300
414
  inputDescriptor.textWidth = inputOptions.text.width;
301
415
  } else {
302
- throw is.invalidParameterError('text.width', 'positive integer', inputOptions.text.width);
416
+ throw is.invalidParameterError('text.width', 'integer between 1 and 1000000', inputOptions.text.width);
303
417
  }
304
418
  }
305
419
  if (is.defined(inputOptions.text.height)) {
306
- if (is.integer(inputOptions.text.height) && inputOptions.text.height > 0) {
420
+ if (is.integer(inputOptions.text.height) && is.inRange(inputOptions.text.height, 1, 1000000)) {
307
421
  inputDescriptor.textHeight = inputOptions.text.height;
308
422
  } else {
309
- throw is.invalidParameterError('text.height', 'positive integer', inputOptions.text.height);
423
+ throw is.invalidParameterError('text.height', 'integer between 1 and 1000000', inputOptions.text.height);
310
424
  }
311
425
  }
312
426
  if (is.defined(inputOptions.text.align)) {
@@ -356,8 +470,53 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
356
470
  throw new Error('Expected a valid string to create an image with text.');
357
471
  }
358
472
  }
473
+ // Join images together
474
+ if (is.defined(inputOptions.join)) {
475
+ if (is.defined(this.options.join)) {
476
+ if (is.defined(inputOptions.join.animated)) {
477
+ if (is.bool(inputOptions.join.animated)) {
478
+ inputDescriptor.joinAnimated = inputOptions.join.animated;
479
+ } else {
480
+ throw is.invalidParameterError('join.animated', 'boolean', inputOptions.join.animated);
481
+ }
482
+ }
483
+ if (is.defined(inputOptions.join.across)) {
484
+ if (is.integer(inputOptions.join.across) && is.inRange(inputOptions.join.across, 1, 1000000)) {
485
+ inputDescriptor.joinAcross = inputOptions.join.across;
486
+ } else {
487
+ throw is.invalidParameterError('join.across', 'integer between 1 and 100000', inputOptions.join.across);
488
+ }
489
+ }
490
+ if (is.defined(inputOptions.join.shim)) {
491
+ if (is.integer(inputOptions.join.shim) && is.inRange(inputOptions.join.shim, 0, 1000000)) {
492
+ inputDescriptor.joinShim = inputOptions.join.shim;
493
+ } else {
494
+ throw is.invalidParameterError('join.shim', 'integer between 0 and 100000', inputOptions.join.shim);
495
+ }
496
+ }
497
+ if (is.defined(inputOptions.join.background)) {
498
+ inputDescriptor.joinBackground = this._getBackgroundColourOption(inputOptions.join.background);
499
+ }
500
+ if (is.defined(inputOptions.join.halign)) {
501
+ if (is.string(inputOptions.join.halign) && is.string(this.constructor.align[inputOptions.join.halign])) {
502
+ inputDescriptor.joinHalign = this.constructor.align[inputOptions.join.halign];
503
+ } else {
504
+ throw is.invalidParameterError('join.halign', 'valid alignment', inputOptions.join.halign);
505
+ }
506
+ }
507
+ if (is.defined(inputOptions.join.valign)) {
508
+ if (is.string(inputOptions.join.valign) && is.string(this.constructor.align[inputOptions.join.valign])) {
509
+ inputDescriptor.joinValign = this.constructor.align[inputOptions.join.valign];
510
+ } else {
511
+ throw is.invalidParameterError('join.valign', 'valid alignment', inputOptions.join.valign);
512
+ }
513
+ }
514
+ } else {
515
+ throw new Error('Expected input to be an array of images to join');
516
+ }
517
+ }
359
518
  } else if (is.defined(inputOptions)) {
360
- throw new Error('Invalid input options ' + inputOptions);
519
+ throw new Error(`Invalid input options ${inputOptions}`);
361
520
  }
362
521
  return inputDescriptor;
363
522
  }
@@ -369,10 +528,8 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
369
528
  * @param {string} encoding - unused
370
529
  * @param {Function} callback
371
530
  */
372
- function _write (chunk, encoding, callback) {
373
- /* istanbul ignore else */
531
+ function _write (chunk, _encoding, callback) {
374
532
  if (Array.isArray(this.options.input.buffer)) {
375
- /* istanbul ignore else */
376
533
  if (is.buffer(chunk)) {
377
534
  if (this.options.input.buffer.length === 0) {
378
535
  this.on('finish', () => {
@@ -416,29 +573,31 @@ function _isStreamInput () {
416
573
  * such as resize or rotate.
417
574
  *
418
575
  * Dimensions in the response will respect the `page` and `pages` properties of the
419
- * {@link /api-constructor#parameters|constructor parameters}.
576
+ * {@link /api-constructor/ constructor parameters}.
420
577
  *
421
578
  * A `Promise` is returned when `callback` is not provided.
422
579
  *
423
- * - `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
580
+ * - `format`: Name of decoder used to parse image e.g. `jpeg`, `png`, `webp`, `gif`, `svg`, `heif`, `tiff`
581
+ * - `mediaType`: Media Type (MIME Type) e.g. `image/jpeg`, `image/png`, `image/svg+xml`, `image/avif`
424
582
  * - `size`: Total size of image in bytes, for Stream and Buffer input only
425
583
  * - `width`: Number of pixels wide (EXIF orientation is not taken into consideration, see example below)
426
584
  * - `height`: Number of pixels high (EXIF orientation is not taken into consideration, see example below)
427
- * - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://www.libvips.org/API/current/VipsImage.html#VipsInterpretation)
585
+ * - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://www.libvips.org/API/current/enum.Interpretation.html)
428
586
  * - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
429
- * - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://www.libvips.org/API/current/VipsImage.html#VipsBandFormat)
587
+ * - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://www.libvips.org/API/current/enum.BandFormat.html)
430
588
  * - `density`: Number of pixels per inch (DPI), if present
431
589
  * - `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK
432
590
  * - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
591
+ * - `isPalette`: Boolean indicating whether the image is palette-based (GIF, PNG).
592
+ * - `bitsPerSample`: Number of bits per sample for each channel (GIF, PNG, HEIF).
433
593
  * - `pages`: Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP
434
594
  * - `pageHeight`: Number of pixels high each page in a multi-page image will be.
435
- * - `paletteBitDepth`: Bit depth of palette-based image (GIF, PNG).
436
595
  * - `loop`: Number of times to loop an animated image, zero refers to a continuous loop.
437
596
  * - `delay`: Delay in ms between each page in an animated image, provided as an array of integers.
438
597
  * - `pagePrimary`: Number of the primary page in a HEIF image
439
598
  * - `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide
440
599
  * - `subifds`: Number of Sub Image File Directories in an OME-TIFF image
441
- * - `background`: Default background colour, if present, for PNG (bKGD) and GIF images, either an RGB Object or a single greyscale value
600
+ * - `background`: Default background colour, if present, for PNG (bKGD) and GIF images
442
601
  * - `compression`: The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC)
443
602
  * - `resolutionUnit`: The unit of resolution (density), either `inch` or `cm`, if present
444
603
  * - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
@@ -448,9 +607,11 @@ function _isStreamInput () {
448
607
  * - `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present
449
608
  * - `iptc`: Buffer containing raw IPTC data, if present
450
609
  * - `xmp`: Buffer containing raw XMP data, if present
610
+ * - `xmpAsString`: String containing XMP data, if valid UTF-8.
451
611
  * - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
452
612
  * - `formatMagick`: String containing format for images loaded via *magick
453
613
  * - `comments`: Array of keyword/text pairs representing PNG text blocks, if present.
614
+ * - `gainMap.image`: HDR gain map, if present, as compressed JPEG image.
454
615
  *
455
616
  * @example
456
617
  * const metadata = await sharp(input).metadata();
@@ -470,15 +631,9 @@ function _isStreamInput () {
470
631
  * });
471
632
  *
472
633
  * @example
473
- * // Based on EXIF rotation metadata, get the right-side-up width and height:
474
- *
475
- * const size = getNormalSize(await sharp(input).metadata());
476
- *
477
- * function getNormalSize({ width, height, orientation }) {
478
- * return (orientation || 0) >= 5
479
- * ? { width: height, height: width }
480
- * : { width, height };
481
- * }
634
+ * // Get dimensions taking EXIF Orientation into account.
635
+ * const { autoOrient } = await sharp(input).metadata();
636
+ * const { width, height } = autoOrient;
482
637
  *
483
638
  * @param {Function} [callback] - called with the arguments `(err, metadata)`
484
639
  * @returns {Promise<Object>|Sharp}
@@ -639,9 +794,10 @@ function stats (callback) {
639
794
 
640
795
  /**
641
796
  * Decorate the Sharp prototype with input-related functions.
797
+ * @module Sharp
642
798
  * @private
643
799
  */
644
- module.exports = function (Sharp) {
800
+ export default (Sharp) => {
645
801
  Object.assign(Sharp.prototype, {
646
802
  // Private
647
803
  _inputOptionsFromObject,
@@ -1,61 +1,49 @@
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
  /**
7
7
  * Is this value defined and not null?
8
8
  * @private
9
9
  */
10
- const defined = function (val) {
11
- return typeof val !== 'undefined' && val !== null;
12
- };
10
+ const defined = (val) => typeof val !== 'undefined' && val !== null;
13
11
 
14
12
  /**
15
13
  * Is this value an object?
16
14
  * @private
17
15
  */
18
- const object = function (val) {
19
- return typeof val === 'object';
20
- };
16
+ const object = (val) => typeof val === 'object';
21
17
 
22
18
  /**
23
19
  * Is this value a plain object?
24
20
  * @private
25
21
  */
26
- const plainObject = function (val) {
27
- return Object.prototype.toString.call(val) === '[object Object]';
28
- };
22
+ const plainObject = (val) => Object.prototype.toString.call(val) === '[object Object]';
29
23
 
30
24
  /**
31
25
  * Is this value a function?
32
26
  * @private
33
27
  */
34
- const fn = function (val) {
35
- return typeof val === 'function';
36
- };
28
+ const fn = (val) => typeof val === 'function';
37
29
 
38
30
  /**
39
31
  * Is this value a boolean?
40
32
  * @private
41
33
  */
42
- const bool = function (val) {
43
- return typeof val === 'boolean';
44
- };
34
+ const bool = (val) => typeof val === 'boolean';
45
35
 
46
36
  /**
47
37
  * Is this value a Buffer object?
48
38
  * @private
49
39
  */
50
- const buffer = function (val) {
51
- return val instanceof Buffer;
52
- };
40
+ const buffer = (val) => val instanceof Buffer;
53
41
 
54
42
  /**
55
43
  * Is this value a typed array object?. E.g. Uint8Array or Uint8ClampedArray?
56
44
  * @private
57
45
  */
58
- const typedArray = function (val) {
46
+ const typedArray = (val) => {
59
47
  if (defined(val)) {
60
48
  switch (val.constructor) {
61
49
  case Uint8Array:
@@ -78,49 +66,37 @@ const typedArray = function (val) {
78
66
  * Is this value an ArrayBuffer object?
79
67
  * @private
80
68
  */
81
- const arrayBuffer = function (val) {
82
- return val instanceof ArrayBuffer;
83
- };
69
+ const arrayBuffer = (val) => val instanceof ArrayBuffer;
84
70
 
85
71
  /**
86
72
  * Is this value a non-empty string?
87
73
  * @private
88
74
  */
89
- const string = function (val) {
90
- return typeof val === 'string' && val.length > 0;
91
- };
75
+ const string = (val) => typeof val === 'string' && val.length > 0;
92
76
 
93
77
  /**
94
78
  * Is this value a real number?
95
79
  * @private
96
80
  */
97
- const number = function (val) {
98
- return typeof val === 'number' && !Number.isNaN(val);
99
- };
81
+ const number = (val) => typeof val === 'number' && Number.isFinite(val);
100
82
 
101
83
  /**
102
84
  * Is this value an integer?
103
85
  * @private
104
86
  */
105
- const integer = function (val) {
106
- return Number.isInteger(val);
107
- };
87
+ const integer = (val) => Number.isInteger(val);
108
88
 
109
89
  /**
110
90
  * Is this value within an inclusive given range?
111
91
  * @private
112
92
  */
113
- const inRange = function (val, min, max) {
114
- return val >= min && val <= max;
115
- };
93
+ const inRange = (val, min, max) => val >= min && val <= max;
116
94
 
117
95
  /**
118
96
  * Is this value within the elements of an array?
119
97
  * @private
120
98
  */
121
- const inArray = function (val, list) {
122
- return list.includes(val);
123
- };
99
+ const inArray = (val, list) => list.includes(val);
124
100
 
125
101
  /**
126
102
  * Create an Error with a message relating to an invalid parameter.
@@ -131,11 +107,9 @@ const inArray = function (val, list) {
131
107
  * @returns {Error} Containing the formatted message.
132
108
  * @private
133
109
  */
134
- const invalidParameterError = function (name, expected, actual) {
135
- return new Error(
110
+ const invalidParameterError = (name, expected, actual) => new Error(
136
111
  `Expected ${expected} for ${name} but received ${actual} of type ${typeof actual}`
137
112
  );
138
- };
139
113
 
140
114
  /**
141
115
  * Ensures an Error from C++ contains a JS stack.
@@ -145,7 +119,7 @@ const invalidParameterError = function (name, expected, actual) {
145
119
  * @returns {Error} Error with message and stack.
146
120
  * @private
147
121
  */
148
- const nativeError = function (native, context) {
122
+ const nativeError = (native, context) => {
149
123
  context.message = native.message;
150
124
  return context;
151
125
  };