sharp 0.31.3 → 0.32.1
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 +1 -3
- package/binding.gyp +1 -1
- package/install/can-compile.js +3 -0
- package/install/dll-copy.js +3 -0
- package/install/libvips.js +21 -15
- package/lib/agent.js +4 -1
- package/lib/channel.js +3 -0
- package/lib/colour.js +5 -1
- package/lib/composite.js +3 -0
- package/lib/constructor.js +20 -11
- package/lib/index.d.ts +1621 -0
- package/lib/index.js +3 -0
- package/lib/input.js +32 -6
- package/lib/is.js +12 -0
- package/lib/libvips.js +5 -2
- package/lib/operation.js +104 -37
- package/lib/output.js +31 -15
- package/lib/platform.js +3 -0
- package/lib/resize.js +52 -19
- package/lib/sharp.js +3 -0
- package/lib/utility.js +5 -1
- package/package.json +30 -23
- package/src/common.cc +26 -21
- package/src/common.h +19 -17
- package/src/libvips/cplusplus/vips-operators.cpp +7 -0
- package/src/metadata.cc +18 -22
- package/src/metadata.h +3 -13
- package/src/operations.cc +39 -44
- package/src/operations.h +9 -15
- package/src/pipeline.cc +88 -52
- package/src/pipeline.h +20 -15
- package/src/sharp.cc +2 -13
- package/src/stats.cc +6 -17
- package/src/stats.h +2 -13
- package/src/utilities.cc +16 -27
- package/src/utilities.h +2 -13
package/lib/index.js
CHANGED
package/lib/input.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
1
4
|
'use strict';
|
|
2
5
|
|
|
3
6
|
const color = require('color');
|
|
@@ -21,9 +24,9 @@ const align = {
|
|
|
21
24
|
* @private
|
|
22
25
|
*/
|
|
23
26
|
function _inputOptionsFromObject (obj) {
|
|
24
|
-
const { raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd } = obj;
|
|
25
|
-
return [raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd].some(is.defined)
|
|
26
|
-
? { raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd }
|
|
27
|
+
const { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd } = obj;
|
|
28
|
+
return [raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd].some(is.defined)
|
|
29
|
+
? { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd }
|
|
27
30
|
: undefined;
|
|
28
31
|
}
|
|
29
32
|
|
|
@@ -35,8 +38,9 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
35
38
|
const inputDescriptor = {
|
|
36
39
|
failOn: 'warning',
|
|
37
40
|
limitInputPixels: Math.pow(0x3FFF, 2),
|
|
41
|
+
ignoreIcc: false,
|
|
38
42
|
unlimited: false,
|
|
39
|
-
sequentialRead:
|
|
43
|
+
sequentialRead: true
|
|
40
44
|
};
|
|
41
45
|
if (is.string(input)) {
|
|
42
46
|
// filesystem
|
|
@@ -47,6 +51,11 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
47
51
|
throw Error('Input Buffer is empty');
|
|
48
52
|
}
|
|
49
53
|
inputDescriptor.buffer = input;
|
|
54
|
+
} else if (is.arrayBuffer(input)) {
|
|
55
|
+
if (input.byteLength === 0) {
|
|
56
|
+
throw Error('Input bit Array is empty');
|
|
57
|
+
}
|
|
58
|
+
inputDescriptor.buffer = Buffer.from(input, 0, input.byteLength);
|
|
50
59
|
} else if (is.typedArray(input)) {
|
|
51
60
|
if (input.length === 0) {
|
|
52
61
|
throw Error('Input Bit Array is empty');
|
|
@@ -92,6 +101,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
92
101
|
throw is.invalidParameterError('density', 'number between 1 and 100000', inputOptions.density);
|
|
93
102
|
}
|
|
94
103
|
}
|
|
104
|
+
// Ignore embeddded ICC profile
|
|
105
|
+
if (is.defined(inputOptions.ignoreIcc)) {
|
|
106
|
+
if (is.bool(inputOptions.ignoreIcc)) {
|
|
107
|
+
inputDescriptor.ignoreIcc = inputOptions.ignoreIcc;
|
|
108
|
+
} else {
|
|
109
|
+
throw is.invalidParameterError('ignoreIcc', 'boolean', inputOptions.ignoreIcc);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
95
112
|
// limitInputPixels
|
|
96
113
|
if (is.defined(inputOptions.limitInputPixels)) {
|
|
97
114
|
if (is.bool(inputOptions.limitInputPixels)) {
|
|
@@ -327,6 +344,13 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
327
344
|
throw is.invalidParameterError('text.spacing', 'number', inputOptions.text.spacing);
|
|
328
345
|
}
|
|
329
346
|
}
|
|
347
|
+
if (is.defined(inputOptions.text.wrap)) {
|
|
348
|
+
if (is.string(inputOptions.text.wrap) && is.inArray(inputOptions.text.wrap, ['word', 'char', 'wordChar', 'none'])) {
|
|
349
|
+
inputDescriptor.textWrap = inputOptions.text.wrap;
|
|
350
|
+
} else {
|
|
351
|
+
throw is.invalidParameterError('text.wrap', 'one of: word, char, wordChar, none', inputOptions.text.wrap);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
330
354
|
delete inputDescriptor.buffer;
|
|
331
355
|
} else {
|
|
332
356
|
throw new Error('Expected a valid string to create an image with text.');
|
|
@@ -387,8 +411,9 @@ function _isStreamInput () {
|
|
|
387
411
|
/**
|
|
388
412
|
* Fast access to (uncached) image metadata without decoding any compressed pixel data.
|
|
389
413
|
*
|
|
390
|
-
* This is
|
|
391
|
-
* It does not
|
|
414
|
+
* This is read from the header of the input image.
|
|
415
|
+
* It does not take into consideration any operations to be applied to the output image,
|
|
416
|
+
* such as resize or rotate.
|
|
392
417
|
*
|
|
393
418
|
* Dimensions in the response will respect the `page` and `pages` properties of the
|
|
394
419
|
* {@link /api-constructor#parameters|constructor parameters}.
|
|
@@ -423,6 +448,7 @@ function _isStreamInput () {
|
|
|
423
448
|
* - `iptc`: Buffer containing raw IPTC data, if present
|
|
424
449
|
* - `xmp`: Buffer containing raw XMP data, if present
|
|
425
450
|
* - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
|
451
|
+
* - `formatMagick`: String containing format for images loaded via *magick
|
|
426
452
|
*
|
|
427
453
|
* @example
|
|
428
454
|
* const metadata = await sharp(input).metadata();
|
package/lib/is.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
1
4
|
'use strict';
|
|
2
5
|
|
|
3
6
|
/**
|
|
@@ -71,6 +74,14 @@ const typedArray = function (val) {
|
|
|
71
74
|
return false;
|
|
72
75
|
};
|
|
73
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Is this value an ArrayBuffer object?
|
|
79
|
+
* @private
|
|
80
|
+
*/
|
|
81
|
+
const arrayBuffer = function (val) {
|
|
82
|
+
return val instanceof ArrayBuffer;
|
|
83
|
+
};
|
|
84
|
+
|
|
74
85
|
/**
|
|
75
86
|
* Is this value a non-empty string?
|
|
76
87
|
* @private
|
|
@@ -134,6 +145,7 @@ module.exports = {
|
|
|
134
145
|
bool: bool,
|
|
135
146
|
buffer: buffer,
|
|
136
147
|
typedArray: typedArray,
|
|
148
|
+
arrayBuffer: arrayBuffer,
|
|
137
149
|
string: string,
|
|
138
150
|
number: number,
|
|
139
151
|
integer: integer,
|
package/lib/libvips.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
1
4
|
'use strict';
|
|
2
5
|
|
|
3
6
|
const fs = require('fs');
|
|
@@ -85,8 +88,7 @@ const hasVendoredLibvips = function () {
|
|
|
85
88
|
|
|
86
89
|
/* istanbul ignore next */
|
|
87
90
|
const removeVendoredLibvips = function () {
|
|
88
|
-
|
|
89
|
-
rm(vendorPath, { recursive: true, maxRetries: 3, force: true });
|
|
91
|
+
fs.rmSync(vendorPath, { recursive: true, maxRetries: 3, force: true });
|
|
90
92
|
};
|
|
91
93
|
|
|
92
94
|
/* istanbul ignore next */
|
|
@@ -115,6 +117,7 @@ const useGlobalLibvips = function () {
|
|
|
115
117
|
}
|
|
116
118
|
/* istanbul ignore next */
|
|
117
119
|
if (isRosetta()) {
|
|
120
|
+
log('Detected Rosetta, skipping search for globally-installed libvips');
|
|
118
121
|
return false;
|
|
119
122
|
}
|
|
120
123
|
const globalVipsVersion = globalLibvipsVersion();
|
package/lib/operation.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
1
4
|
'use strict';
|
|
2
5
|
|
|
3
6
|
const color = require('color');
|
|
@@ -111,7 +114,7 @@ function flop (flop) {
|
|
|
111
114
|
*
|
|
112
115
|
* You must provide an array of length 4 or a 2x2 affine transformation matrix.
|
|
113
116
|
* By default, new pixels are filled with a black background. You can provide a background color with the `background` option.
|
|
114
|
-
* A particular interpolator may also be specified. Set the `interpolator` option to an attribute of the `sharp.
|
|
117
|
+
* A particular interpolator may also be specified. Set the `interpolator` option to an attribute of the `sharp.interpolators` Object e.g. `sharp.interpolators.nohalo`.
|
|
115
118
|
*
|
|
116
119
|
* In the case of a 2x2 matrix, the transform is:
|
|
117
120
|
* - X = `matrix[0, 0]` \* (x + `idx`) + `matrix[0, 1]` \* (y + `idy`) + `odx`
|
|
@@ -128,7 +131,7 @@ function flop (flop) {
|
|
|
128
131
|
* const pipeline = sharp()
|
|
129
132
|
* .affine([[1, 0.3], [0.1, 0.7]], {
|
|
130
133
|
* background: 'white',
|
|
131
|
-
*
|
|
134
|
+
* interpolator: sharp.interpolators.nohalo
|
|
132
135
|
* })
|
|
133
136
|
* .toBuffer((err, outputBuffer, info) => {
|
|
134
137
|
* // outputBuffer contains the transformed image
|
|
@@ -232,7 +235,7 @@ function affine (matrix, options) {
|
|
|
232
235
|
* .toBuffer();
|
|
233
236
|
*
|
|
234
237
|
* @param {Object|number} [options] - if present, is an Object with attributes
|
|
235
|
-
* @param {number} [options.sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`, between 0.000001 and
|
|
238
|
+
* @param {number} [options.sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`, between 0.000001 and 10
|
|
236
239
|
* @param {number} [options.m1=1.0] - the level of sharpening to apply to "flat" areas, between 0 and 1000000
|
|
237
240
|
* @param {number} [options.m2=2.0] - the level of sharpening to apply to "jagged" areas, between 0 and 1000000
|
|
238
241
|
* @param {number} [options.x1=2.0] - threshold between "flat" and "jagged", between 0 and 1000000
|
|
@@ -270,10 +273,10 @@ function sharpen (options, flat, jagged) {
|
|
|
270
273
|
}
|
|
271
274
|
}
|
|
272
275
|
} else if (is.plainObject(options)) {
|
|
273
|
-
if (is.number(options.sigma) && is.inRange(options.sigma, 0.000001,
|
|
276
|
+
if (is.number(options.sigma) && is.inRange(options.sigma, 0.000001, 10)) {
|
|
274
277
|
this.options.sharpenSigma = options.sigma;
|
|
275
278
|
} else {
|
|
276
|
-
throw is.invalidParameterError('options.sigma', 'number between 0.000001 and
|
|
279
|
+
throw is.invalidParameterError('options.sigma', 'number between 0.000001 and 10', options.sigma);
|
|
277
280
|
}
|
|
278
281
|
if (is.defined(options.m1)) {
|
|
279
282
|
if (is.number(options.m1) && is.inRange(options.m1, 0, 1000000)) {
|
|
@@ -402,6 +405,32 @@ function flatten (options) {
|
|
|
402
405
|
return this;
|
|
403
406
|
}
|
|
404
407
|
|
|
408
|
+
/**
|
|
409
|
+
* Ensure the image has an alpha channel
|
|
410
|
+
* with all white pixel values made fully transparent.
|
|
411
|
+
*
|
|
412
|
+
* Existing alpha channel values for non-white pixels remain unchanged.
|
|
413
|
+
*
|
|
414
|
+
* This feature is experimental and the API may change.
|
|
415
|
+
*
|
|
416
|
+
* @since 0.32.1
|
|
417
|
+
*
|
|
418
|
+
* @example
|
|
419
|
+
* await sharp(rgbInput)
|
|
420
|
+
* .unflatten()
|
|
421
|
+
* .toBuffer();
|
|
422
|
+
*
|
|
423
|
+
* @example
|
|
424
|
+
* await sharp(rgbInput)
|
|
425
|
+
* .threshold(128, { grayscale: false }) // converter bright pixels to white
|
|
426
|
+
* .unflatten()
|
|
427
|
+
* .toBuffer();
|
|
428
|
+
*/
|
|
429
|
+
function unflatten () {
|
|
430
|
+
this.options.unflatten = true;
|
|
431
|
+
return this;
|
|
432
|
+
}
|
|
433
|
+
|
|
405
434
|
/**
|
|
406
435
|
* Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma`
|
|
407
436
|
* then increasing the encoding (brighten) post-resize at a factor of `gamma`.
|
|
@@ -466,16 +495,50 @@ function negate (options) {
|
|
|
466
495
|
}
|
|
467
496
|
|
|
468
497
|
/**
|
|
469
|
-
* Enhance output image contrast by stretching its luminance to cover
|
|
498
|
+
* Enhance output image contrast by stretching its luminance to cover a full dynamic range.
|
|
499
|
+
*
|
|
500
|
+
* Uses a histogram-based approach, taking a default range of 1% to 99% to reduce sensitivity to noise at the extremes.
|
|
501
|
+
*
|
|
502
|
+
* Luminance values below the `lower` percentile will be underexposed by clipping to zero.
|
|
503
|
+
* Luminance values above the `upper` percentile will be overexposed by clipping to the max pixel value.
|
|
470
504
|
*
|
|
471
505
|
* @example
|
|
472
|
-
* const output = await sharp(input)
|
|
506
|
+
* const output = await sharp(input)
|
|
507
|
+
* .normalise()
|
|
508
|
+
* .toBuffer();
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* const output = await sharp(input)
|
|
512
|
+
* .normalise({ lower: 0, upper: 100 })
|
|
513
|
+
* .toBuffer();
|
|
473
514
|
*
|
|
474
|
-
* @param {
|
|
515
|
+
* @param {Object} [options]
|
|
516
|
+
* @param {number} [options.lower=1] - Percentile below which luminance values will be underexposed.
|
|
517
|
+
* @param {number} [options.upper=99] - Percentile above which luminance values will be overexposed.
|
|
475
518
|
* @returns {Sharp}
|
|
476
519
|
*/
|
|
477
|
-
function normalise (
|
|
478
|
-
|
|
520
|
+
function normalise (options) {
|
|
521
|
+
if (is.plainObject(options)) {
|
|
522
|
+
if (is.defined(options.lower)) {
|
|
523
|
+
if (is.number(options.lower) && is.inRange(options.lower, 0, 99)) {
|
|
524
|
+
this.options.normaliseLower = options.lower;
|
|
525
|
+
} else {
|
|
526
|
+
throw is.invalidParameterError('lower', 'number between 0 and 99', options.lower);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
if (is.defined(options.upper)) {
|
|
530
|
+
if (is.number(options.upper) && is.inRange(options.upper, 1, 100)) {
|
|
531
|
+
this.options.normaliseUpper = options.upper;
|
|
532
|
+
} else {
|
|
533
|
+
throw is.invalidParameterError('upper', 'number between 1 and 100', options.upper);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (this.options.normaliseLower >= this.options.normaliseUpper) {
|
|
538
|
+
throw is.invalidParameterError('range', 'lower to be less than upper',
|
|
539
|
+
`${this.options.normaliseLower} >= ${this.options.normaliseUpper}`);
|
|
540
|
+
}
|
|
541
|
+
this.options.normalise = true;
|
|
479
542
|
return this;
|
|
480
543
|
}
|
|
481
544
|
|
|
@@ -483,13 +546,17 @@ function normalise (normalise) {
|
|
|
483
546
|
* Alternative spelling of normalise.
|
|
484
547
|
*
|
|
485
548
|
* @example
|
|
486
|
-
* const output = await sharp(input)
|
|
549
|
+
* const output = await sharp(input)
|
|
550
|
+
* .normalize()
|
|
551
|
+
* .toBuffer();
|
|
487
552
|
*
|
|
488
|
-
* @param {
|
|
553
|
+
* @param {Object} [options]
|
|
554
|
+
* @param {number} [options.lower=1] - Percentile below which luminance values will be underexposed.
|
|
555
|
+
* @param {number} [options.upper=99] - Percentile above which luminance values will be overexposed.
|
|
489
556
|
* @returns {Sharp}
|
|
490
557
|
*/
|
|
491
|
-
function normalize (
|
|
492
|
-
return this.normalise(
|
|
558
|
+
function normalize (options) {
|
|
559
|
+
return this.normalise(options);
|
|
493
560
|
}
|
|
494
561
|
|
|
495
562
|
/**
|
|
@@ -509,34 +576,33 @@ function normalize (normalize) {
|
|
|
509
576
|
* .toBuffer();
|
|
510
577
|
*
|
|
511
578
|
* @param {Object} options
|
|
512
|
-
* @param {number} options.width -
|
|
513
|
-
* @param {number} options.height -
|
|
514
|
-
* @param {number} [options.maxSlope=3] -
|
|
515
|
-
* cumulative histogram. A value of 0 disables contrast limiting. Valid values
|
|
516
|
-
* are integers in the range 0-100 (inclusive)
|
|
579
|
+
* @param {number} options.width - Integral width of the search window, in pixels.
|
|
580
|
+
* @param {number} options.height - Integral height of the search window, in pixels.
|
|
581
|
+
* @param {number} [options.maxSlope=3] - Integral level of brightening, between 0 and 100, where 0 disables contrast limiting.
|
|
517
582
|
* @returns {Sharp}
|
|
518
583
|
* @throws {Error} Invalid parameters
|
|
519
584
|
*/
|
|
520
585
|
function clahe (options) {
|
|
521
|
-
if (
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
586
|
+
if (is.plainObject(options)) {
|
|
587
|
+
if (is.integer(options.width) && options.width > 0) {
|
|
588
|
+
this.options.claheWidth = options.width;
|
|
589
|
+
} else {
|
|
590
|
+
throw is.invalidParameterError('width', 'integer greater than zero', options.width);
|
|
591
|
+
}
|
|
592
|
+
if (is.integer(options.height) && options.height > 0) {
|
|
593
|
+
this.options.claheHeight = options.height;
|
|
594
|
+
} else {
|
|
595
|
+
throw is.invalidParameterError('height', 'integer greater than zero', options.height);
|
|
596
|
+
}
|
|
597
|
+
if (is.defined(options.maxSlope)) {
|
|
598
|
+
if (is.integer(options.maxSlope) && is.inRange(options.maxSlope, 0, 100)) {
|
|
599
|
+
this.options.claheMaxSlope = options.maxSlope;
|
|
600
|
+
} else {
|
|
601
|
+
throw is.invalidParameterError('maxSlope', 'integer between 0 and 100', options.maxSlope);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
538
604
|
} else {
|
|
539
|
-
|
|
605
|
+
throw is.invalidParameterError('options', 'plain object', options);
|
|
540
606
|
}
|
|
541
607
|
return this;
|
|
542
608
|
}
|
|
@@ -835,6 +901,7 @@ module.exports = function (Sharp) {
|
|
|
835
901
|
median,
|
|
836
902
|
blur,
|
|
837
903
|
flatten,
|
|
904
|
+
unflatten,
|
|
838
905
|
gamma,
|
|
839
906
|
negate,
|
|
840
907
|
normalise,
|
package/lib/output.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
1
4
|
'use strict';
|
|
2
5
|
|
|
3
6
|
const path = require('path');
|
|
@@ -40,7 +43,7 @@ const bitdepthFromColourCount = (colours) => 1 << 31 - Math.clz32(Math.ceil(Math
|
|
|
40
43
|
* Note that raw pixel data is only supported for buffer output.
|
|
41
44
|
*
|
|
42
45
|
* By default all metadata will be removed, which includes EXIF-based orientation.
|
|
43
|
-
* See {@link withMetadata} for control over this.
|
|
46
|
+
* See {@link #withmetadata|withMetadata} for control over this.
|
|
44
47
|
*
|
|
45
48
|
* The caller is responsible for ensuring directory structures and permissions exist.
|
|
46
49
|
*
|
|
@@ -61,6 +64,7 @@ const bitdepthFromColourCount = (colours) => 1 << 31 - Math.clz32(Math.ceil(Math
|
|
|
61
64
|
* `info` contains the output image `format`, `size` (bytes), `width`, `height`,
|
|
62
65
|
* `channels` and `premultiplied` (indicating if premultiplication was used).
|
|
63
66
|
* When using a crop strategy also contains `cropOffsetLeft` and `cropOffsetTop`.
|
|
67
|
+
* When using the attention crop strategy also contains `attentionX` and `attentionY`, the focal point of the cropped region.
|
|
64
68
|
* May also contain `textAutofitDpi` (dpi the font was rendered at) if image was created from text.
|
|
65
69
|
* @returns {Promise<Object>} - when no callback is provided
|
|
66
70
|
* @throws {Error} Invalid parameters
|
|
@@ -91,12 +95,12 @@ function toFile (fileOut, callback) {
|
|
|
91
95
|
* Write output to a Buffer.
|
|
92
96
|
* JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
|
|
93
97
|
*
|
|
94
|
-
* Use {@link toFormat} or one of the format-specific functions such as {@link jpeg}, {@link png} etc. to set the output format.
|
|
98
|
+
* Use {@link #toformat|toFormat} or one of the format-specific functions such as {@link jpeg}, {@link png} etc. to set the output format.
|
|
95
99
|
*
|
|
96
100
|
* If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.
|
|
97
101
|
*
|
|
98
102
|
* By default all metadata will be removed, which includes EXIF-based orientation.
|
|
99
|
-
* See {@link withMetadata} for control over this.
|
|
103
|
+
* See {@link #withmetadata|withMetadata} for control over this.
|
|
100
104
|
*
|
|
101
105
|
* `callback`, if present, gets three arguments `(err, data, info)` where:
|
|
102
106
|
* - `err` is an error, if any.
|
|
@@ -173,12 +177,18 @@ function toBuffer (options, callback) {
|
|
|
173
177
|
* .then(info => { ... });
|
|
174
178
|
*
|
|
175
179
|
* @example
|
|
176
|
-
* // Set
|
|
180
|
+
* // Set output EXIF metadata
|
|
177
181
|
* const data = await sharp(input)
|
|
178
182
|
* .withMetadata({
|
|
179
183
|
* exif: {
|
|
180
184
|
* IFD0: {
|
|
181
|
-
* Copyright: '
|
|
185
|
+
* Copyright: 'The National Gallery'
|
|
186
|
+
* },
|
|
187
|
+
* IFD3: {
|
|
188
|
+
* GPSLatitudeRef: 'N',
|
|
189
|
+
* GPSLatitude: '51/1 30/1 3230/100',
|
|
190
|
+
* GPSLongitudeRef: 'W',
|
|
191
|
+
* GPSLongitude: '0/1 7/1 4366/100'
|
|
182
192
|
* }
|
|
183
193
|
* }
|
|
184
194
|
* })
|
|
@@ -192,7 +202,7 @@ function toBuffer (options, callback) {
|
|
|
192
202
|
*
|
|
193
203
|
* @param {Object} [options]
|
|
194
204
|
* @param {number} [options.orientation] value between 1 and 8, used to update the EXIF `Orientation` tag.
|
|
195
|
-
* @param {string} [options.icc]
|
|
205
|
+
* @param {string} [options.icc='srgb'] Filesystem path to output ICC profile, relative to `process.cwd()`, defaults to built-in sRGB.
|
|
196
206
|
* @param {Object<Object>} [options.exif={}] Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
|
|
197
207
|
* @param {number} [options.density] Number of pixels per inch (DPI).
|
|
198
208
|
* @returns {Sharp}
|
|
@@ -559,8 +569,8 @@ function webp (options) {
|
|
|
559
569
|
* .toFile('optim.gif');
|
|
560
570
|
*
|
|
561
571
|
* @param {Object} [options] - output options
|
|
562
|
-
* @param {boolean} [options.
|
|
563
|
-
* @param {boolean} [options.
|
|
572
|
+
* @param {boolean} [options.reuse=true] - re-use existing palette, otherwise generate new (slow)
|
|
573
|
+
* @param {boolean} [options.progressive=false] - use progressive (interlace) scan
|
|
564
574
|
* @param {number} [options.colours=256] - maximum number of palette entries, including transparency, between 2 and 256
|
|
565
575
|
* @param {number} [options.colors=256] - alternative spelling of `options.colours`
|
|
566
576
|
* @param {number} [options.effort=7] - CPU effort, between 1 (fastest) and 10 (slowest)
|
|
@@ -575,10 +585,11 @@ function webp (options) {
|
|
|
575
585
|
*/
|
|
576
586
|
function gif (options) {
|
|
577
587
|
if (is.object(options)) {
|
|
578
|
-
if (is.defined(options.
|
|
579
|
-
this._setBooleanOption('
|
|
580
|
-
}
|
|
581
|
-
|
|
588
|
+
if (is.defined(options.reuse)) {
|
|
589
|
+
this._setBooleanOption('gifReuse', options.reuse);
|
|
590
|
+
}
|
|
591
|
+
if (is.defined(options.progressive)) {
|
|
592
|
+
this._setBooleanOption('gifProgressive', options.progressive);
|
|
582
593
|
}
|
|
583
594
|
const colours = options.colours || options.colors;
|
|
584
595
|
if (is.defined(colours)) {
|
|
@@ -621,6 +632,7 @@ function gif (options) {
|
|
|
621
632
|
return this._updateFormatOut('gif', options);
|
|
622
633
|
}
|
|
623
634
|
|
|
635
|
+
/* istanbul ignore next */
|
|
624
636
|
/**
|
|
625
637
|
* Use these JP2 options for output image.
|
|
626
638
|
*
|
|
@@ -654,7 +666,6 @@ function gif (options) {
|
|
|
654
666
|
* @returns {Sharp}
|
|
655
667
|
* @throws {Error} Invalid options
|
|
656
668
|
*/
|
|
657
|
-
/* istanbul ignore next */
|
|
658
669
|
function jp2 (options) {
|
|
659
670
|
if (!this.constructor.format.jp2k.output.buffer) {
|
|
660
671
|
throw errJp2Save();
|
|
@@ -690,7 +701,7 @@ function jp2 (options) {
|
|
|
690
701
|
}
|
|
691
702
|
if (is.defined(options.chromaSubsampling)) {
|
|
692
703
|
if (is.string(options.chromaSubsampling) && is.inArray(options.chromaSubsampling, ['4:2:0', '4:4:4'])) {
|
|
693
|
-
this.options.
|
|
704
|
+
this.options.jp2ChromaSubsampling = options.chromaSubsampling;
|
|
694
705
|
} else {
|
|
695
706
|
throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling);
|
|
696
707
|
}
|
|
@@ -735,7 +746,8 @@ function trySetAnimationOptions (source, target) {
|
|
|
735
746
|
/**
|
|
736
747
|
* Use these TIFF options for output image.
|
|
737
748
|
*
|
|
738
|
-
* The `density` can be set in pixels/inch via {@link withMetadata}
|
|
749
|
+
* The `density` can be set in pixels/inch via {@link #withmetadata|withMetadata}
|
|
750
|
+
* instead of providing `xres` and `yres` in pixels/mm.
|
|
739
751
|
*
|
|
740
752
|
* @example
|
|
741
753
|
* // Convert SVG input to LZW-compressed, 1 bit per pixel TIFF output
|
|
@@ -1051,6 +1063,10 @@ function raw (options) {
|
|
|
1051
1063
|
*
|
|
1052
1064
|
* The container will be set to `zip` when the output is a Buffer or Stream, otherwise it will default to `fs`.
|
|
1053
1065
|
*
|
|
1066
|
+
* Requires libvips compiled with support for libgsf.
|
|
1067
|
+
* The prebuilt binaries do not include this - see
|
|
1068
|
+
* {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}.
|
|
1069
|
+
*
|
|
1054
1070
|
* @example
|
|
1055
1071
|
* sharp('input.tiff')
|
|
1056
1072
|
* .png()
|
package/lib/platform.js
CHANGED
package/lib/resize.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
1
4
|
'use strict';
|
|
2
5
|
|
|
3
6
|
const is = require('./is');
|
|
@@ -36,6 +39,18 @@ const position = {
|
|
|
36
39
|
'left top': 8
|
|
37
40
|
};
|
|
38
41
|
|
|
42
|
+
/**
|
|
43
|
+
* How to extend the image.
|
|
44
|
+
* @member
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
const extendWith = {
|
|
48
|
+
background: 'background',
|
|
49
|
+
copy: 'copy',
|
|
50
|
+
repeat: 'repeat',
|
|
51
|
+
mirror: 'mirror'
|
|
52
|
+
};
|
|
53
|
+
|
|
39
54
|
/**
|
|
40
55
|
* Strategies for automagic cover behaviour.
|
|
41
56
|
* @member
|
|
@@ -103,7 +118,7 @@ function isResizeExpected (options) {
|
|
|
103
118
|
* Resize image to `width`, `height` or `width x height`.
|
|
104
119
|
*
|
|
105
120
|
* When both a `width` and `height` are provided, the possible methods by which the image should **fit** these are:
|
|
106
|
-
* - `cover`: (default) Preserving aspect ratio, ensure the image covers both provided dimensions by cropping/clipping to fit.
|
|
121
|
+
* - `cover`: (default) Preserving aspect ratio, attempt to ensure the image covers both provided dimensions by cropping/clipping to fit.
|
|
107
122
|
* - `contain`: Preserving aspect ratio, contain within both provided dimensions using "letterboxing" where necessary.
|
|
108
123
|
* - `fill`: Ignore the aspect ratio of the input and stretch to both provided dimensions.
|
|
109
124
|
* - `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.
|
|
@@ -216,32 +231,32 @@ function isResizeExpected (options) {
|
|
|
216
231
|
* .toBuffer()
|
|
217
232
|
* );
|
|
218
233
|
*
|
|
219
|
-
* @param {number} [width] - pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
|
|
220
|
-
* @param {number} [height] - pixels high the resultant image should be. Use `null` or `undefined` to auto-scale the height to match the width.
|
|
234
|
+
* @param {number} [width] - How many pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
|
|
235
|
+
* @param {number} [height] - How many pixels high the resultant image should be. Use `null` or `undefined` to auto-scale the height to match the width.
|
|
221
236
|
* @param {Object} [options]
|
|
222
|
-
* @param {
|
|
223
|
-
* @param {
|
|
224
|
-
* @param {String} [options.fit='cover'] -
|
|
225
|
-
* @param {String} [options.position='centre'] - position, gravity or strategy to use when `fit` is `cover` or `contain`.
|
|
237
|
+
* @param {number} [options.width] - An alternative means of specifying `width`. If both are present this takes priority.
|
|
238
|
+
* @param {number} [options.height] - An alternative means of specifying `height`. If both are present this takes priority.
|
|
239
|
+
* @param {String} [options.fit='cover'] - How the image should be resized/cropped to fit the target dimension(s), one of `cover`, `contain`, `fill`, `inside` or `outside`.
|
|
240
|
+
* @param {String} [options.position='centre'] - A position, gravity or strategy to use when `fit` is `cover` or `contain`.
|
|
226
241
|
* @param {String|Object} [options.background={r: 0, g: 0, b: 0, alpha: 1}] - background colour when `fit` is `contain`, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black without transparency.
|
|
227
|
-
* @param {String} [options.kernel='lanczos3'] -
|
|
228
|
-
* @param {Boolean} [options.withoutEnlargement=false] -
|
|
229
|
-
* @param {Boolean} [options.withoutReduction=false] -
|
|
230
|
-
* @param {Boolean} [options.fastShrinkOnLoad=true] -
|
|
242
|
+
* @param {String} [options.kernel='lanczos3'] - The kernel to use for image reduction. Use the `fastShrinkOnLoad` option to control kernel vs shrink-on-load.
|
|
243
|
+
* @param {Boolean} [options.withoutEnlargement=false] - Do not scale up if the width *or* height are already less than the target dimensions, equivalent to GraphicsMagick's `>` geometry option. This may result in output dimensions smaller than the target dimensions.
|
|
244
|
+
* @param {Boolean} [options.withoutReduction=false] - Do not scale down if the width *or* height are already greater than the target dimensions, equivalent to GraphicsMagick's `<` geometry option. This may still result in a crop to reach the target dimensions.
|
|
245
|
+
* @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 or round-down of an auto-scaled dimension.
|
|
231
246
|
* @returns {Sharp}
|
|
232
247
|
* @throws {Error} Invalid parameters
|
|
233
248
|
*/
|
|
234
|
-
function resize (
|
|
249
|
+
function resize (widthOrOptions, height, options) {
|
|
235
250
|
if (isResizeExpected(this.options)) {
|
|
236
251
|
this.options.debuglog('ignoring previous resize options');
|
|
237
252
|
}
|
|
238
|
-
if (is.defined(
|
|
239
|
-
if (is.object(
|
|
240
|
-
options =
|
|
241
|
-
} else if (is.integer(
|
|
242
|
-
this.options.width =
|
|
253
|
+
if (is.defined(widthOrOptions)) {
|
|
254
|
+
if (is.object(widthOrOptions) && !is.defined(options)) {
|
|
255
|
+
options = widthOrOptions;
|
|
256
|
+
} else if (is.integer(widthOrOptions) && widthOrOptions > 0) {
|
|
257
|
+
this.options.width = widthOrOptions;
|
|
243
258
|
} else {
|
|
244
|
-
throw is.invalidParameterError('width', 'positive integer',
|
|
259
|
+
throw is.invalidParameterError('width', 'positive integer', widthOrOptions);
|
|
245
260
|
}
|
|
246
261
|
} else {
|
|
247
262
|
this.options.width = -1;
|
|
@@ -322,7 +337,8 @@ function resize (width, height, options) {
|
|
|
322
337
|
}
|
|
323
338
|
|
|
324
339
|
/**
|
|
325
|
-
*
|
|
340
|
+
* Extend / pad / extrude one or more edges of the image with either
|
|
341
|
+
* the provided background colour or pixels derived from the image.
|
|
326
342
|
* This operation will always occur after resizing and extraction, if any.
|
|
327
343
|
*
|
|
328
344
|
* @example
|
|
@@ -348,11 +364,21 @@ function resize (width, height, options) {
|
|
|
348
364
|
* })
|
|
349
365
|
* ...
|
|
350
366
|
*
|
|
367
|
+
* @example
|
|
368
|
+
* // Extrude image by 8 pixels to the right, mirroring existing right hand edge
|
|
369
|
+
* sharp(input)
|
|
370
|
+
* .extend({
|
|
371
|
+
* right: 8,
|
|
372
|
+
* background: 'mirror'
|
|
373
|
+
* })
|
|
374
|
+
* ...
|
|
375
|
+
*
|
|
351
376
|
* @param {(number|Object)} extend - single pixel count to add to all edges or an Object with per-edge counts
|
|
352
377
|
* @param {number} [extend.top=0]
|
|
353
378
|
* @param {number} [extend.left=0]
|
|
354
379
|
* @param {number} [extend.bottom=0]
|
|
355
380
|
* @param {number} [extend.right=0]
|
|
381
|
+
* @param {String} [extend.extendWith='background'] - populate new pixels using this method, one of: background, copy, repeat, mirror.
|
|
356
382
|
* @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.
|
|
357
383
|
* @returns {Sharp}
|
|
358
384
|
* @throws {Error} Invalid parameters
|
|
@@ -393,6 +419,13 @@ function extend (extend) {
|
|
|
393
419
|
}
|
|
394
420
|
}
|
|
395
421
|
this._setBackgroundColourOption('extendBackground', extend.background);
|
|
422
|
+
if (is.defined(extend.extendWith)) {
|
|
423
|
+
if (is.string(extendWith[extend.extendWith])) {
|
|
424
|
+
this.options.extendWith = extendWith[extend.extendWith];
|
|
425
|
+
} else {
|
|
426
|
+
throw is.invalidParameterError('extendWith', 'one of: background, copy, repeat, mirror', extend.extendWith);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
396
429
|
} else {
|
|
397
430
|
throw is.invalidParameterError('extend', 'integer or object', extend);
|
|
398
431
|
}
|