sharp 0.30.0 → 0.30.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.
- package/README.md +3 -3
- package/binding.gyp +0 -2
- package/lib/colour.js +9 -0
- package/lib/composite.js +16 -1
- package/lib/constructor.js +5 -2
- package/lib/input.js +16 -5
- package/lib/libvips.js +8 -3
- package/lib/operation.js +136 -28
- package/lib/output.js +1 -0
- package/lib/sharp.js +1 -1
- package/lib/utility.js +2 -2
- package/package.json +5 -5
- package/src/common.cc +13 -4
- package/src/common.h +1 -1
- package/src/operations.cc +10 -3
- package/src/operations.h +2 -1
- package/src/pipeline.cc +42 -47
- package/src/pipeline.h +12 -6
- package/src/sharp.cc +0 -16
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# sharp
|
|
2
2
|
|
|
3
|
-
<img src="https://cdn.jsdelivr.net/gh/lovell/sharp@
|
|
3
|
+
<img src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
|
|
4
4
|
|
|
5
5
|
The typical use case for this high speed Node.js module
|
|
6
6
|
is to convert large images in common formats to
|
|
@@ -95,10 +95,10 @@ readableStream
|
|
|
95
95
|
|
|
96
96
|
## Contributing
|
|
97
97
|
|
|
98
|
-
A [guide for contributors](https://github.com/lovell/sharp/blob/
|
|
98
|
+
A [guide for contributors](https://github.com/lovell/sharp/blob/main/.github/CONTRIBUTING.md)
|
|
99
99
|
covers reporting bugs, requesting features and submitting code changes.
|
|
100
100
|
|
|
101
|
-
[](https://coveralls.io/r/lovell/sharp?branch=main)
|
|
102
102
|
[](https://nodejs.org/dist/latest/docs/api/n-api.html#n_api_n_api_version_matrix)
|
|
103
103
|
|
|
104
104
|
## Licensing
|
package/binding.gyp
CHANGED
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
'VCCLCompilerTool': {
|
|
40
40
|
'ExceptionHandling': 1,
|
|
41
41
|
'Optimization': 1,
|
|
42
|
-
'RuntimeLibrary': '2', # /MD
|
|
43
42
|
'WholeProgramOptimization': 'true'
|
|
44
43
|
},
|
|
45
44
|
'VCLibrarianTool': {
|
|
@@ -206,7 +205,6 @@
|
|
|
206
205
|
'VCCLCompilerTool': {
|
|
207
206
|
'ExceptionHandling': 1,
|
|
208
207
|
'Optimization': 1,
|
|
209
|
-
'RuntimeLibrary': '2', # /MD
|
|
210
208
|
'WholeProgramOptimization': 'true'
|
|
211
209
|
},
|
|
212
210
|
'VCLibrarianTool': {
|
package/lib/colour.js
CHANGED
|
@@ -19,6 +19,11 @@ const colourspace = {
|
|
|
19
19
|
* Tint the image using the provided chroma while preserving the image luminance.
|
|
20
20
|
* An alpha channel may be present and will be unchanged by the operation.
|
|
21
21
|
*
|
|
22
|
+
* @example
|
|
23
|
+
* const output = await sharp(input)
|
|
24
|
+
* .tint({ r: 255, g: 240, b: 16 })
|
|
25
|
+
* .toBuffer();
|
|
26
|
+
*
|
|
22
27
|
* @param {string|Object} rgb - parsed by the [color](https://www.npmjs.org/package/color) module to extract chroma values.
|
|
23
28
|
* @returns {Sharp}
|
|
24
29
|
* @throws {Error} Invalid parameter
|
|
@@ -37,6 +42,10 @@ function tint (rgb) {
|
|
|
37
42
|
* This may be overridden by other sharp operations such as `toColourspace('b-w')`,
|
|
38
43
|
* which will produce an output image containing one color channel.
|
|
39
44
|
* An alpha channel may be present, and will be unchanged by the operation.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const output = await sharp(input).greyscale().toBuffer();
|
|
48
|
+
*
|
|
40
49
|
* @param {Boolean} [greyscale=true]
|
|
41
50
|
* @returns {Sharp}
|
|
42
51
|
*/
|
package/lib/composite.js
CHANGED
|
@@ -56,6 +56,21 @@ const blend = {
|
|
|
56
56
|
* @since 0.22.0
|
|
57
57
|
*
|
|
58
58
|
* @example
|
|
59
|
+
* await sharp(background)
|
|
60
|
+
* .composite([
|
|
61
|
+
* { input: layer1, gravity: 'northwest' },
|
|
62
|
+
* { input: layer2, gravity: 'southeast' },
|
|
63
|
+
* ])
|
|
64
|
+
* .toFile('combined.png');
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const output = await sharp('input.gif', { animated: true })
|
|
68
|
+
* .composite([
|
|
69
|
+
* { input: 'overlay.png', tile: true, blend: 'saturate' }
|
|
70
|
+
* ])
|
|
71
|
+
* .toBuffer();
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
59
74
|
* sharp('input.png')
|
|
60
75
|
* .rotate(180)
|
|
61
76
|
* .resize(300)
|
|
@@ -89,6 +104,7 @@ const blend = {
|
|
|
89
104
|
* @param {Number} [images[].raw.width]
|
|
90
105
|
* @param {Number} [images[].raw.height]
|
|
91
106
|
* @param {Number} [images[].raw.channels]
|
|
107
|
+
* @param {boolean} [images[].animated=false] - Set to `true` to read all frames/pages of an animated image.
|
|
92
108
|
* @param {boolean} [images[].failOnError=true] - @see {@link /api-constructor#parameters|constructor parameters}
|
|
93
109
|
* @param {number|boolean} [images[].limitInputPixels=268402689] - @see {@link /api-constructor#parameters|constructor parameters}
|
|
94
110
|
* @returns {Sharp}
|
|
@@ -162,7 +178,6 @@ function composite (images) {
|
|
|
162
178
|
throw is.invalidParameterError('premultiplied', 'boolean', image.premultiplied);
|
|
163
179
|
}
|
|
164
180
|
}
|
|
165
|
-
|
|
166
181
|
return composite;
|
|
167
182
|
});
|
|
168
183
|
return this;
|
package/lib/constructor.js
CHANGED
|
@@ -186,8 +186,11 @@ const Sharp = function (input, options) {
|
|
|
186
186
|
medianSize: 0,
|
|
187
187
|
blurSigma: 0,
|
|
188
188
|
sharpenSigma: 0,
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
sharpenM1: 1,
|
|
190
|
+
sharpenM2: 2,
|
|
191
|
+
sharpenX1: 2,
|
|
192
|
+
sharpenY2: 10,
|
|
193
|
+
sharpenY3: 20,
|
|
191
194
|
threshold: 0,
|
|
192
195
|
thresholdGrayscale: true,
|
|
193
196
|
trimThreshold: 0,
|
package/lib/input.js
CHANGED
|
@@ -299,8 +299,8 @@ function _isStreamInput () {
|
|
|
299
299
|
*
|
|
300
300
|
* - `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
|
|
301
301
|
* - `size`: Total size of image in bytes, for Stream and Buffer input only
|
|
302
|
-
* - `width`: Number of pixels wide (EXIF orientation is not taken into consideration)
|
|
303
|
-
* - `height`: Number of pixels high (EXIF orientation is not taken into consideration)
|
|
302
|
+
* - `width`: Number of pixels wide (EXIF orientation is not taken into consideration, see example below)
|
|
303
|
+
* - `height`: Number of pixels high (EXIF orientation is not taken into consideration, see example below)
|
|
304
304
|
* - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsInterpretation)
|
|
305
305
|
* - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
|
|
306
306
|
* - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsBandFormat)
|
|
@@ -343,6 +343,17 @@ function _isStreamInput () {
|
|
|
343
343
|
* // data contains a WebP image half the width and height of the original JPEG
|
|
344
344
|
* });
|
|
345
345
|
*
|
|
346
|
+
* @example
|
|
347
|
+
* // Based on EXIF rotation metadata, get the right-side-up width and height:
|
|
348
|
+
*
|
|
349
|
+
* const size = getNormalSize(await sharp(input).metadata());
|
|
350
|
+
*
|
|
351
|
+
* function getNormalSize({ width, height, orientation }) {
|
|
352
|
+
* return orientation || 0 >= 5
|
|
353
|
+
* ? { width: height, height: width }
|
|
354
|
+
* : { width, height };
|
|
355
|
+
* }
|
|
356
|
+
*
|
|
346
357
|
* @param {Function} [callback] - called with the arguments `(err, metadata)`
|
|
347
358
|
* @returns {Promise<Object>|Sharp}
|
|
348
359
|
*/
|
|
@@ -401,9 +412,9 @@ function metadata (callback) {
|
|
|
401
412
|
* - `maxX` (x-coordinate of one of the pixel where the maximum lies)
|
|
402
413
|
* - `maxY` (y-coordinate of one of the pixel where the maximum lies)
|
|
403
414
|
* - `isOpaque`: Is the image fully opaque? Will be `true` if the image has no alpha channel or if every pixel is fully opaque.
|
|
404
|
-
* - `entropy`: Histogram-based estimation of greyscale entropy, discarding alpha channel if any
|
|
405
|
-
* - `sharpness`: Estimation of greyscale sharpness based on the standard deviation of a Laplacian convolution, discarding alpha channel if any
|
|
406
|
-
* - `dominant`: Object containing most dominant sRGB colour based on a 4096-bin 3D histogram
|
|
415
|
+
* - `entropy`: Histogram-based estimation of greyscale entropy, discarding alpha channel if any.
|
|
416
|
+
* - `sharpness`: Estimation of greyscale sharpness based on the standard deviation of a Laplacian convolution, discarding alpha channel if any.
|
|
417
|
+
* - `dominant`: Object containing most dominant sRGB colour based on a 4096-bin 3D histogram.
|
|
407
418
|
*
|
|
408
419
|
* **Note**: Statistics are derived from the original input image. Any operations performed on the image must first be
|
|
409
420
|
* written to a buffer in order to run `stats` on the result (see third example).
|
package/lib/libvips.js
CHANGED
|
@@ -86,9 +86,14 @@ const removeVendoredLibvips = function () {
|
|
|
86
86
|
const pkgConfigPath = function () {
|
|
87
87
|
if (process.platform !== 'win32') {
|
|
88
88
|
const brewPkgConfigPath = spawnSync('which brew >/dev/null 2>&1 && eval $(brew --env) && echo $PKG_CONFIG_LIBDIR', spawnSyncOptions).stdout || '';
|
|
89
|
-
return [
|
|
90
|
-
.
|
|
91
|
-
.
|
|
89
|
+
return [
|
|
90
|
+
brewPkgConfigPath.trim(),
|
|
91
|
+
env.PKG_CONFIG_PATH,
|
|
92
|
+
'/usr/local/lib/pkgconfig',
|
|
93
|
+
'/usr/lib/pkgconfig',
|
|
94
|
+
'/usr/local/libdata/pkgconfig',
|
|
95
|
+
'/usr/libdata/pkgconfig'
|
|
96
|
+
].filter(Boolean).join(':');
|
|
92
97
|
} else {
|
|
93
98
|
return '';
|
|
94
99
|
}
|
package/lib/operation.js
CHANGED
|
@@ -63,6 +63,10 @@ function rotate (angle, options) {
|
|
|
63
63
|
/**
|
|
64
64
|
* Flip the image about the vertical Y axis. This always occurs after rotation, if any.
|
|
65
65
|
* The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* const output = await sharp(input).flip().toBuffer();
|
|
69
|
+
*
|
|
66
70
|
* @param {Boolean} [flip=true]
|
|
67
71
|
* @returns {Sharp}
|
|
68
72
|
*/
|
|
@@ -74,6 +78,10 @@ function flip (flip) {
|
|
|
74
78
|
/**
|
|
75
79
|
* Flop the image about the horizontal X axis. This always occurs after rotation, if any.
|
|
76
80
|
* The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* const output = await sharp(input).flop().toBuffer();
|
|
84
|
+
*
|
|
77
85
|
* @param {Boolean} [flop=true]
|
|
78
86
|
* @returns {Sharp}
|
|
79
87
|
*/
|
|
@@ -185,40 +193,107 @@ function affine (matrix, options) {
|
|
|
185
193
|
* When a `sigma` is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space.
|
|
186
194
|
* Separate control over the level of sharpening in "flat" and "jagged" areas is available.
|
|
187
195
|
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
* @
|
|
196
|
+
* See {@link https://www.libvips.org/API/current/libvips-convolution.html#vips-sharpen|libvips sharpen} operation.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* const data = await sharp(input).sharpen().toBuffer();
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* const data = await sharp(input).sharpen({ sigma: 2 }).toBuffer();
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* const data = await sharp(input)
|
|
206
|
+
* .sharpen({
|
|
207
|
+
* sigma: 2,
|
|
208
|
+
* m1: 0
|
|
209
|
+
* m2: 3,
|
|
210
|
+
* x1: 3,
|
|
211
|
+
* y2: 15,
|
|
212
|
+
* y3: 15,
|
|
213
|
+
* })
|
|
214
|
+
* .toBuffer();
|
|
215
|
+
*
|
|
216
|
+
* @param {Object|number} [options] - if present, is an Object with attributes or (deprecated) a number for `options.sigma`.
|
|
217
|
+
* @param {number} [options.sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
|
|
218
|
+
* @param {number} [options.m1=1.0] - the level of sharpening to apply to "flat" areas.
|
|
219
|
+
* @param {number} [options.m2=2.0] - the level of sharpening to apply to "jagged" areas.
|
|
220
|
+
* @param {number} [options.x1=2.0] - threshold between "flat" and "jagged"
|
|
221
|
+
* @param {number} [options.y2=10.0] - maximum amount of brightening.
|
|
222
|
+
* @param {number} [options.y3=20.0] - maximum amount of darkening.
|
|
223
|
+
* @param {number} [flat] - (deprecated) see `options.m1`.
|
|
224
|
+
* @param {number} [jagged] - (deprecated) see `options.m2`.
|
|
191
225
|
* @returns {Sharp}
|
|
192
226
|
* @throws {Error} Invalid parameters
|
|
193
227
|
*/
|
|
194
|
-
function sharpen (
|
|
195
|
-
if (!is.defined(
|
|
228
|
+
function sharpen (options, flat, jagged) {
|
|
229
|
+
if (!is.defined(options)) {
|
|
196
230
|
// No arguments: default to mild sharpen
|
|
197
231
|
this.options.sharpenSigma = -1;
|
|
198
|
-
} else if (is.bool(
|
|
199
|
-
//
|
|
200
|
-
this.options.sharpenSigma =
|
|
201
|
-
} else if (is.number(
|
|
202
|
-
//
|
|
203
|
-
this.options.sharpenSigma =
|
|
204
|
-
//
|
|
232
|
+
} else if (is.bool(options)) {
|
|
233
|
+
// Deprecated boolean argument: apply mild sharpen?
|
|
234
|
+
this.options.sharpenSigma = options ? -1 : 0;
|
|
235
|
+
} else if (is.number(options) && is.inRange(options, 0.01, 10000)) {
|
|
236
|
+
// Deprecated numeric argument: specific sigma
|
|
237
|
+
this.options.sharpenSigma = options;
|
|
238
|
+
// Deprecated control over flat areas
|
|
205
239
|
if (is.defined(flat)) {
|
|
206
240
|
if (is.number(flat) && is.inRange(flat, 0, 10000)) {
|
|
207
|
-
this.options.
|
|
241
|
+
this.options.sharpenM1 = flat;
|
|
208
242
|
} else {
|
|
209
243
|
throw is.invalidParameterError('flat', 'number between 0 and 10000', flat);
|
|
210
244
|
}
|
|
211
245
|
}
|
|
212
|
-
//
|
|
246
|
+
// Deprecated control over jagged areas
|
|
213
247
|
if (is.defined(jagged)) {
|
|
214
248
|
if (is.number(jagged) && is.inRange(jagged, 0, 10000)) {
|
|
215
|
-
this.options.
|
|
249
|
+
this.options.sharpenM2 = jagged;
|
|
216
250
|
} else {
|
|
217
251
|
throw is.invalidParameterError('jagged', 'number between 0 and 10000', jagged);
|
|
218
252
|
}
|
|
219
253
|
}
|
|
254
|
+
} else if (is.plainObject(options)) {
|
|
255
|
+
if (is.number(options.sigma) && is.inRange(options.sigma, 0.01, 10000)) {
|
|
256
|
+
this.options.sharpenSigma = options.sigma;
|
|
257
|
+
} else {
|
|
258
|
+
throw is.invalidParameterError('options.sigma', 'number between 0.01 and 10000', options.sigma);
|
|
259
|
+
}
|
|
260
|
+
if (is.defined(options.m1)) {
|
|
261
|
+
if (is.number(options.m1) && is.inRange(options.m1, 0, 10000)) {
|
|
262
|
+
this.options.sharpenM1 = options.m1;
|
|
263
|
+
} else {
|
|
264
|
+
throw is.invalidParameterError('options.m1', 'number between 0 and 10000', options.m1);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (is.defined(options.m2)) {
|
|
268
|
+
if (is.number(options.m2) && is.inRange(options.m2, 0, 10000)) {
|
|
269
|
+
this.options.sharpenM2 = options.m2;
|
|
270
|
+
} else {
|
|
271
|
+
throw is.invalidParameterError('options.m2', 'number between 0 and 10000', options.m2);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (is.defined(options.x1)) {
|
|
275
|
+
if (is.number(options.x1) && is.inRange(options.x1, 0, 10000)) {
|
|
276
|
+
this.options.sharpenX1 = options.x1;
|
|
277
|
+
} else {
|
|
278
|
+
throw is.invalidParameterError('options.x1', 'number between 0 and 10000', options.x1);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (is.defined(options.y2)) {
|
|
282
|
+
if (is.number(options.y2) && is.inRange(options.y2, 0, 10000)) {
|
|
283
|
+
this.options.sharpenY2 = options.y2;
|
|
284
|
+
} else {
|
|
285
|
+
throw is.invalidParameterError('options.y2', 'number between 0 and 10000', options.y2);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (is.defined(options.y3)) {
|
|
289
|
+
if (is.number(options.y3) && is.inRange(options.y3, 0, 10000)) {
|
|
290
|
+
this.options.sharpenY3 = options.y3;
|
|
291
|
+
} else {
|
|
292
|
+
throw is.invalidParameterError('options.y3', 'number between 0 and 10000', options.y3);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
220
295
|
} else {
|
|
221
|
-
throw is.invalidParameterError('sigma', 'number between 0.01 and 10000',
|
|
296
|
+
throw is.invalidParameterError('sigma', 'number between 0.01 and 10000', options);
|
|
222
297
|
}
|
|
223
298
|
return this;
|
|
224
299
|
}
|
|
@@ -226,6 +301,13 @@ function sharpen (sigma, flat, jagged) {
|
|
|
226
301
|
/**
|
|
227
302
|
* Apply median filter.
|
|
228
303
|
* When used without parameters the default window is 3x3.
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* const output = await sharp(input).median().toBuffer();
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* const output = await sharp(input).median(5).toBuffer();
|
|
310
|
+
*
|
|
229
311
|
* @param {number} [size=3] square mask size: size x size
|
|
230
312
|
* @returns {Sharp}
|
|
231
313
|
* @throws {Error} Invalid parameters
|
|
@@ -356,6 +438,10 @@ function negate (options) {
|
|
|
356
438
|
|
|
357
439
|
/**
|
|
358
440
|
* Enhance output image contrast by stretching its luminance to cover the full dynamic range.
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* const output = await sharp(input).normalise().toBuffer();
|
|
444
|
+
*
|
|
359
445
|
* @param {Boolean} [normalise=true]
|
|
360
446
|
* @returns {Sharp}
|
|
361
447
|
*/
|
|
@@ -366,6 +452,10 @@ function normalise (normalise) {
|
|
|
366
452
|
|
|
367
453
|
/**
|
|
368
454
|
* Alternative spelling of normalise.
|
|
455
|
+
*
|
|
456
|
+
* @example
|
|
457
|
+
* const output = await sharp(input).normalize().toBuffer();
|
|
458
|
+
*
|
|
369
459
|
* @param {Boolean} [normalize=true]
|
|
370
460
|
* @returns {Sharp}
|
|
371
461
|
*/
|
|
@@ -381,6 +471,14 @@ function normalize (normalize) {
|
|
|
381
471
|
*
|
|
382
472
|
* @since 0.28.3
|
|
383
473
|
*
|
|
474
|
+
* @example
|
|
475
|
+
* const output = await sharp(input)
|
|
476
|
+
* .clahe({
|
|
477
|
+
* width: 3,
|
|
478
|
+
* height: 3,
|
|
479
|
+
* })
|
|
480
|
+
* .toBuffer();
|
|
481
|
+
*
|
|
384
482
|
* @param {Object} options
|
|
385
483
|
* @param {number} options.width - integer width of the region in pixels.
|
|
386
484
|
* @param {number} options.height - integer height of the region in pixels.
|
|
@@ -590,28 +688,38 @@ function recomb (inputMatrix) {
|
|
|
590
688
|
* @since 0.22.1
|
|
591
689
|
*
|
|
592
690
|
* @example
|
|
593
|
-
*
|
|
691
|
+
* // increase brightness by a factor of 2
|
|
692
|
+
* const output = await sharp(input)
|
|
594
693
|
* .modulate({
|
|
595
|
-
* brightness: 2
|
|
596
|
-
* })
|
|
694
|
+
* brightness: 2
|
|
695
|
+
* })
|
|
696
|
+
* .toBuffer();
|
|
597
697
|
*
|
|
598
|
-
*
|
|
698
|
+
* @example
|
|
699
|
+
* // hue-rotate by 180 degrees
|
|
700
|
+
* const output = await sharp(input)
|
|
599
701
|
* .modulate({
|
|
600
|
-
* hue: 180
|
|
601
|
-
* })
|
|
702
|
+
* hue: 180
|
|
703
|
+
* })
|
|
704
|
+
* .toBuffer();
|
|
602
705
|
*
|
|
603
|
-
*
|
|
706
|
+
* @example
|
|
707
|
+
* // increase lightness by +50
|
|
708
|
+
* const output = await sharp(input)
|
|
604
709
|
* .modulate({
|
|
605
|
-
* lightness: 50
|
|
606
|
-
* })
|
|
710
|
+
* lightness: 50
|
|
711
|
+
* })
|
|
712
|
+
* .toBuffer();
|
|
607
713
|
*
|
|
714
|
+
* @example
|
|
608
715
|
* // decreate brightness and saturation while also hue-rotating by 90 degrees
|
|
609
|
-
* sharp(input)
|
|
716
|
+
* const output = await sharp(input)
|
|
610
717
|
* .modulate({
|
|
611
718
|
* brightness: 0.5,
|
|
612
719
|
* saturation: 0.5,
|
|
613
|
-
* hue: 90
|
|
614
|
-
* })
|
|
720
|
+
* hue: 90,
|
|
721
|
+
* })
|
|
722
|
+
* .toBuffer();
|
|
615
723
|
*
|
|
616
724
|
* @param {Object} [options]
|
|
617
725
|
* @param {number} [options.brightness] Brightness multiplier
|
package/lib/output.js
CHANGED
package/lib/sharp.js
CHANGED
|
@@ -21,7 +21,7 @@ try {
|
|
|
21
21
|
'- Consult the installation documentation: https://sharp.pixelplumbing.com/install'
|
|
22
22
|
);
|
|
23
23
|
// Check loaded
|
|
24
|
-
if (process.platform === 'win32') {
|
|
24
|
+
if (process.platform === 'win32' || /symbol/.test(err.message)) {
|
|
25
25
|
const loadedModule = Object.keys(require.cache).find((i) => /[\\/]build[\\/]Release[\\/]sharp(.*)\.node$/.test(i));
|
|
26
26
|
if (loadedModule) {
|
|
27
27
|
const [, loadedPackage] = loadedModule.match(/node_modules[\\/]([^\\/]+)[\\/]/);
|
package/lib/utility.js
CHANGED
|
@@ -30,11 +30,11 @@ const interpolators = {
|
|
|
30
30
|
bilinear: 'bilinear',
|
|
31
31
|
/** [Bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation) (the default). */
|
|
32
32
|
bicubic: 'bicubic',
|
|
33
|
-
/** [LBB interpolation](https://github.com/
|
|
33
|
+
/** [LBB interpolation](https://github.com/libvips/libvips/blob/master/libvips/resample/lbb.cpp#L100). Prevents some "[acutance](http://en.wikipedia.org/wiki/Acutance)" but typically reduces performance by a factor of 2. */
|
|
34
34
|
locallyBoundedBicubic: 'lbb',
|
|
35
35
|
/** [Nohalo interpolation](http://eprints.soton.ac.uk/268086/). Prevents acutance but typically reduces performance by a factor of 3. */
|
|
36
36
|
nohalo: 'nohalo',
|
|
37
|
-
/** [VSQBS interpolation](https://github.com/
|
|
37
|
+
/** [VSQBS interpolation](https://github.com/libvips/libvips/blob/master/libvips/resample/vsqbs.cpp#L48). Prevents "staircasing" when enlarging. */
|
|
38
38
|
vertexSplitQuadraticBasisSpline: 'vsqbs'
|
|
39
39
|
};
|
|
40
40
|
|
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, GIF, AVIF and TIFF images",
|
|
4
|
-
"version": "0.30.
|
|
4
|
+
"version": "0.30.3",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://github.com/lovell/sharp",
|
|
7
7
|
"contributors": [
|
|
@@ -126,8 +126,8 @@
|
|
|
126
126
|
"vips"
|
|
127
127
|
],
|
|
128
128
|
"dependencies": {
|
|
129
|
-
"color": "^4.2.
|
|
130
|
-
"detect-libc": "^2.0.
|
|
129
|
+
"color": "^4.2.1",
|
|
130
|
+
"detect-libc": "^2.0.1",
|
|
131
131
|
"node-addon-api": "^4.3.0",
|
|
132
132
|
"prebuild-install": "^7.0.1",
|
|
133
133
|
"semver": "^7.3.5",
|
|
@@ -143,10 +143,10 @@
|
|
|
143
143
|
"exif-reader": "^1.0.3",
|
|
144
144
|
"icc": "^2.0.0",
|
|
145
145
|
"license-checker": "^25.0.1",
|
|
146
|
-
"mocha": "^9.2.
|
|
146
|
+
"mocha": "^9.2.2",
|
|
147
147
|
"mock-fs": "^5.1.2",
|
|
148
148
|
"nyc": "^15.1.0",
|
|
149
|
-
"prebuild": "^11.0.
|
|
149
|
+
"prebuild": "^11.0.3",
|
|
150
150
|
"rimraf": "^3.0.2",
|
|
151
151
|
"semistandard": "^16.0.1"
|
|
152
152
|
},
|
package/src/common.cc
CHANGED
|
@@ -398,6 +398,10 @@ namespace sharp {
|
|
|
398
398
|
// From filesystem
|
|
399
399
|
imageType = DetermineImageType(descriptor->file.data());
|
|
400
400
|
if (imageType == ImageType::MISSING) {
|
|
401
|
+
if (descriptor->file.find("<svg") != std::string::npos) {
|
|
402
|
+
throw vips::VError("Input file is missing, did you mean "
|
|
403
|
+
"sharp(Buffer.from('" + descriptor->file.substr(0, 8) + "...')?");
|
|
404
|
+
}
|
|
401
405
|
throw vips::VError("Input file is missing");
|
|
402
406
|
}
|
|
403
407
|
if (imageType != ImageType::UNKNOWN) {
|
|
@@ -885,7 +889,7 @@ namespace sharp {
|
|
|
885
889
|
}
|
|
886
890
|
|
|
887
891
|
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
|
|
888
|
-
Canvas canvas, bool swap, bool withoutEnlargement) {
|
|
892
|
+
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction) {
|
|
889
893
|
if (swap) {
|
|
890
894
|
// Swap input width and height when requested.
|
|
891
895
|
std::swap(width, height);
|
|
@@ -940,9 +944,14 @@ namespace sharp {
|
|
|
940
944
|
}
|
|
941
945
|
}
|
|
942
946
|
|
|
943
|
-
// We should not enlarge
|
|
944
|
-
//
|
|
945
|
-
if (
|
|
947
|
+
// We should not reduce or enlarge the output image, if
|
|
948
|
+
// withoutReduction or withoutEnlargement is specified.
|
|
949
|
+
if (withoutReduction) {
|
|
950
|
+
// Equivalent of VIPS_SIZE_UP
|
|
951
|
+
hshrink = std::min(1.0, hshrink);
|
|
952
|
+
vshrink = std::min(1.0, vshrink);
|
|
953
|
+
} else if (withoutEnlargement) {
|
|
954
|
+
// Equivalent of VIPS_SIZE_DOWN
|
|
946
955
|
hshrink = std::max(1.0, hshrink);
|
|
947
956
|
vshrink = std::max(1.0, vshrink);
|
|
948
957
|
}
|
package/src/common.h
CHANGED
|
@@ -345,7 +345,7 @@ namespace sharp {
|
|
|
345
345
|
the required thumbnail width/height and canvas mode.
|
|
346
346
|
*/
|
|
347
347
|
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
|
|
348
|
-
Canvas canvas, bool swap, bool withoutEnlargement);
|
|
348
|
+
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction);
|
|
349
349
|
|
|
350
350
|
} // namespace sharp
|
|
351
351
|
|
package/src/operations.cc
CHANGED
|
@@ -209,7 +209,8 @@ namespace sharp {
|
|
|
209
209
|
/*
|
|
210
210
|
* Sharpen flat and jagged areas. Use sigma of -1.0 for fast sharpen.
|
|
211
211
|
*/
|
|
212
|
-
VImage Sharpen(VImage image, double const sigma, double const
|
|
212
|
+
VImage Sharpen(VImage image, double const sigma, double const m1, double const m2,
|
|
213
|
+
double const x1, double const y2, double const y3) {
|
|
213
214
|
if (sigma == -1.0) {
|
|
214
215
|
// Fast, mild sharpen
|
|
215
216
|
VImage sharpen = VImage::new_matrixv(3, 3,
|
|
@@ -224,8 +225,14 @@ namespace sharp {
|
|
|
224
225
|
if (colourspaceBeforeSharpen == VIPS_INTERPRETATION_RGB) {
|
|
225
226
|
colourspaceBeforeSharpen = VIPS_INTERPRETATION_sRGB;
|
|
226
227
|
}
|
|
227
|
-
return image
|
|
228
|
-
VImage::option()
|
|
228
|
+
return image
|
|
229
|
+
.sharpen(VImage::option()
|
|
230
|
+
->set("sigma", sigma)
|
|
231
|
+
->set("m1", m1)
|
|
232
|
+
->set("m2", m2)
|
|
233
|
+
->set("x1", x1)
|
|
234
|
+
->set("y2", y2)
|
|
235
|
+
->set("y3", y3))
|
|
229
236
|
.colourspace(colourspaceBeforeSharpen);
|
|
230
237
|
}
|
|
231
238
|
}
|
package/src/operations.h
CHANGED
|
@@ -64,7 +64,8 @@ namespace sharp {
|
|
|
64
64
|
/*
|
|
65
65
|
* Sharpen flat and jagged areas. Use sigma of -1.0 for fast sharpen.
|
|
66
66
|
*/
|
|
67
|
-
VImage Sharpen(VImage image, double const sigma, double const
|
|
67
|
+
VImage Sharpen(VImage image, double const sigma, double const m1, double const m2,
|
|
68
|
+
double const x1, double const y2, double const y3);
|
|
68
69
|
|
|
69
70
|
/*
|
|
70
71
|
Threshold an image
|
package/src/pipeline.cc
CHANGED
|
@@ -138,17 +138,6 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
138
138
|
pageHeight = inputHeight;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
// If withoutReduction is specified,
|
|
142
|
-
// Override target width and height if less than respective value from input file
|
|
143
|
-
if (baton->withoutReduction) {
|
|
144
|
-
if (baton->width < inputWidth) {
|
|
145
|
-
baton->width = inputWidth;
|
|
146
|
-
}
|
|
147
|
-
if (baton->height < inputHeight) {
|
|
148
|
-
baton->height = inputHeight;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
141
|
// Scaling calculations
|
|
153
142
|
double hshrink;
|
|
154
143
|
double vshrink;
|
|
@@ -161,7 +150,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
161
150
|
// Shrink to pageHeight, so we work for multi-page images
|
|
162
151
|
std::tie(hshrink, vshrink) = sharp::ResolveShrink(
|
|
163
152
|
inputWidth, pageHeight, targetResizeWidth, targetResizeHeight,
|
|
164
|
-
baton->canvas, swap, baton->withoutEnlargement);
|
|
153
|
+
baton->canvas, swap, baton->withoutEnlargement, baton->withoutReduction);
|
|
165
154
|
|
|
166
155
|
// The jpeg preload shrink.
|
|
167
156
|
int jpegShrinkOnLoad = 1;
|
|
@@ -184,7 +173,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
184
173
|
|
|
185
174
|
if (inputImageType == sharp::ImageType::JPEG) {
|
|
186
175
|
// Leave at least a factor of two for the final resize step, when fastShrinkOnLoad: false
|
|
187
|
-
// for more consistent results and avoid
|
|
176
|
+
// for more consistent results and to avoid extra sharpness to the image
|
|
188
177
|
int factor = baton->fastShrinkOnLoad ? 1 : 2;
|
|
189
178
|
if (shrink >= 8 * factor) {
|
|
190
179
|
jpegShrinkOnLoad = 8;
|
|
@@ -193,6 +182,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
193
182
|
} else if (shrink >= 2 * factor) {
|
|
194
183
|
jpegShrinkOnLoad = 2;
|
|
195
184
|
}
|
|
185
|
+
// Lower shrink-on-load for known libjpeg rounding errors
|
|
186
|
+
if (jpegShrinkOnLoad > 1 && static_cast<int>(shrink) == jpegShrinkOnLoad) {
|
|
187
|
+
jpegShrinkOnLoad /= 2;
|
|
188
|
+
}
|
|
196
189
|
} else if (inputImageType == sharp::ImageType::WEBP ||
|
|
197
190
|
inputImageType == sharp::ImageType::SVG ||
|
|
198
191
|
inputImageType == sharp::ImageType::PDF) {
|
|
@@ -270,35 +263,28 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
270
263
|
}
|
|
271
264
|
|
|
272
265
|
// Any pre-shrinking may already have been done
|
|
273
|
-
|
|
274
|
-
|
|
266
|
+
inputWidth = image.width();
|
|
267
|
+
inputHeight = image.height();
|
|
275
268
|
|
|
276
269
|
// After pre-shrink, but before the main shrink stage
|
|
277
270
|
// Reuse the initial pageHeight if we didn't pre-shrink
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if (baton->fastShrinkOnLoad && jpegShrinkOnLoad > 1) {
|
|
281
|
-
// JPEG shrink-on-load rounds the output dimensions down, which
|
|
282
|
-
// may cause incorrect dimensions when fastShrinkOnLoad is enabled
|
|
283
|
-
// Just recalculate vshrink / hshrink on the main image instead of
|
|
284
|
-
// the pre-shrunk image when this is the case
|
|
285
|
-
hshrink = static_cast<double>(thumbWidth) / (static_cast<double>(inputWidth) / hshrink);
|
|
286
|
-
vshrink = static_cast<double>(preshrunkPageHeight) / (static_cast<double>(pageHeight) / vshrink);
|
|
287
|
-
} else {
|
|
288
|
-
// Shrink to preshrunkPageHeight, so we work for multi-page images
|
|
289
|
-
std::tie(hshrink, vshrink) = sharp::ResolveShrink(
|
|
290
|
-
thumbWidth, preshrunkPageHeight, targetResizeWidth, targetResizeHeight,
|
|
291
|
-
baton->canvas, swap, baton->withoutEnlargement);
|
|
271
|
+
if (shouldPreShrink) {
|
|
272
|
+
pageHeight = sharp::GetPageHeight(image);
|
|
292
273
|
}
|
|
293
274
|
|
|
294
|
-
|
|
275
|
+
// Shrink to pageHeight, so we work for multi-page images
|
|
276
|
+
std::tie(hshrink, vshrink) = sharp::ResolveShrink(
|
|
277
|
+
inputWidth, pageHeight, targetResizeWidth, targetResizeHeight,
|
|
278
|
+
baton->canvas, swap, baton->withoutEnlargement, baton->withoutReduction);
|
|
279
|
+
|
|
280
|
+
int targetHeight = static_cast<int>(std::rint(static_cast<double>(pageHeight) / vshrink));
|
|
295
281
|
int targetPageHeight = targetHeight;
|
|
296
282
|
|
|
297
283
|
// In toilet-roll mode, we must adjust vshrink so that we exactly hit
|
|
298
|
-
//
|
|
299
|
-
if (
|
|
284
|
+
// pageHeight or we'll have pixels straddling pixel boundaries
|
|
285
|
+
if (inputHeight > pageHeight) {
|
|
300
286
|
targetHeight *= nPages;
|
|
301
|
-
vshrink = static_cast<double>(
|
|
287
|
+
vshrink = static_cast<double>(inputHeight) / targetHeight;
|
|
302
288
|
}
|
|
303
289
|
|
|
304
290
|
// Ensure we're using a device-independent colour space
|
|
@@ -306,7 +292,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
306
292
|
if (
|
|
307
293
|
sharp::HasProfile(image) &&
|
|
308
294
|
image.interpretation() != VIPS_INTERPRETATION_LABS &&
|
|
309
|
-
image.interpretation() != VIPS_INTERPRETATION_GREY16
|
|
295
|
+
image.interpretation() != VIPS_INTERPRETATION_GREY16 &&
|
|
296
|
+
image.interpretation() != VIPS_INTERPRETATION_B_W
|
|
310
297
|
) {
|
|
311
298
|
// Convert to sRGB/P3 using embedded profile
|
|
312
299
|
try {
|
|
@@ -367,7 +354,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
367
354
|
}
|
|
368
355
|
|
|
369
356
|
bool const shouldPremultiplyAlpha = sharp::HasAlpha(image) &&
|
|
370
|
-
(shouldResize || shouldBlur || shouldConv || shouldSharpen
|
|
357
|
+
(shouldResize || shouldBlur || shouldConv || shouldSharpen);
|
|
371
358
|
|
|
372
359
|
// Premultiply image alpha channel before all transformations to avoid
|
|
373
360
|
// dark fringing around bright pixels
|
|
@@ -532,12 +519,14 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
532
519
|
MultiPageUnsupported(nPages, "Affine");
|
|
533
520
|
std::vector<double> background;
|
|
534
521
|
std::tie(image, background) = sharp::ApplyAlpha(image, baton->affineBackground, shouldPremultiplyAlpha);
|
|
522
|
+
vips::VInterpolate interp = vips::VInterpolate::new_from_name(
|
|
523
|
+
const_cast<char*>(baton->affineInterpolator.data()));
|
|
535
524
|
image = image.affine(baton->affineMatrix, VImage::option()->set("background", background)
|
|
536
525
|
->set("idx", baton->affineIdx)
|
|
537
526
|
->set("idy", baton->affineIdy)
|
|
538
527
|
->set("odx", baton->affineOdx)
|
|
539
528
|
->set("ody", baton->affineOdy)
|
|
540
|
-
->set("interpolate",
|
|
529
|
+
->set("interpolate", interp));
|
|
541
530
|
}
|
|
542
531
|
|
|
543
532
|
// Extend edges
|
|
@@ -588,11 +577,14 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
588
577
|
|
|
589
578
|
// Sharpen
|
|
590
579
|
if (shouldSharpen) {
|
|
591
|
-
image = sharp::Sharpen(image, baton->sharpenSigma, baton->
|
|
580
|
+
image = sharp::Sharpen(image, baton->sharpenSigma, baton->sharpenM1, baton->sharpenM2,
|
|
581
|
+
baton->sharpenX1, baton->sharpenY2, baton->sharpenY3);
|
|
592
582
|
}
|
|
593
583
|
|
|
594
584
|
// Composite
|
|
595
585
|
if (shouldComposite) {
|
|
586
|
+
std::vector<VImage> images = { image };
|
|
587
|
+
std::vector<int> modes, xs, ys;
|
|
596
588
|
for (Composite *composite : baton->composite) {
|
|
597
589
|
VImage compositeImage;
|
|
598
590
|
sharp::ImageType compositeImageType = sharp::ImageType::UNKNOWN;
|
|
@@ -638,12 +630,12 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
638
630
|
// gravity was used for extract_area, set it back to its default value of 0
|
|
639
631
|
composite->gravity = 0;
|
|
640
632
|
}
|
|
641
|
-
// Ensure image to composite is sRGB with
|
|
633
|
+
// Ensure image to composite is sRGB with unpremultiplied alpha
|
|
642
634
|
compositeImage = compositeImage.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
643
635
|
if (!sharp::HasAlpha(compositeImage)) {
|
|
644
636
|
compositeImage = sharp::EnsureAlpha(compositeImage, 1);
|
|
645
637
|
}
|
|
646
|
-
if (
|
|
638
|
+
if (composite->premultiplied) compositeImage = compositeImage.unpremultiply();
|
|
647
639
|
// Calculate position
|
|
648
640
|
int left;
|
|
649
641
|
int top;
|
|
@@ -661,12 +653,12 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
661
653
|
std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
|
|
662
654
|
compositeImage.width(), compositeImage.height(), composite->gravity);
|
|
663
655
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
->set("y", top));
|
|
656
|
+
images.push_back(compositeImage);
|
|
657
|
+
modes.push_back(composite->mode);
|
|
658
|
+
xs.push_back(left);
|
|
659
|
+
ys.push_back(top);
|
|
669
660
|
}
|
|
661
|
+
image = image.composite(images, modes, VImage::option()->set("x", xs)->set("y", ys));
|
|
670
662
|
}
|
|
671
663
|
|
|
672
664
|
// Reverse premultiplication after all transformations:
|
|
@@ -1409,8 +1401,11 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1409
1401
|
baton->lightness = sharp::AttrAsDouble(options, "lightness");
|
|
1410
1402
|
baton->medianSize = sharp::AttrAsUint32(options, "medianSize");
|
|
1411
1403
|
baton->sharpenSigma = sharp::AttrAsDouble(options, "sharpenSigma");
|
|
1412
|
-
baton->
|
|
1413
|
-
baton->
|
|
1404
|
+
baton->sharpenM1 = sharp::AttrAsDouble(options, "sharpenM1");
|
|
1405
|
+
baton->sharpenM2 = sharp::AttrAsDouble(options, "sharpenM2");
|
|
1406
|
+
baton->sharpenX1 = sharp::AttrAsDouble(options, "sharpenX1");
|
|
1407
|
+
baton->sharpenY2 = sharp::AttrAsDouble(options, "sharpenY2");
|
|
1408
|
+
baton->sharpenY3 = sharp::AttrAsDouble(options, "sharpenY3");
|
|
1414
1409
|
baton->threshold = sharp::AttrAsInt32(options, "threshold");
|
|
1415
1410
|
baton->thresholdGrayscale = sharp::AttrAsBool(options, "thresholdGrayscale");
|
|
1416
1411
|
baton->trimThreshold = sharp::AttrAsDouble(options, "trimThreshold");
|
|
@@ -1442,7 +1437,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1442
1437
|
baton->affineIdy = sharp::AttrAsDouble(options, "affineIdy");
|
|
1443
1438
|
baton->affineOdx = sharp::AttrAsDouble(options, "affineOdx");
|
|
1444
1439
|
baton->affineOdy = sharp::AttrAsDouble(options, "affineOdy");
|
|
1445
|
-
baton->affineInterpolator =
|
|
1440
|
+
baton->affineInterpolator = sharp::AttrAsStr(options, "affineInterpolator");
|
|
1446
1441
|
baton->removeAlpha = sharp::AttrAsBool(options, "removeAlpha");
|
|
1447
1442
|
baton->ensureAlpha = sharp::AttrAsDouble(options, "ensureAlpha");
|
|
1448
1443
|
if (options.Has("boolean")) {
|
package/src/pipeline.h
CHANGED
|
@@ -90,8 +90,11 @@ struct PipelineBaton {
|
|
|
90
90
|
double lightness;
|
|
91
91
|
int medianSize;
|
|
92
92
|
double sharpenSigma;
|
|
93
|
-
double
|
|
94
|
-
double
|
|
93
|
+
double sharpenM1;
|
|
94
|
+
double sharpenM2;
|
|
95
|
+
double sharpenX1;
|
|
96
|
+
double sharpenY2;
|
|
97
|
+
double sharpenY3;
|
|
95
98
|
int threshold;
|
|
96
99
|
bool thresholdGrayscale;
|
|
97
100
|
double trimThreshold;
|
|
@@ -126,7 +129,7 @@ struct PipelineBaton {
|
|
|
126
129
|
double affineIdy;
|
|
127
130
|
double affineOdx;
|
|
128
131
|
double affineOdy;
|
|
129
|
-
|
|
132
|
+
std::string affineInterpolator;
|
|
130
133
|
int jpegQuality;
|
|
131
134
|
bool jpegProgressive;
|
|
132
135
|
std::string jpegChromaSubsampling;
|
|
@@ -234,8 +237,11 @@ struct PipelineBaton {
|
|
|
234
237
|
lightness(0),
|
|
235
238
|
medianSize(0),
|
|
236
239
|
sharpenSigma(0.0),
|
|
237
|
-
|
|
238
|
-
|
|
240
|
+
sharpenM1(1.0),
|
|
241
|
+
sharpenM2(2.0),
|
|
242
|
+
sharpenX1(2.0),
|
|
243
|
+
sharpenY2(10.0),
|
|
244
|
+
sharpenY3(20.0),
|
|
239
245
|
threshold(0),
|
|
240
246
|
thresholdGrayscale(true),
|
|
241
247
|
trimThreshold(0.0),
|
|
@@ -268,7 +274,7 @@ struct PipelineBaton {
|
|
|
268
274
|
affineIdy(0),
|
|
269
275
|
affineOdx(0),
|
|
270
276
|
affineOdy(0),
|
|
271
|
-
affineInterpolator(
|
|
277
|
+
affineInterpolator("bicubic"),
|
|
272
278
|
jpegQuality(80),
|
|
273
279
|
jpegProgressive(false),
|
|
274
280
|
jpegChromaSubsampling("4:2:0"),
|
package/src/sharp.cc
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
|
|
15
15
|
#include <napi.h>
|
|
16
|
-
#include <cstdlib>
|
|
17
16
|
#include <vips/vips8>
|
|
18
17
|
|
|
19
18
|
#include "common.h"
|
|
@@ -22,14 +21,6 @@
|
|
|
22
21
|
#include "utilities.h"
|
|
23
22
|
#include "stats.h"
|
|
24
23
|
|
|
25
|
-
#if defined(_MSC_VER) && _MSC_VER >= 1400 // MSVC 2005/8
|
|
26
|
-
static void empty_invalid_parameter_handler(const wchar_t* expression,
|
|
27
|
-
const wchar_t* function, const wchar_t* file, unsigned int line,
|
|
28
|
-
uintptr_t reserved) {
|
|
29
|
-
// No-op.
|
|
30
|
-
}
|
|
31
|
-
#endif
|
|
32
|
-
|
|
33
24
|
static void* sharp_vips_init(void*) {
|
|
34
25
|
g_setenv("VIPS_MIN_STACK_SIZE", "2m", FALSE);
|
|
35
26
|
vips_init("sharp");
|
|
@@ -43,13 +34,6 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
|
|
|
43
34
|
g_log_set_handler("VIPS", static_cast<GLogLevelFlags>(G_LOG_LEVEL_WARNING),
|
|
44
35
|
static_cast<GLogFunc>(sharp::VipsWarningCallback), nullptr);
|
|
45
36
|
|
|
46
|
-
// Tell the CRT to not exit the application when an invalid parameter is
|
|
47
|
-
// passed. The main issue is that invalid FDs will trigger this behaviour.
|
|
48
|
-
// See: https://github.com/libvips/libvips/pull/2571.
|
|
49
|
-
#if defined(_MSC_VER) && _MSC_VER >= 1400 // MSVC 2005/8
|
|
50
|
-
_set_invalid_parameter_handler(empty_invalid_parameter_handler);
|
|
51
|
-
#endif
|
|
52
|
-
|
|
53
37
|
// Methods available to JavaScript
|
|
54
38
|
exports.Set("metadata", Napi::Function::New(env, metadata));
|
|
55
39
|
exports.Set("pipeline", Napi::Function::New(env, pipeline));
|