sharp 0.20.5 → 0.21.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.
- package/README.md +3 -3
- package/binding.gyp +5 -0
- package/docs/api-channel.md +16 -0
- package/docs/api-colour.md +1 -19
- package/docs/api-composite.md +2 -3
- package/docs/api-constructor.md +2 -2
- package/docs/api-input.md +6 -2
- package/docs/api-operation.md +40 -115
- package/docs/api-output.md +3 -0
- package/docs/api-resize.md +159 -109
- package/docs/api-utility.md +4 -7
- package/docs/changelog.md +87 -0
- package/docs/index.md +10 -4
- package/docs/install.md +18 -38
- package/docs/performance.md +14 -21
- package/install/dll-copy.js +3 -2
- package/install/libvips.js +55 -36
- package/lib/channel.js +18 -0
- package/lib/colour.js +34 -15
- package/lib/composite.js +2 -3
- package/lib/constructor.js +19 -41
- package/lib/input.js +7 -3
- package/lib/libvips.js +38 -6
- package/lib/operation.js +27 -118
- package/lib/output.js +22 -2
- package/lib/platform.js +4 -1
- package/lib/resize.js +308 -104
- package/lib/utility.js +5 -8
- package/package.json +20 -13
- package/src/common.cc +50 -13
- package/src/common.h +12 -10
- package/src/libvips/cplusplus/VImage.cpp +95 -95
- package/src/libvips/cplusplus/vips-operators.cpp +268 -185
- package/src/metadata.cc +15 -0
- package/src/metadata.h +3 -0
- package/src/operations.cc +27 -54
- package/src/operations.h +6 -1
- package/src/pipeline.cc +81 -89
- package/src/pipeline.h +25 -13
- package/src/stats.cc +11 -8
- package/src/stats.h +3 -1
- package/src/utilities.cc +1 -1
package/lib/resize.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const deprecate = require('util').deprecate;
|
|
3
4
|
const is = require('./is');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
* Weighting to apply
|
|
7
|
+
* Weighting to apply when using contain/cover fit.
|
|
7
8
|
* @member
|
|
8
9
|
* @private
|
|
9
10
|
*/
|
|
@@ -21,7 +22,23 @@ const gravity = {
|
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
|
-
*
|
|
25
|
+
* Position to apply when using contain/cover fit.
|
|
26
|
+
* @member
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
const position = {
|
|
30
|
+
top: 1,
|
|
31
|
+
right: 2,
|
|
32
|
+
bottom: 3,
|
|
33
|
+
left: 4,
|
|
34
|
+
'right top': 5,
|
|
35
|
+
'right bottom': 6,
|
|
36
|
+
'left bottom': 7,
|
|
37
|
+
'left top': 8
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Strategies for automagic cover behaviour.
|
|
25
42
|
* @member
|
|
26
43
|
* @private
|
|
27
44
|
*/
|
|
@@ -43,40 +60,137 @@ const kernel = {
|
|
|
43
60
|
};
|
|
44
61
|
|
|
45
62
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
63
|
+
* Methods by which an image can be resized to fit the provided dimensions.
|
|
64
|
+
* @member
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
67
|
+
const fit = {
|
|
68
|
+
contain: 'contain',
|
|
69
|
+
cover: 'cover',
|
|
70
|
+
fill: 'fill',
|
|
71
|
+
inside: 'inside',
|
|
72
|
+
outside: 'outside'
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Map external fit property to internal canvas property.
|
|
77
|
+
* @member
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
const mapFitToCanvas = {
|
|
81
|
+
contain: 'embed',
|
|
82
|
+
cover: 'crop',
|
|
83
|
+
fill: 'ignore_aspect',
|
|
84
|
+
inside: 'max',
|
|
85
|
+
outside: 'min'
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Resize image to `width`, `height` or `width x height`.
|
|
90
|
+
*
|
|
91
|
+
* When both a `width` and `height` are provided, the possible methods by which the image should **fit** these are:
|
|
92
|
+
* - `cover`: Crop to cover both provided dimensions (the default).
|
|
93
|
+
* - `contain`: Embed within both provided dimensions.
|
|
94
|
+
* - `fill`: Ignore the aspect ratio of the input and stretch to both provided dimensions.
|
|
95
|
+
* - `inside`: Preserving aspect ratio, resize the image to be as large as possible while ensuring its dimensions are less than or equal to both those specified.
|
|
96
|
+
* - `outside`: Preserving aspect ratio, resize the image to be as small as possible while ensuring its dimensions are greater than or equal to both those specified.
|
|
97
|
+
* Some of these values are based on the [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) CSS property.
|
|
98
|
+
*
|
|
99
|
+
* When using a `fit` of `cover` or `contain`, the default **position** is `centre`. Other options are:
|
|
100
|
+
* - `sharp.position`: `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`.
|
|
101
|
+
* - `sharp.gravity`: `north`, `northeast`, `east`, `southeast`, `south`, `southwest`, `west`, `northwest`, `center` or `centre`.
|
|
102
|
+
* - `sharp.strategy`: `cover` only, dynamically crop using either the `entropy` or `attention` strategy.
|
|
103
|
+
* Some of these values are based on the [object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) CSS property.
|
|
104
|
+
*
|
|
105
|
+
* The experimental strategy-based approach resizes so one dimension is at its target length
|
|
106
|
+
* then repeatedly ranks edge regions, discarding the edge with the lowest score based on the selected strategy.
|
|
107
|
+
* - `entropy`: focus on the region with the highest [Shannon entropy](https://en.wikipedia.org/wiki/Entropy_%28information_theory%29).
|
|
108
|
+
* - `attention`: focus on the region with the highest luminance frequency, colour saturation and presence of skin tones.
|
|
48
109
|
*
|
|
49
|
-
* Possible kernels are:
|
|
110
|
+
* Possible interpolation kernels are:
|
|
50
111
|
* - `nearest`: Use [nearest neighbour interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation).
|
|
51
112
|
* - `cubic`: Use a [Catmull-Rom spline](https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline).
|
|
52
113
|
* - `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`.
|
|
53
114
|
* - `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
|
|
54
115
|
*
|
|
55
116
|
* @example
|
|
56
|
-
* sharp(
|
|
117
|
+
* sharp(input)
|
|
118
|
+
* .resize({ width: 100 })
|
|
119
|
+
* .toBuffer()
|
|
120
|
+
* .then(data => {
|
|
121
|
+
* // 100 pixels wide, auto-scaled height
|
|
122
|
+
* });
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* sharp(input)
|
|
126
|
+
* .resize({ height: 100 })
|
|
127
|
+
* .toBuffer()
|
|
128
|
+
* .then(data => {
|
|
129
|
+
* // 100 pixels high, auto-scaled width
|
|
130
|
+
* });
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* sharp(input)
|
|
57
134
|
* .resize(200, 300, {
|
|
58
|
-
* kernel: sharp.kernel.nearest
|
|
135
|
+
* kernel: sharp.kernel.nearest,
|
|
136
|
+
* fit: 'contain',
|
|
137
|
+
* position: 'right top',
|
|
138
|
+
* background: { r: 255, g: 255, b: 255, alpha: 0.5 }
|
|
139
|
+
* })
|
|
140
|
+
* .toFile('output.png')
|
|
141
|
+
* .then(() => {
|
|
142
|
+
* // output.png is a 200 pixels wide and 300 pixels high image
|
|
143
|
+
* // containing a nearest-neighbour scaled version
|
|
144
|
+
* // contained within the north-east corner of a semi-transparent white canvas
|
|
145
|
+
* });
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* const transformer = sharp()
|
|
149
|
+
* .resize({
|
|
150
|
+
* width: 200,
|
|
151
|
+
* height: 200,
|
|
152
|
+
* fit: sharp.fit.cover,
|
|
153
|
+
* position: sharp.strategy.entropy
|
|
154
|
+
* });
|
|
155
|
+
* // Read image data from readableStream
|
|
156
|
+
* // Write 200px square auto-cropped image data to writableStream
|
|
157
|
+
* readableStream
|
|
158
|
+
* .pipe(transformer)
|
|
159
|
+
* .pipe(writableStream);
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* sharp(input)
|
|
163
|
+
* .resize(200, 200, {
|
|
164
|
+
* fit: sharp.fit.inside,
|
|
165
|
+
* withoutEnlargement: true
|
|
59
166
|
* })
|
|
60
|
-
* .
|
|
61
|
-
* .
|
|
62
|
-
* .
|
|
63
|
-
*
|
|
64
|
-
* //
|
|
65
|
-
* //
|
|
66
|
-
* // of the image data in inputBuffer
|
|
167
|
+
* .toFormat('jpeg')
|
|
168
|
+
* .toBuffer()
|
|
169
|
+
* .then(function(outputBuffer) {
|
|
170
|
+
* // outputBuffer contains JPEG image data
|
|
171
|
+
* // no wider and no higher than 200 pixels
|
|
172
|
+
* // and no larger than the input image
|
|
67
173
|
* });
|
|
68
174
|
*
|
|
69
175
|
* @param {Number} [width] - pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
|
|
70
176
|
* @param {Number} [height] - pixels high the resultant image should be. Use `null` or `undefined` to auto-scale the height to match the width.
|
|
71
177
|
* @param {Object} [options]
|
|
178
|
+
* @param {String} [options.width] - alternative means of specifying `width`. If both are present this take priority.
|
|
179
|
+
* @param {String} [options.height] - alternative means of specifying `height`. If both are present this take priority.
|
|
180
|
+
* @param {String} [options.fit='cover'] - how the image should be resized to fit both provided dimensions, one of `cover`, `contain`, `fill`, `inside` or `outside`.
|
|
181
|
+
* @param {String} [options.position='centre'] - position, gravity or strategy to use when `fit` is `cover` or `contain`.
|
|
182
|
+
* @param {String|Object} [options.background={r: 0, g: 0, b: 0, alpha: 1}] - background colour when using a `fit` of `contain`, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black without transparency.
|
|
72
183
|
* @param {String} [options.kernel='lanczos3'] - the kernel to use for image reduction.
|
|
184
|
+
* @param {Boolean} [options.withoutEnlargement=false] - do not enlarge if the width *or* height are already less than the specified dimensions, equivalent to GraphicsMagick's `>` geometry option.
|
|
73
185
|
* @param {Boolean} [options.fastShrinkOnLoad=true] - take greater advantage of the JPEG and WebP shrink-on-load feature, which can lead to a slight moiré pattern on some images.
|
|
74
186
|
* @returns {Sharp}
|
|
75
187
|
* @throws {Error} Invalid parameters
|
|
76
188
|
*/
|
|
77
189
|
function resize (width, height, options) {
|
|
78
190
|
if (is.defined(width)) {
|
|
79
|
-
if (is.
|
|
191
|
+
if (is.object(width) && !is.defined(options)) {
|
|
192
|
+
options = width;
|
|
193
|
+
} else if (is.integer(width) && width > 0) {
|
|
80
194
|
this.options.width = width;
|
|
81
195
|
} else {
|
|
82
196
|
throw is.invalidParameterError('width', 'positive integer', width);
|
|
@@ -94,6 +208,38 @@ function resize (width, height, options) {
|
|
|
94
208
|
this.options.height = -1;
|
|
95
209
|
}
|
|
96
210
|
if (is.object(options)) {
|
|
211
|
+
// Width
|
|
212
|
+
if (is.integer(options.width) && options.width > 0) {
|
|
213
|
+
this.options.width = options.width;
|
|
214
|
+
}
|
|
215
|
+
// Height
|
|
216
|
+
if (is.integer(options.height) && options.height > 0) {
|
|
217
|
+
this.options.height = options.height;
|
|
218
|
+
}
|
|
219
|
+
// Fit
|
|
220
|
+
if (is.defined(options.fit)) {
|
|
221
|
+
const canvas = mapFitToCanvas[options.fit];
|
|
222
|
+
if (is.string(canvas)) {
|
|
223
|
+
this.options.canvas = canvas;
|
|
224
|
+
} else {
|
|
225
|
+
throw is.invalidParameterError('fit', 'valid fit', options.fit);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Position
|
|
229
|
+
if (is.defined(options.position)) {
|
|
230
|
+
const pos = is.integer(options.position)
|
|
231
|
+
? options.position
|
|
232
|
+
: strategy[options.position] || position[options.position] || gravity[options.position];
|
|
233
|
+
if (is.integer(pos) && (is.inRange(pos, 0, 8) || is.inRange(pos, 16, 17))) {
|
|
234
|
+
this.options.position = pos;
|
|
235
|
+
} else {
|
|
236
|
+
throw is.invalidParameterError('position', 'valid position/gravity/strategy', options.position);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Background
|
|
240
|
+
if (is.defined(options.background)) {
|
|
241
|
+
this._setColourOption('resizeBackground', options.background);
|
|
242
|
+
}
|
|
97
243
|
// Kernel
|
|
98
244
|
if (is.defined(options.kernel)) {
|
|
99
245
|
if (is.string(kernel[options.kernel])) {
|
|
@@ -102,6 +248,10 @@ function resize (width, height, options) {
|
|
|
102
248
|
throw is.invalidParameterError('kernel', 'valid kernel name', options.kernel);
|
|
103
249
|
}
|
|
104
250
|
}
|
|
251
|
+
// Without enlargement
|
|
252
|
+
if (is.defined(options.withoutEnlargement)) {
|
|
253
|
+
this._setBooleanOption('withoutEnlargement', options.withoutEnlargement);
|
|
254
|
+
}
|
|
105
255
|
// Shrink on load
|
|
106
256
|
if (is.defined(options.fastShrinkOnLoad)) {
|
|
107
257
|
this._setBooleanOption('fastShrinkOnLoad', options.fastShrinkOnLoad);
|
|
@@ -111,48 +261,145 @@ function resize (width, height, options) {
|
|
|
111
261
|
}
|
|
112
262
|
|
|
113
263
|
/**
|
|
114
|
-
*
|
|
264
|
+
* Extends/pads the edges of the image with the provided background colour.
|
|
265
|
+
* This operation will always occur after resizing and extraction, if any.
|
|
115
266
|
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
267
|
+
* @example
|
|
268
|
+
* // Resize to 140 pixels wide, then add 10 transparent pixels
|
|
269
|
+
* // to the top, left and right edges and 20 to the bottom edge
|
|
270
|
+
* sharp(input)
|
|
271
|
+
* .resize(140)
|
|
272
|
+
* .)
|
|
273
|
+
* .extend({
|
|
274
|
+
* top: 10,
|
|
275
|
+
* bottom: 20,
|
|
276
|
+
* left: 10,
|
|
277
|
+
* right: 10
|
|
278
|
+
* background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
279
|
+
* })
|
|
280
|
+
* ...
|
|
118
281
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
282
|
+
* @param {(Number|Object)} extend - single pixel count to add to all edges or an Object with per-edge counts
|
|
283
|
+
* @param {Number} [extend.top]
|
|
284
|
+
* @param {Number} [extend.left]
|
|
285
|
+
* @param {Number} [extend.bottom]
|
|
286
|
+
* @param {Number} [extend.right]
|
|
287
|
+
* @param {String|Object} [extend.background={r: 0, g: 0, b: 0, alpha: 1}] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black without transparency.
|
|
288
|
+
* @returns {Sharp}
|
|
289
|
+
* @throws {Error} Invalid parameters
|
|
290
|
+
*/
|
|
291
|
+
function extend (extend) {
|
|
292
|
+
if (is.integer(extend) && extend > 0) {
|
|
293
|
+
this.options.extendTop = extend;
|
|
294
|
+
this.options.extendBottom = extend;
|
|
295
|
+
this.options.extendLeft = extend;
|
|
296
|
+
this.options.extendRight = extend;
|
|
297
|
+
} else if (
|
|
298
|
+
is.object(extend) &&
|
|
299
|
+
is.integer(extend.top) && extend.top >= 0 &&
|
|
300
|
+
is.integer(extend.bottom) && extend.bottom >= 0 &&
|
|
301
|
+
is.integer(extend.left) && extend.left >= 0 &&
|
|
302
|
+
is.integer(extend.right) && extend.right >= 0
|
|
303
|
+
) {
|
|
304
|
+
this.options.extendTop = extend.top;
|
|
305
|
+
this.options.extendBottom = extend.bottom;
|
|
306
|
+
this.options.extendLeft = extend.left;
|
|
307
|
+
this.options.extendRight = extend.right;
|
|
308
|
+
this._setColourOption('extendBackground', extend.background);
|
|
309
|
+
} else {
|
|
310
|
+
throw new Error('Invalid edge extension ' + extend);
|
|
311
|
+
}
|
|
312
|
+
return this;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Extract a region of the image.
|
|
317
|
+
*
|
|
318
|
+
* - Use `extract` before `resize` for pre-resize extraction.
|
|
319
|
+
* - Use `extract` after `resize` for post-resize extraction.
|
|
320
|
+
* - Use `extract` before and after for both.
|
|
123
321
|
*
|
|
124
322
|
* @example
|
|
125
|
-
*
|
|
126
|
-
* .
|
|
127
|
-
* .
|
|
128
|
-
*
|
|
129
|
-
*
|
|
323
|
+
* sharp(input)
|
|
324
|
+
* .extract({ left: left, top: top, width: width, height: height })
|
|
325
|
+
* .toFile(output, function(err) {
|
|
326
|
+
* // Extract a region of the input image, saving in the same format.
|
|
327
|
+
* });
|
|
328
|
+
* @example
|
|
329
|
+
* sharp(input)
|
|
330
|
+
* .extract({ left: leftOffsetPre, top: topOffsetPre, width: widthPre, height: heightPre })
|
|
331
|
+
* .resize(width, height)
|
|
332
|
+
* .extract({ left: leftOffsetPost, top: topOffsetPost, width: widthPost, height: heightPost })
|
|
333
|
+
* .toFile(output, function(err) {
|
|
334
|
+
* // Extract a region, resize, then extract from the resized image
|
|
130
335
|
* });
|
|
131
|
-
* // Read image data from readableStream
|
|
132
|
-
* // Write 200px square auto-cropped image data to writableStream
|
|
133
|
-
* readableStream.pipe(transformer).pipe(writableStream);
|
|
134
336
|
*
|
|
135
|
-
* @param {
|
|
337
|
+
* @param {Object} options
|
|
338
|
+
* @param {Number} options.left - zero-indexed offset from left edge
|
|
339
|
+
* @param {Number} options.top - zero-indexed offset from top edge
|
|
340
|
+
* @param {Number} options.width - dimension of extracted image
|
|
341
|
+
* @param {Number} options.height - dimension of extracted image
|
|
136
342
|
* @returns {Sharp}
|
|
137
343
|
* @throws {Error} Invalid parameters
|
|
138
344
|
*/
|
|
345
|
+
function extract (options) {
|
|
346
|
+
const suffix = this.options.width === -1 && this.options.height === -1 ? 'Pre' : 'Post';
|
|
347
|
+
['left', 'top', 'width', 'height'].forEach(function (name) {
|
|
348
|
+
const value = options[name];
|
|
349
|
+
if (is.integer(value) && value >= 0) {
|
|
350
|
+
this.options[name + (name === 'left' || name === 'top' ? 'Offset' : '') + suffix] = value;
|
|
351
|
+
} else {
|
|
352
|
+
throw new Error('Non-integer value for ' + name + ' of ' + value);
|
|
353
|
+
}
|
|
354
|
+
}, this);
|
|
355
|
+
// Ensure existing rotation occurs before pre-resize extraction
|
|
356
|
+
if (suffix === 'Pre' && ((this.options.angle % 360) !== 0 || this.options.useExifOrientation === true)) {
|
|
357
|
+
this.options.rotateBeforePreExtract = true;
|
|
358
|
+
}
|
|
359
|
+
return this;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Trim "boring" pixels from all edges that contain values similar to the top-left pixel.
|
|
364
|
+
* The `info` response Object will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
|
365
|
+
* @param {Number} [threshold=10] the allowed difference from the top-left pixel, a number greater than zero.
|
|
366
|
+
* @returns {Sharp}
|
|
367
|
+
* @throws {Error} Invalid parameters
|
|
368
|
+
*/
|
|
369
|
+
function trim (threshold) {
|
|
370
|
+
if (!is.defined(threshold)) {
|
|
371
|
+
this.options.trimThreshold = 10;
|
|
372
|
+
} else if (is.number(threshold) && threshold > 0) {
|
|
373
|
+
this.options.trimThreshold = threshold;
|
|
374
|
+
} else {
|
|
375
|
+
throw is.invalidParameterError('threshold', 'number greater than zero', threshold);
|
|
376
|
+
}
|
|
377
|
+
return this;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Deprecated functions
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* @deprecated
|
|
384
|
+
* @private
|
|
385
|
+
*/
|
|
139
386
|
function crop (crop) {
|
|
140
387
|
this.options.canvas = 'crop';
|
|
141
388
|
if (!is.defined(crop)) {
|
|
142
389
|
// Default
|
|
143
|
-
this.options.
|
|
390
|
+
this.options.position = gravity.center;
|
|
144
391
|
} else if (is.integer(crop) && is.inRange(crop, 0, 8)) {
|
|
145
392
|
// Gravity (numeric)
|
|
146
|
-
this.options.
|
|
393
|
+
this.options.position = crop;
|
|
147
394
|
} else if (is.string(crop) && is.integer(gravity[crop])) {
|
|
148
395
|
// Gravity (string)
|
|
149
|
-
this.options.
|
|
396
|
+
this.options.position = gravity[crop];
|
|
150
397
|
} else if (is.integer(crop) && crop >= strategy.entropy) {
|
|
151
398
|
// Strategy
|
|
152
|
-
this.options.
|
|
399
|
+
this.options.position = crop;
|
|
153
400
|
} else if (is.string(crop) && is.integer(strategy[crop])) {
|
|
154
401
|
// Strategy (string)
|
|
155
|
-
this.options.
|
|
402
|
+
this.options.position = strategy[crop];
|
|
156
403
|
} else {
|
|
157
404
|
throw is.invalidParameterError('crop', 'valid crop id/name/strategy', crop);
|
|
158
405
|
}
|
|
@@ -160,66 +407,29 @@ function crop (crop) {
|
|
|
160
407
|
}
|
|
161
408
|
|
|
162
409
|
/**
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* If the background contains an alpha value then WebP and PNG format output images will
|
|
167
|
-
* contain an alpha channel, even when the input image does not.
|
|
168
|
-
*
|
|
169
|
-
* @example
|
|
170
|
-
* sharp('input.gif')
|
|
171
|
-
* .resize(200, 300)
|
|
172
|
-
* .background({r: 0, g: 0, b: 0, alpha: 0})
|
|
173
|
-
* .embed()
|
|
174
|
-
* .toFormat(sharp.format.webp)
|
|
175
|
-
* .toBuffer(function(err, outputBuffer) {
|
|
176
|
-
* if (err) {
|
|
177
|
-
* throw err;
|
|
178
|
-
* }
|
|
179
|
-
* // outputBuffer contains WebP image data of a 200 pixels wide and 300 pixels high
|
|
180
|
-
* // containing a scaled version, embedded on a transparent canvas, of input.gif
|
|
181
|
-
* });
|
|
182
|
-
* @param {String} [embed='centre'] - A member of `sharp.gravity` to embed to an edge/corner.
|
|
183
|
-
* @returns {Sharp}
|
|
184
|
-
* @throws {Error} Invalid parameters
|
|
410
|
+
* @deprecated
|
|
411
|
+
* @private
|
|
185
412
|
*/
|
|
186
413
|
function embed (embed) {
|
|
187
414
|
this.options.canvas = 'embed';
|
|
188
|
-
|
|
189
415
|
if (!is.defined(embed)) {
|
|
190
416
|
// Default
|
|
191
|
-
this.options.
|
|
417
|
+
this.options.position = gravity.center;
|
|
192
418
|
} else if (is.integer(embed) && is.inRange(embed, 0, 8)) {
|
|
193
419
|
// Gravity (numeric)
|
|
194
|
-
this.options.
|
|
420
|
+
this.options.position = embed;
|
|
195
421
|
} else if (is.string(embed) && is.integer(gravity[embed])) {
|
|
196
422
|
// Gravity (string)
|
|
197
|
-
this.options.
|
|
423
|
+
this.options.position = gravity[embed];
|
|
198
424
|
} else {
|
|
199
425
|
throw is.invalidParameterError('embed', 'valid embed id/name', embed);
|
|
200
426
|
}
|
|
201
|
-
|
|
202
427
|
return this;
|
|
203
428
|
}
|
|
204
429
|
|
|
205
430
|
/**
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
* Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
|
210
|
-
*
|
|
211
|
-
* @example
|
|
212
|
-
* sharp(inputBuffer)
|
|
213
|
-
* .resize(200, 200)
|
|
214
|
-
* .max()
|
|
215
|
-
* .toFormat('jpeg')
|
|
216
|
-
* .toBuffer()
|
|
217
|
-
* .then(function(outputBuffer) {
|
|
218
|
-
* // outputBuffer contains JPEG image data no wider than 200 pixels and no higher
|
|
219
|
-
* // than 200 pixels regardless of the inputBuffer image dimensions
|
|
220
|
-
* });
|
|
221
|
-
*
|
|
222
|
-
* @returns {Sharp}
|
|
431
|
+
* @deprecated
|
|
432
|
+
* @private
|
|
223
433
|
*/
|
|
224
434
|
function max () {
|
|
225
435
|
this.options.canvas = 'max';
|
|
@@ -227,12 +437,8 @@ function max () {
|
|
|
227
437
|
}
|
|
228
438
|
|
|
229
439
|
/**
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
|
234
|
-
*
|
|
235
|
-
* @returns {Sharp}
|
|
440
|
+
* @deprecated
|
|
441
|
+
* @private
|
|
236
442
|
*/
|
|
237
443
|
function min () {
|
|
238
444
|
this.options.canvas = 'min';
|
|
@@ -240,9 +446,8 @@ function min () {
|
|
|
240
446
|
}
|
|
241
447
|
|
|
242
448
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* @returns {Sharp}
|
|
449
|
+
* @deprecated
|
|
450
|
+
* @private
|
|
246
451
|
*/
|
|
247
452
|
function ignoreAspectRatio () {
|
|
248
453
|
this.options.canvas = 'ignore_aspect';
|
|
@@ -250,15 +455,8 @@ function ignoreAspectRatio () {
|
|
|
250
455
|
}
|
|
251
456
|
|
|
252
457
|
/**
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
* "*change the dimensions of the image only if its width or height exceeds the geometry specification*".
|
|
256
|
-
* Use with `max()` to preserve the image's aspect ratio.
|
|
257
|
-
*
|
|
258
|
-
* The default behaviour *before* function call is `false`, meaning the image will be enlarged.
|
|
259
|
-
*
|
|
260
|
-
* @param {Boolean} [withoutEnlargement=true]
|
|
261
|
-
* @returns {Sharp}
|
|
458
|
+
* @deprecated
|
|
459
|
+
* @private
|
|
262
460
|
*/
|
|
263
461
|
function withoutEnlargement (withoutEnlargement) {
|
|
264
462
|
this.options.withoutEnlargement = is.bool(withoutEnlargement) ? withoutEnlargement : true;
|
|
@@ -272,12 +470,9 @@ function withoutEnlargement (withoutEnlargement) {
|
|
|
272
470
|
module.exports = function (Sharp) {
|
|
273
471
|
[
|
|
274
472
|
resize,
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
min,
|
|
279
|
-
ignoreAspectRatio,
|
|
280
|
-
withoutEnlargement
|
|
473
|
+
extend,
|
|
474
|
+
extract,
|
|
475
|
+
trim
|
|
281
476
|
].forEach(function (f) {
|
|
282
477
|
Sharp.prototype[f.name] = f;
|
|
283
478
|
});
|
|
@@ -285,4 +480,13 @@ module.exports = function (Sharp) {
|
|
|
285
480
|
Sharp.gravity = gravity;
|
|
286
481
|
Sharp.strategy = strategy;
|
|
287
482
|
Sharp.kernel = kernel;
|
|
483
|
+
Sharp.fit = fit;
|
|
484
|
+
Sharp.position = position;
|
|
485
|
+
// Deprecated functions, to be removed in v0.22.0
|
|
486
|
+
Sharp.prototype.crop = deprecate(crop, 'crop(position) is deprecated, use resize({ fit: "cover", position }) instead');
|
|
487
|
+
Sharp.prototype.embed = deprecate(embed, 'embed(position) is deprecated, use resize({ fit: "contain", position }) instead');
|
|
488
|
+
Sharp.prototype.max = deprecate(max, 'max() is deprecated, use resize({ fit: "inside" }) instead');
|
|
489
|
+
Sharp.prototype.min = deprecate(min, 'min() is deprecated, use resize({ fit: "outside" }) instead');
|
|
490
|
+
Sharp.prototype.ignoreAspectRatio = deprecate(ignoreAspectRatio, 'ignoreAspectRatio() is deprecated, use resize({ fit: "fill" }) instead');
|
|
491
|
+
Sharp.prototype.withoutEnlargement = deprecate(withoutEnlargement, 'withoutEnlargement() is deprecated, use resize({ withoutEnlargement: true }) instead');
|
|
288
492
|
};
|
package/lib/utility.js
CHANGED
|
@@ -82,23 +82,20 @@ function counters () {
|
|
|
82
82
|
* Improves the performance of `resize`, `blur` and `sharpen` operations
|
|
83
83
|
* by taking advantage of the SIMD vector unit of the CPU, e.g. Intel SSE and ARM NEON.
|
|
84
84
|
*
|
|
85
|
-
* This feature is currently off by default but future versions may reverse this.
|
|
86
|
-
* Versions of liborc prior to 0.4.25 are known to segfault under heavy load.
|
|
87
|
-
*
|
|
88
85
|
* @example
|
|
89
86
|
* const simd = sharp.simd();
|
|
90
|
-
* // simd is `true` if
|
|
87
|
+
* // simd is `true` if the runtime use of liborc is currently enabled
|
|
91
88
|
* @example
|
|
92
|
-
* const simd = sharp.simd(
|
|
93
|
-
* //
|
|
89
|
+
* const simd = sharp.simd(false);
|
|
90
|
+
* // prevent libvips from using liborc at runtime
|
|
94
91
|
*
|
|
95
|
-
* @param {Boolean} [simd=
|
|
92
|
+
* @param {Boolean} [simd=true]
|
|
96
93
|
* @returns {Boolean}
|
|
97
94
|
*/
|
|
98
95
|
function simd (simd) {
|
|
99
96
|
return sharp.simd(is.bool(simd) ? simd : null);
|
|
100
97
|
}
|
|
101
|
-
simd(
|
|
98
|
+
simd(true);
|
|
102
99
|
|
|
103
100
|
/**
|
|
104
101
|
* Decorate the Sharp class with utility-related functions.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sharp",
|
|
3
3
|
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.21.0",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://github.com/lovell/sharp",
|
|
7
7
|
"contributors": [
|
|
@@ -49,11 +49,17 @@
|
|
|
49
49
|
"Rik Heywood <rik@rik.org>",
|
|
50
50
|
"Thomas Parisot <hi@oncletom.io>",
|
|
51
51
|
"Nathan Graves <nathanrgraves+github@gmail.com>",
|
|
52
|
-
"Tom Lokhorst <tom@lokhorst.eu>"
|
|
52
|
+
"Tom Lokhorst <tom@lokhorst.eu>",
|
|
53
|
+
"Espen Hovlandsdal <espen@hovlandsdal.com>",
|
|
54
|
+
"Sylvain Dumont <sylvain.dumont35@gmail.com>",
|
|
55
|
+
"Alun Davies <alun.owain.davies@googlemail.com>",
|
|
56
|
+
"Aidan Hoolachan <ajhoolachan21@gmail.com>",
|
|
57
|
+
"Axel Eirola <axel.eirola@iki.fi>",
|
|
58
|
+
"Freezy <freezy@xbmc.org>"
|
|
53
59
|
],
|
|
54
60
|
"scripts": {
|
|
55
61
|
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
|
|
56
|
-
"clean": "rm -rf node_modules/ build/ vendor/ coverage/ test/fixtures/output.*",
|
|
62
|
+
"clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
|
|
57
63
|
"test": "semistandard && cc && nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js && prebuild-ci",
|
|
58
64
|
"coverage": "./test/coverage/report.sh",
|
|
59
65
|
"test-leak": "./test/leak/leak.sh",
|
|
@@ -83,35 +89,36 @@
|
|
|
83
89
|
"dependencies": {
|
|
84
90
|
"color": "^3.0.0",
|
|
85
91
|
"detect-libc": "^1.0.3",
|
|
86
|
-
"nan": "^2.
|
|
92
|
+
"nan": "^2.11.1",
|
|
87
93
|
"fs-copy-file-sync": "^1.1.1",
|
|
88
94
|
"npmlog": "^4.1.2",
|
|
89
|
-
"prebuild-install": "^
|
|
90
|
-
"semver": "^5.5.
|
|
91
|
-
"simple-get": "^
|
|
92
|
-
"tar": "^4.4.
|
|
95
|
+
"prebuild-install": "^5.2.0",
|
|
96
|
+
"semver": "^5.5.1",
|
|
97
|
+
"simple-get": "^3.0.3",
|
|
98
|
+
"tar": "^4.4.6",
|
|
93
99
|
"tunnel-agent": "^0.6.0"
|
|
94
100
|
},
|
|
95
101
|
"devDependencies": {
|
|
96
102
|
"async": "^2.6.1",
|
|
97
103
|
"cc": "^1.0.2",
|
|
98
104
|
"decompress-zip": "^0.3.1",
|
|
99
|
-
"documentation": "^8.
|
|
105
|
+
"documentation": "^8.1.2",
|
|
100
106
|
"exif-reader": "^1.0.2",
|
|
101
107
|
"icc": "^1.0.0",
|
|
102
108
|
"mocha": "^5.2.0",
|
|
103
|
-
"
|
|
104
|
-
"
|
|
109
|
+
"mock-fs": "^4.7.0",
|
|
110
|
+
"nyc": "^13.1.0",
|
|
111
|
+
"prebuild": "^8.1.0",
|
|
105
112
|
"prebuild-ci": "^2.2.3",
|
|
106
113
|
"rimraf": "^2.6.2",
|
|
107
114
|
"semistandard": "^12.0.1"
|
|
108
115
|
},
|
|
109
116
|
"license": "Apache-2.0",
|
|
110
117
|
"config": {
|
|
111
|
-
"libvips": "8.
|
|
118
|
+
"libvips": "8.7.0"
|
|
112
119
|
},
|
|
113
120
|
"engines": {
|
|
114
|
-
"node": ">=
|
|
121
|
+
"node": ">=6"
|
|
115
122
|
},
|
|
116
123
|
"semistandard": {
|
|
117
124
|
"env": [
|