@revizly/sharp 0.35.0-revizly4 → 0.35.0-revizly41
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/README.md +12 -18
- package/{lib/channel.js → dist/channel.cjs} +1 -1
- package/dist/channel.mjs +177 -0
- package/{lib/colour.js → dist/colour.cjs} +11 -7
- package/dist/colour.mjs +199 -0
- package/{lib/composite.js → dist/composite.cjs} +2 -1
- package/dist/composite.mjs +213 -0
- package/{lib/constructor.js → dist/constructor.cjs} +42 -29
- package/dist/constructor.mjs +512 -0
- package/dist/index.cjs +25 -0
- package/dist/index.d.cts +2001 -0
- package/dist/index.d.mts +2048 -0
- package/dist/index.mjs +25 -0
- package/{lib/input.js → dist/input.cjs} +26 -21
- package/dist/input.mjs +814 -0
- package/{lib/is.js → dist/is.cjs} +1 -1
- package/dist/is.mjs +143 -0
- package/{lib/libvips.js → dist/libvips.cjs} +35 -30
- package/dist/libvips.mjs +212 -0
- package/{lib/operation.js → dist/operation.cjs} +33 -51
- package/dist/operation.mjs +998 -0
- package/{lib/output.js → dist/output.cjs} +161 -28
- package/dist/output.mjs +1799 -0
- package/{lib/resize.js → dist/resize.cjs} +46 -24
- package/dist/resize.mjs +617 -0
- package/dist/sharp.cjs +125 -0
- package/dist/sharp.mjs +125 -0
- package/{lib/utility.js → dist/utility.cjs} +18 -8
- package/dist/utility.mjs +301 -0
- package/install/build.js +3 -3
- package/lib/index.d.ts +105 -75
- package/package.json +46 -27
- package/src/binding.gyp +18 -13
- package/src/common.cc +70 -17
- package/src/common.h +22 -3
- package/src/metadata.cc +66 -8
- package/src/metadata.h +6 -1
- package/src/operations.cc +25 -8
- package/src/operations.h +1 -1
- package/src/pipeline.cc +206 -69
- package/src/pipeline.h +16 -1
- package/src/stats.cc +6 -6
- package/src/utilities.cc +7 -6
- package/install/check.js +0 -14
- package/lib/index.js +0 -16
- 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.
|
|
117
|
+
* @param {Number} [images[].left] - the pixel offset from the left edge.
|
|
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)) {
|
|
167
|
+
composite.left = image.left;
|
|
168
|
+
} else {
|
|
169
|
+
throw is.invalidParameterError('left', 'integer', image.left);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (is.defined(image.top)) {
|
|
173
|
+
if (is.integer(image.top)) {
|
|
174
|
+
composite.top = image.top;
|
|
175
|
+
} else {
|
|
176
|
+
throw is.invalidParameterError('top', 'integer', 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] -
|
|
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:
|
|
383
|
+
tiffBitdepth: 0,
|
|
366
384
|
tiffTile: false,
|
|
367
385
|
tiffTileHeight: 256,
|
|
368
386
|
tiffTileWidth: 256,
|
|
@@ -375,6 +393,8 @@ const Sharp = function (input, options) {
|
|
|
375
393
|
heifEffort: 4,
|
|
376
394
|
heifChromaSubsampling: '4:4:4',
|
|
377
395
|
heifBitdepth: 8,
|
|
396
|
+
heifTune: 'auto',
|
|
397
|
+
heifEncoder: 'auto',
|
|
378
398
|
jxlDistance: 1,
|
|
379
399
|
jxlDecodingTier: 0,
|
|
380
400
|
jxlEffort: 7,
|
|
@@ -416,29 +436,33 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
|
|
|
416
436
|
* This allows multiple output Streams and therefore multiple processing pipelines to share a single input Stream.
|
|
417
437
|
*
|
|
418
438
|
* @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
439
|
* // firstWritableStream receives auto-rotated, resized readableStream
|
|
424
440
|
* // secondWritableStream receives auto-rotated, extracted region of readableStream
|
|
425
441
|
*
|
|
442
|
+
* const pipeline = sharp().rotate();
|
|
443
|
+
* pipeline
|
|
444
|
+
* .clone()
|
|
445
|
+
* .resize(800, 600)
|
|
446
|
+
* .pipe(firstWritableStream);
|
|
447
|
+
* pipeline
|
|
448
|
+
* .clone()
|
|
449
|
+
* .extract({ left: 20, top: 20, width: 100, height: 100 })
|
|
450
|
+
* .pipe(secondWritableStream);
|
|
451
|
+
* readableStream.pipe(pipeline);
|
|
452
|
+
*
|
|
426
453
|
* @example
|
|
427
454
|
* // Create a pipeline that will download an image, resize it and format it to different files
|
|
428
455
|
* // 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
456
|
*
|
|
433
|
-
* const
|
|
457
|
+
* const sharpStream = sharp();
|
|
434
458
|
*
|
|
459
|
+
* const promises = [];
|
|
435
460
|
* promises.push(
|
|
436
461
|
* sharpStream
|
|
437
462
|
* .clone()
|
|
438
463
|
* .jpeg({ quality: 100 })
|
|
439
464
|
* .toFile("originalFile.jpg")
|
|
440
465
|
* );
|
|
441
|
-
*
|
|
442
466
|
* promises.push(
|
|
443
467
|
* sharpStream
|
|
444
468
|
* .clone()
|
|
@@ -446,7 +470,6 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
|
|
|
446
470
|
* .jpeg({ quality: 80 })
|
|
447
471
|
* .toFile("optimized-500.jpg")
|
|
448
472
|
* );
|
|
449
|
-
*
|
|
450
473
|
* promises.push(
|
|
451
474
|
* sharpStream
|
|
452
475
|
* .clone()
|
|
@@ -455,19 +478,9 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
|
|
|
455
478
|
* .toFile("optimized-500.webp")
|
|
456
479
|
* );
|
|
457
480
|
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
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
|
-
* });
|
|
481
|
+
* const res = await fetch("https://www.example.com/some-file.jpg")
|
|
482
|
+
* Readable.fromWeb(res.body).pipe(sharpStream);
|
|
483
|
+
* await Promise.all(promises);
|
|
471
484
|
*
|
|
472
485
|
* @returns {Sharp}
|
|
473
486
|
*/
|