@depup/sharp 0.34.5-depup.0 → 0.35.4-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +16 -109
  2. package/changes.json +5 -0
  3. package/{lib/channel.js → dist/channel.cjs} +1 -1
  4. package/dist/channel.mjs +177 -0
  5. package/{lib/colour.js → dist/colour.cjs} +11 -7
  6. package/dist/colour.mjs +199 -0
  7. package/{lib/composite.js → dist/composite.cjs} +8 -7
  8. package/dist/composite.mjs +213 -0
  9. package/{lib/constructor.js → dist/constructor.cjs} +42 -30
  10. package/dist/constructor.mjs +511 -0
  11. package/dist/index.cjs +25 -0
  12. package/dist/index.d.cts +1999 -0
  13. package/dist/index.d.mts +2046 -0
  14. package/dist/index.mjs +25 -0
  15. package/{lib/input.js → dist/input.cjs} +47 -37
  16. package/dist/input.mjs +819 -0
  17. package/{lib/is.js → dist/is.cjs} +1 -1
  18. package/dist/is.mjs +143 -0
  19. package/{lib/libvips.js → dist/libvips.cjs} +35 -30
  20. package/dist/libvips.mjs +212 -0
  21. package/{lib/operation.js → dist/operation.cjs} +37 -51
  22. package/dist/operation.mjs +1002 -0
  23. package/{lib/output.js → dist/output.cjs} +166 -47
  24. package/dist/output.mjs +1785 -0
  25. package/{lib/resize.js → dist/resize.cjs} +54 -32
  26. package/dist/resize.mjs +617 -0
  27. package/dist/sharp.cjs +174 -0
  28. package/dist/sharp.mjs +174 -0
  29. package/{lib/utility.js → dist/utility.cjs} +18 -8
  30. package/dist/utility.mjs +301 -0
  31. package/install/build.js +3 -3
  32. package/lib/index.d.ts +111 -83
  33. package/package.json +95 -54
  34. package/src/binding.gyp +19 -14
  35. package/src/common.cc +77 -21
  36. package/src/common.h +23 -4
  37. package/src/metadata.cc +66 -8
  38. package/src/metadata.h +6 -1
  39. package/src/operations.cc +25 -8
  40. package/src/operations.h +1 -1
  41. package/src/pipeline.cc +203 -69
  42. package/src/pipeline.h +15 -1
  43. package/src/stats.cc +6 -6
  44. package/src/utilities.cc +7 -6
  45. package/install/check.js +0 -14
  46. package/lib/index.js +0 -16
  47. package/lib/sharp.js +0 -121
@@ -0,0 +1,213 @@
1
+ /*!
2
+ Copyright 2013 Lovell Fuller and others.
3
+ SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import is from './is.mjs';
7
+
8
+ /**
9
+ * Blend modes.
10
+ * @member
11
+ * @private
12
+ */
13
+ const blend = {
14
+ clear: 'clear',
15
+ source: 'source',
16
+ over: 'over',
17
+ in: 'in',
18
+ out: 'out',
19
+ atop: 'atop',
20
+ dest: 'dest',
21
+ 'dest-over': 'dest-over',
22
+ 'dest-in': 'dest-in',
23
+ 'dest-out': 'dest-out',
24
+ 'dest-atop': 'dest-atop',
25
+ xor: 'xor',
26
+ add: 'add',
27
+ saturate: 'saturate',
28
+ multiply: 'multiply',
29
+ screen: 'screen',
30
+ overlay: 'overlay',
31
+ darken: 'darken',
32
+ lighten: 'lighten',
33
+ 'colour-dodge': 'colour-dodge',
34
+ 'color-dodge': 'colour-dodge',
35
+ 'colour-burn': 'colour-burn',
36
+ 'color-burn': 'colour-burn',
37
+ 'hard-light': 'hard-light',
38
+ 'soft-light': 'soft-light',
39
+ difference: 'difference',
40
+ exclusion: 'exclusion'
41
+ };
42
+
43
+ /**
44
+ * Composite image(s) over the processed (resized, extracted etc.) image.
45
+ *
46
+ * The images to composite must be the same size or smaller than the processed image.
47
+ * If both `top` and `left` options are provided, they take precedence over `gravity`.
48
+ *
49
+ * Other operations in the same processing pipeline (e.g. resize, rotate, flip,
50
+ * flop, extract) will always be applied to the input image before composition.
51
+ *
52
+ * The `blend` option can be one of `clear`, `source`, `over`, `in`, `out`, `atop`,
53
+ * `dest`, `dest-over`, `dest-in`, `dest-out`, `dest-atop`,
54
+ * `xor`, `add`, `saturate`, `multiply`, `screen`, `overlay`, `darken`, `lighten`,
55
+ * `colour-dodge`, `color-dodge`, `colour-burn`,`color-burn`,
56
+ * `hard-light`, `soft-light`, `difference`, `exclusion`.
57
+ *
58
+ * More information about blend modes can be found at
59
+ * https://www.libvips.org/API/current/enum.BlendMode.html
60
+ * and https://www.cairographics.org/operators/
61
+ *
62
+ * @since 0.22.0
63
+ *
64
+ * @example
65
+ * await sharp(background)
66
+ * .composite([
67
+ * { input: layer1, gravity: 'northwest' },
68
+ * { input: layer2, gravity: 'southeast' },
69
+ * ])
70
+ * .toFile('combined.png');
71
+ *
72
+ * @example
73
+ * const output = await sharp('input.gif', { animated: true })
74
+ * .composite([
75
+ * { input: 'overlay.png', tile: true, blend: 'saturate' }
76
+ * ])
77
+ * .toBuffer();
78
+ *
79
+ * @example
80
+ * sharp('input.png')
81
+ * .rotate(180)
82
+ * .resize(300)
83
+ * .flatten( { background: '#ff6600' } )
84
+ * .composite([{ input: 'overlay.png', gravity: 'southeast' }])
85
+ * .sharpen()
86
+ * .withMetadata()
87
+ * .webp( { quality: 90 } )
88
+ * .toBuffer()
89
+ * .then(function(outputBuffer) {
90
+ * // outputBuffer contains upside down, 300px wide, alpha channel flattened
91
+ * // onto orange background, composited with overlay.png with SE gravity,
92
+ * // sharpened, with metadata, 90% quality WebP image data. Phew!
93
+ * });
94
+ *
95
+ * @param {Object[]} images - Ordered list of images to composite
96
+ * @param {Buffer|String} [images[].input] - Buffer containing image data, String containing the path to an image file, or Create object (see below)
97
+ * @param {Object} [images[].input.create] - describes a blank overlay to be created.
98
+ * @param {Number} [images[].input.create.width]
99
+ * @param {Number} [images[].input.create.height]
100
+ * @param {Number} [images[].input.create.channels] - 3-4
101
+ * @param {String|Object} [images[].input.create.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
102
+ * @param {Object} [images[].input.text] - describes a new text image to be created.
103
+ * @param {string} [images[].input.text.text] - text to render as a UTF-8 string. It can contain Pango markup, for example `<i>Le</i>Monde`.
104
+ * @param {string} [images[].input.text.font] - font name to render with.
105
+ * @param {string} [images[].input.text.fontfile] - absolute filesystem path to a font file that can be used by `font`.
106
+ * @param {number} [images[].input.text.width=0] - integral number of pixels to word-wrap at. Lines of text wider than this will be broken at word boundaries.
107
+ * @param {number} [images[].input.text.height=0] - integral number of pixels high. When defined, `dpi` will be ignored and the text will automatically fit the pixel resolution defined by `width` and `height`. Will be ignored if `width` is not specified or set to 0.
108
+ * @param {string} [images[].input.text.align='left'] - text alignment (`'left'`, `'centre'`, `'center'`, `'right'`).
109
+ * @param {boolean} [images[].input.text.justify=false] - set this to true to apply justification to the text.
110
+ * @param {number} [images[].input.text.dpi=72] - the resolution (size) at which to render the text. Does not take effect if `height` is specified.
111
+ * @param {boolean} [images[].input.text.rgba=false] - set this to true to enable RGBA output. This is useful for colour emoji rendering, or support for Pango markup features like `<span foreground="red">Red!</span>`.
112
+ * @param {number} [images[].input.text.spacing=0] - text line height in points. Will use the font line height if none is specified.
113
+ * @param {Boolean} [images[].autoOrient=false] - set to true to use EXIF orientation data, if present, to orient the image.
114
+ * @param {String} [images[].blend='over'] - how to blend this image with the image below.
115
+ * @param {String} [images[].gravity='centre'] - gravity at which to place the overlay.
116
+ * @param {Number} [images[].top] - the pixel offset from the top edge, an integer between -100000000 and 100000000.
117
+ * @param {Number} [images[].left] - the pixel offset from the left edge, an integer between -100000000 and 100000000.
118
+ * @param {Boolean} [images[].tile=false] - set to true to repeat the overlay image across the entire image with the given `gravity`.
119
+ * @param {Boolean} [images[].premultiplied=false] - set to true to avoid premultiplying the image below. Equivalent to the `--premultiplied` vips option.
120
+ * @param {Number} [images[].density=72] - number representing the DPI for vector overlay image.
121
+ * @param {Object} [images[].raw] - describes overlay when using raw pixel data.
122
+ * @param {Number} [images[].raw.width]
123
+ * @param {Number} [images[].raw.height]
124
+ * @param {Number} [images[].raw.channels]
125
+ * @param {boolean} [images[].animated=false] - Set to `true` to read all frames/pages of an animated image.
126
+ * @param {string} [images[].failOn='warning'] - @see {@link /api-constructor/ constructor parameters}
127
+ * @param {number|boolean} [images[].limitInputPixels=268402689] - @see {@link /api-constructor/ constructor parameters}
128
+ * @param {number|boolean} [images[].limitInputChannels=5] - @see {@link /api-constructor/ constructor parameters}
129
+ * @returns {Sharp}
130
+ * @throws {Error} Invalid parameters
131
+ */
132
+ function composite (images) {
133
+ if (!Array.isArray(images)) {
134
+ throw is.invalidParameterError('images to composite', 'array', images);
135
+ }
136
+ this.options.composite = images.map(image => {
137
+ if (!is.object(image)) {
138
+ throw is.invalidParameterError('image to composite', 'object', image);
139
+ }
140
+ const inputOptions = this._inputOptionsFromObject(image);
141
+ const composite = {
142
+ input: this._createInputDescriptor(image.input, inputOptions, { allowStream: false }),
143
+ blend: 'over',
144
+ tile: false,
145
+ left: 0,
146
+ top: 0,
147
+ hasOffset: false,
148
+ gravity: 0,
149
+ premultiplied: false
150
+ };
151
+ if (is.defined(image.blend)) {
152
+ if (is.string(blend[image.blend])) {
153
+ composite.blend = blend[image.blend];
154
+ } else {
155
+ throw is.invalidParameterError('blend', 'valid blend name', image.blend);
156
+ }
157
+ }
158
+ if (is.defined(image.tile)) {
159
+ if (is.bool(image.tile)) {
160
+ composite.tile = image.tile;
161
+ } else {
162
+ throw is.invalidParameterError('tile', 'boolean', image.tile);
163
+ }
164
+ }
165
+ if (is.defined(image.left)) {
166
+ if (is.integer(image.left) && is.inRange(image.left, -100000000, 100000000)) {
167
+ composite.left = image.left;
168
+ } else {
169
+ throw is.invalidParameterError('left', 'integer between -100000000 and 100000000', image.left);
170
+ }
171
+ }
172
+ if (is.defined(image.top)) {
173
+ if (is.integer(image.top) && is.inRange(image.top, -100000000, 100000000)) {
174
+ composite.top = image.top;
175
+ } else {
176
+ throw is.invalidParameterError('top', 'integer between -100000000 and 100000000', image.top);
177
+ }
178
+ }
179
+ if (is.defined(image.top) !== is.defined(image.left)) {
180
+ throw new Error('Expected both left and top to be set');
181
+ } else {
182
+ composite.hasOffset = is.integer(image.top) && is.integer(image.left);
183
+ }
184
+ if (is.defined(image.gravity)) {
185
+ if (is.integer(image.gravity) && is.inRange(image.gravity, 0, 8)) {
186
+ composite.gravity = image.gravity;
187
+ } else if (is.string(image.gravity) && is.integer(this.constructor.gravity[image.gravity])) {
188
+ composite.gravity = this.constructor.gravity[image.gravity];
189
+ } else {
190
+ throw is.invalidParameterError('gravity', 'valid gravity', image.gravity);
191
+ }
192
+ }
193
+ if (is.defined(image.premultiplied)) {
194
+ if (is.bool(image.premultiplied)) {
195
+ composite.premultiplied = image.premultiplied;
196
+ } else {
197
+ throw is.invalidParameterError('premultiplied', 'boolean', image.premultiplied);
198
+ }
199
+ }
200
+ return composite;
201
+ });
202
+ return this;
203
+ }
204
+
205
+ /**
206
+ * Decorate the Sharp prototype with composite-related functions.
207
+ * @module Sharp
208
+ * @private
209
+ */
210
+ export default (Sharp) => {
211
+ Sharp.prototype.composite = composite;
212
+ Sharp.blend = blend;
213
+ };
@@ -5,9 +5,9 @@
5
5
 
6
6
  const util = require('node:util');
7
7
  const stream = require('node:stream');
8
- const is = require('./is');
8
+ const is = require('./is.cjs');
9
9
 
10
- require('./sharp');
10
+ require('./sharp.cjs');
11
11
 
12
12
  // Use NODE_DEBUG=sharp to enable libvips warnings
13
13
  const debuglog = util.debuglog('sharp');
@@ -48,7 +48,7 @@ const queueListener = (queueLength) => {
48
48
  * // resize to 300 pixels wide,
49
49
  * // emit an 'info' event with calculated dimensions
50
50
  * // and finally write image data to writableStream
51
- * const { body } = fetch('https://...');
51
+ * const { body } = await fetch('https://...');
52
52
  * const readableStream = Readable.fromWeb(body);
53
53
  * const transformer = sharp()
54
54
  * .resize(300)
@@ -58,6 +58,17 @@ const queueListener = (queueLength) => {
58
58
  * readableStream.pipe(transformer).pipe(writableStream);
59
59
  *
60
60
  * @example
61
+ * // Web Streams API, requires Node.js >= 24.15.0
62
+ * const { Duplex } = require('node:stream');
63
+ *
64
+ * const { body } = await fetch('https://...');
65
+ * const transformer = Duplex.toWeb(
66
+ * sharp().resize(300),
67
+ * { readableType: 'bytes' }
68
+ * );
69
+ * body.pipeThrough(transformer).pipeTo(writable);
70
+ *
71
+ * @example
61
72
  * // Create a blank 300x200 PNG image of semi-translucent red pixels
62
73
  * sharp({
63
74
  * create: {
@@ -146,14 +157,16 @@ const queueListener = (queueLength) => {
146
157
  * An array of inputs can be provided, and these will be joined together.
147
158
  * JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
148
159
  * @param {Object} [options] - if present, is an Object with optional attributes.
149
- * @param {string} [options.failOn='warning'] - When to abort processing of invalid pixel data, one of (in order of sensitivity, least to most): 'none', 'truncated', 'error', 'warning'. Higher levels imply lower levels. Invalid metadata will always abort.
160
+ * @param {string} [options.failOn='warning'] - When to abort processing of invalid pixel data, one of (in order of sensitivity, least to most): 'none', 'truncated', 'error', 'warning'. Higher levels imply lower levels. Invalid metadata will always abort. Use the default 'warning' level with untrusted input.
150
161
  * @param {number|boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
151
162
  * (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
152
163
  * An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
164
+ * @param {number|boolean} [options.limitInputChannels=5] - Do not process input images where the number of channels exceeds this limit. Assumes image metadata can be trusted.
165
+ * An integral Number of channels, zero or false to remove limit, true to use default limit of 5.
153
166
  * @param {boolean} [options.unlimited=false] - Set this to `true` to remove safety features that help prevent memory exhaustion (JPEG, PNG, SVG, HEIF).
154
167
  * @param {boolean} [options.autoOrient=false] - Set this to `true` to rotate/flip the image to match EXIF `Orientation`, if any.
155
168
  * @param {boolean} [options.sequentialRead=true] - Set this to `false` to use random access rather than sequential read. Some operations will do this automatically.
156
- * @param {number} [options.density=72] - number representing the DPI for vector images in the range 1 to 100000.
169
+ * @param {number} [options.density=72] - The DPI at which to render SVG and PDF images, in the range 1 to 100000.
157
170
  * @param {number} [options.ignoreIcc=false] - should the embedded ICC profile, if any, be ignored.
158
171
  * @param {number} [options.pages=1] - Number of pages to extract for multi-page input (GIF, WebP, TIFF), use -1 for all pages.
159
172
  * @param {number} [options.page=0] - Page number to start extracting from for multi-page input (GIF, WebP, TIFF), zero based.
@@ -278,6 +291,7 @@ const Sharp = function (input, options) {
278
291
  trimBackground: [],
279
292
  trimThreshold: -1,
280
293
  trimLineArt: false,
294
+ trimMargin: 0,
281
295
  dilateWidth: 0,
282
296
  erodeWidth: 0,
283
297
  gamma: 0,
@@ -306,6 +320,7 @@ const Sharp = function (input, options) {
306
320
  fileOut: '',
307
321
  formatOut: 'input',
308
322
  streamOut: false,
323
+ typedArrayOut: false,
309
324
  keepMetadata: 0,
310
325
  withMetadataOrientation: -1,
311
326
  withMetadataDensity: 0,
@@ -313,6 +328,8 @@ const Sharp = function (input, options) {
313
328
  withExif: {},
314
329
  withExifMerge: true,
315
330
  withXmp: '',
331
+ keepGainMap: false,
332
+ withGainMap: false,
316
333
  resolveWithObject: false,
317
334
  loop: -1,
318
335
  delay: [],
@@ -348,6 +365,7 @@ const Sharp = function (input, options) {
348
365
  webpEffort: 4,
349
366
  webpMinSize: false,
350
367
  webpMixed: false,
368
+ webpExact: false,
351
369
  gifBitdepth: 8,
352
370
  gifEffort: 7,
353
371
  gifDither: 1,
@@ -362,7 +380,7 @@ const Sharp = function (input, options) {
362
380
  tiffPredictor: 'horizontal',
363
381
  tiffPyramid: false,
364
382
  tiffMiniswhite: false,
365
- tiffBitdepth: 8,
383
+ tiffBitdepth: 0,
366
384
  tiffTile: false,
367
385
  tiffTileHeight: 256,
368
386
  tiffTileWidth: 256,
@@ -375,6 +393,7 @@ const Sharp = function (input, options) {
375
393
  heifEffort: 4,
376
394
  heifChromaSubsampling: '4:4:4',
377
395
  heifBitdepth: 8,
396
+ heifTune: 'auto',
378
397
  jxlDistance: 1,
379
398
  jxlDecodingTier: 0,
380
399
  jxlEffort: 7,
@@ -416,29 +435,33 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
416
435
  * This allows multiple output Streams and therefore multiple processing pipelines to share a single input Stream.
417
436
  *
418
437
  * @example
419
- * const pipeline = sharp().rotate();
420
- * pipeline.clone().resize(800, 600).pipe(firstWritableStream);
421
- * pipeline.clone().extract({ left: 20, top: 20, width: 100, height: 100 }).pipe(secondWritableStream);
422
- * readableStream.pipe(pipeline);
423
438
  * // firstWritableStream receives auto-rotated, resized readableStream
424
439
  * // secondWritableStream receives auto-rotated, extracted region of readableStream
425
440
  *
441
+ * const pipeline = sharp().rotate();
442
+ * pipeline
443
+ * .clone()
444
+ * .resize(800, 600)
445
+ * .pipe(firstWritableStream);
446
+ * pipeline
447
+ * .clone()
448
+ * .extract({ left: 20, top: 20, width: 100, height: 100 })
449
+ * .pipe(secondWritableStream);
450
+ * readableStream.pipe(pipeline);
451
+ *
426
452
  * @example
427
453
  * // Create a pipeline that will download an image, resize it and format it to different files
428
454
  * // Using Promises to know when the pipeline is complete
429
- * const fs = require("fs");
430
- * const got = require("got");
431
- * const sharpStream = sharp({ failOn: 'none' });
432
455
  *
433
- * const promises = [];
456
+ * const sharpStream = sharp();
434
457
  *
458
+ * const promises = [];
435
459
  * promises.push(
436
460
  * sharpStream
437
461
  * .clone()
438
462
  * .jpeg({ quality: 100 })
439
463
  * .toFile("originalFile.jpg")
440
464
  * );
441
- *
442
465
  * promises.push(
443
466
  * sharpStream
444
467
  * .clone()
@@ -446,7 +469,6 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
446
469
  * .jpeg({ quality: 80 })
447
470
  * .toFile("optimized-500.jpg")
448
471
  * );
449
- *
450
472
  * promises.push(
451
473
  * sharpStream
452
474
  * .clone()
@@ -455,19 +477,9 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
455
477
  * .toFile("optimized-500.webp")
456
478
  * );
457
479
  *
458
- * // https://github.com/sindresorhus/got/blob/main/documentation/3-streams.md
459
- * got.stream("https://www.example.com/some-file.jpg").pipe(sharpStream);
460
- *
461
- * Promise.all(promises)
462
- * .then(res => { console.log("Done!", res); })
463
- * .catch(err => {
464
- * console.error("Error processing files, let's clean it up", err);
465
- * try {
466
- * fs.unlinkSync("originalFile.jpg");
467
- * fs.unlinkSync("optimized-500.jpg");
468
- * fs.unlinkSync("optimized-500.webp");
469
- * } catch (e) {}
470
- * });
480
+ * const res = await fetch("https://www.example.com/some-file.jpg")
481
+ * Readable.fromWeb(res.body).pipe(sharpStream);
482
+ * await Promise.all(promises);
471
483
  *
472
484
  * @returns {Sharp}
473
485
  */
@@ -480,7 +492,7 @@ function clone () {
480
492
  clone.options.queueListener = queueListener;
481
493
  // Pass 'finish' event to clone for Stream-based input
482
494
  if (this._isStreamInput()) {
483
- this.on('finish', () => {
495
+ this._whenStreamInFinished(() => {
484
496
  // Clone inherits input data
485
497
  this._flattenBufferIn();
486
498
  clone.options.input.buffer = this.options.input.buffer;