sharp 0.24.0 → 0.25.2
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 +5 -6
- package/binding.gyp +18 -3
- package/install/libvips.js +10 -8
- package/lib/channel.js +3 -2
- package/lib/composite.js +1 -2
- package/lib/constructor.js +8 -1
- package/lib/input.js +19 -37
- package/lib/libvips.js +10 -8
- package/lib/output.js +15 -4
- package/lib/resize.js +15 -3
- package/package.json +18 -12
- package/src/common.cc +46 -39
- package/src/common.h +15 -21
- package/src/metadata.cc +57 -94
- package/src/metadata.h +2 -2
- package/src/pipeline.cc +238 -294
- package/src/pipeline.h +4 -4
- package/src/sharp.cc +14 -24
- package/src/stats.cc +58 -85
- package/src/stats.h +4 -8
- package/src/utilities.cc +100 -145
- package/src/utilities.h +8 -8
package/README.md
CHANGED
|
@@ -20,8 +20,7 @@ Lanczos resampling ensures quality is not sacrificed for speed.
|
|
|
20
20
|
As well as image resizing, operations such as
|
|
21
21
|
rotation, extraction, compositing and gamma correction are available.
|
|
22
22
|
|
|
23
|
-
Most modern
|
|
24
|
-
Node versions 10, 12 and 13
|
|
23
|
+
Most modern macOS, Windows and Linux systems running Node.js v10+
|
|
25
24
|
do not require any additional install or runtime dependencies.
|
|
26
25
|
|
|
27
26
|
## Examples
|
|
@@ -90,10 +89,10 @@ readableStream
|
|
|
90
89
|
### Documentation
|
|
91
90
|
|
|
92
91
|
Visit [sharp.pixelplumbing.com](https://sharp.pixelplumbing.com/) for complete
|
|
93
|
-
[installation instructions](https://sharp.pixelplumbing.com/
|
|
94
|
-
[API documentation](https://sharp.pixelplumbing.com/
|
|
95
|
-
[benchmark tests](https://sharp.pixelplumbing.com/
|
|
96
|
-
[changelog](https://sharp.pixelplumbing.com/
|
|
92
|
+
[installation instructions](https://sharp.pixelplumbing.com/install),
|
|
93
|
+
[API documentation](https://sharp.pixelplumbing.com/api-constructor),
|
|
94
|
+
[benchmark tests](https://sharp.pixelplumbing.com/performance) and
|
|
95
|
+
[changelog](https://sharp.pixelplumbing.com/changelog).
|
|
97
96
|
|
|
98
97
|
### Contributing
|
|
99
98
|
|
package/binding.gyp
CHANGED
|
@@ -30,6 +30,9 @@
|
|
|
30
30
|
'msvs_settings': {
|
|
31
31
|
'VCCLCompilerTool': {
|
|
32
32
|
'ExceptionHandling': 1
|
|
33
|
+
},
|
|
34
|
+
'VCLinkerTool': {
|
|
35
|
+
'ImageHasSafeExceptionHandlers': 'false'
|
|
33
36
|
}
|
|
34
37
|
},
|
|
35
38
|
'msvs_disabled_warnings': [
|
|
@@ -44,7 +47,11 @@
|
|
|
44
47
|
]
|
|
45
48
|
}, {
|
|
46
49
|
'target_name': 'sharp',
|
|
50
|
+
'defines': [
|
|
51
|
+
'NAPI_VERSION=3'
|
|
52
|
+
],
|
|
47
53
|
'dependencies': [
|
|
54
|
+
'<!(node -p "require(\'node-addon-api\').gyp")',
|
|
48
55
|
'libvips-cpp'
|
|
49
56
|
],
|
|
50
57
|
'variables': {
|
|
@@ -65,11 +72,11 @@
|
|
|
65
72
|
'src/stats.cc',
|
|
66
73
|
'src/operations.cc',
|
|
67
74
|
'src/pipeline.cc',
|
|
68
|
-
'src/
|
|
69
|
-
'src/
|
|
75
|
+
'src/utilities.cc',
|
|
76
|
+
'src/sharp.cc'
|
|
70
77
|
],
|
|
71
78
|
'include_dirs': [
|
|
72
|
-
'
|
|
79
|
+
'<!@(node -p "require(\'node-addon-api\').include")',
|
|
73
80
|
],
|
|
74
81
|
'conditions': [
|
|
75
82
|
['use_global_libvips == "true"', {
|
|
@@ -189,10 +196,18 @@
|
|
|
189
196
|
'-Wno-cast-function-type'
|
|
190
197
|
]
|
|
191
198
|
}],
|
|
199
|
+
['target_arch == "arm"', {
|
|
200
|
+
'cflags_cc': [
|
|
201
|
+
'-Wno-psabi'
|
|
202
|
+
]
|
|
203
|
+
}],
|
|
192
204
|
['OS == "win"', {
|
|
193
205
|
'msvs_settings': {
|
|
194
206
|
'VCCLCompilerTool': {
|
|
195
207
|
'ExceptionHandling': 1
|
|
208
|
+
},
|
|
209
|
+
'VCLinkerTool': {
|
|
210
|
+
'ImageHasSafeExceptionHandlers': 'false'
|
|
196
211
|
}
|
|
197
212
|
},
|
|
198
213
|
'msvs_disabled_warnings': [
|
package/install/libvips.js
CHANGED
|
@@ -14,8 +14,14 @@ const agent = require('../lib/agent');
|
|
|
14
14
|
const libvips = require('../lib/libvips');
|
|
15
15
|
const platform = require('../lib/platform');
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
|
|
17
|
+
const minimumGlibcVersionByArch = {
|
|
18
|
+
arm: '2.28',
|
|
19
|
+
arm64: '2.29',
|
|
20
|
+
x64: '2.17'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
|
|
24
|
+
const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `https://github.com/lovell/sharp-libvips/releases/download/v${minimumLibvipsVersionLabelled}/`;
|
|
19
25
|
|
|
20
26
|
const fail = function (err) {
|
|
21
27
|
npmLog.error('sharp', err.message);
|
|
@@ -57,18 +63,14 @@ try {
|
|
|
57
63
|
// Is this arch/platform supported?
|
|
58
64
|
const arch = process.env.npm_config_arch || process.arch;
|
|
59
65
|
const platformAndArch = platform();
|
|
60
|
-
if (
|
|
61
|
-
throw new Error('Windows x86 (32-bit) node.exe is not supported');
|
|
62
|
-
}
|
|
63
|
-
if (arch === 'ia32') {
|
|
66
|
+
if (arch === 'ia32' && !platformAndArch.startsWith('win32')) {
|
|
64
67
|
throw new Error(`Intel Architecture 32-bit systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
65
68
|
}
|
|
66
69
|
if (platformAndArch === 'freebsd-x64' || platformAndArch === 'openbsd-x64' || platformAndArch === 'sunos-x64') {
|
|
67
70
|
throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
68
71
|
}
|
|
69
72
|
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version) {
|
|
70
|
-
|
|
71
|
-
if (semver.lt(`${detectLibc.version}.0`, minimumGlibcVersion)) {
|
|
73
|
+
if (semver.lt(`${detectLibc.version}.0`, `${minimumGlibcVersionByArch[arch]}.0`)) {
|
|
72
74
|
throw new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
73
75
|
}
|
|
74
76
|
}
|
package/lib/channel.js
CHANGED
|
@@ -54,9 +54,10 @@ function ensureAlpha () {
|
|
|
54
54
|
* @example
|
|
55
55
|
* sharp(input)
|
|
56
56
|
* .extractChannel('green')
|
|
57
|
-
* .
|
|
57
|
+
* .toColourspace('b-w')
|
|
58
|
+
* .toFile('green.jpg', function(err, info) {
|
|
58
59
|
* // info.channels === 1
|
|
59
|
-
* //
|
|
60
|
+
* // green.jpg is a greyscale image containing the green channel of the input
|
|
60
61
|
* });
|
|
61
62
|
*
|
|
62
63
|
* @param {Number|String} channel - zero-indexed band number to extract, or `red`, `green` or `blue` as alternative to `0`, `1` or `2` respectively.
|
package/lib/composite.js
CHANGED
|
@@ -100,8 +100,7 @@ function composite (images) {
|
|
|
100
100
|
if (!is.object(image)) {
|
|
101
101
|
throw is.invalidParameterError('image to composite', 'object', image);
|
|
102
102
|
}
|
|
103
|
-
const
|
|
104
|
-
const inputOptions = (raw || density) ? { raw, density } : undefined;
|
|
103
|
+
const inputOptions = this._inputOptionsFromObject(image);
|
|
105
104
|
const composite = {
|
|
106
105
|
input: this._createInputDescriptor(image.input, inputOptions, { allowStream: false }),
|
|
107
106
|
blend: 'over',
|
package/lib/constructor.js
CHANGED
|
@@ -16,6 +16,8 @@ try {
|
|
|
16
16
|
help.push('- Ensure the version of Node.js used at install time matches that used at runtime');
|
|
17
17
|
} else if (/invalid ELF header/.test(err.message)) {
|
|
18
18
|
help.push(`- Ensure "${process.platform}" is used at install time as well as runtime`);
|
|
19
|
+
} else if (/dylib/.test(err.message) && /Incompatible library version/.test(err.message)) {
|
|
20
|
+
help.push('- Run "brew update && brew upgrade vips"');
|
|
19
21
|
} else if (/Cannot find module/.test(err.message)) {
|
|
20
22
|
help.push('- Run "npm rebuild --verbose sharp" and look for errors');
|
|
21
23
|
} else {
|
|
@@ -161,7 +163,7 @@ const Sharp = function (input, options) {
|
|
|
161
163
|
gamma: 0,
|
|
162
164
|
gammaOut: 0,
|
|
163
165
|
greyscale: false,
|
|
164
|
-
normalise:
|
|
166
|
+
normalise: false,
|
|
165
167
|
brightness: 1,
|
|
166
168
|
saturation: 1,
|
|
167
169
|
hue: 0,
|
|
@@ -217,6 +219,11 @@ const Sharp = function (input, options) {
|
|
|
217
219
|
heifCompression: 'hevc',
|
|
218
220
|
tileSize: 256,
|
|
219
221
|
tileOverlap: 0,
|
|
222
|
+
tileContainer: 'fs',
|
|
223
|
+
tileLayout: 'dz',
|
|
224
|
+
tileFormat: 'last',
|
|
225
|
+
tileDepth: 'last',
|
|
226
|
+
tileAngle: 0,
|
|
220
227
|
tileSkipBlanks: -1,
|
|
221
228
|
tileBackground: [255, 255, 255, 255],
|
|
222
229
|
linearA: 1,
|
package/lib/input.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const util = require('util');
|
|
4
3
|
const color = require('color');
|
|
5
4
|
const is = require('./is');
|
|
6
5
|
const sharp = require('../build/Release/sharp.node');
|
|
7
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Extract input options, if any, from an object.
|
|
9
|
+
* @private
|
|
10
|
+
*/
|
|
11
|
+
function _inputOptionsFromObject (obj) {
|
|
12
|
+
const { raw, density, limitInputPixels, sequentialRead, failOnError } = obj;
|
|
13
|
+
return [raw, density, limitInputPixels, sequentialRead, failOnError].some(is.defined)
|
|
14
|
+
? { raw, density, limitInputPixels, sequentialRead, failOnError }
|
|
15
|
+
: undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
8
18
|
/**
|
|
9
19
|
* Create Object containing input and input-related options.
|
|
10
20
|
* @private
|
|
@@ -24,12 +34,12 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
24
34
|
} else if (is.plainObject(input) && !is.defined(inputOptions)) {
|
|
25
35
|
// Plain Object descriptor, e.g. create
|
|
26
36
|
inputOptions = input;
|
|
27
|
-
if (
|
|
28
|
-
//
|
|
37
|
+
if (_inputOptionsFromObject(inputOptions)) {
|
|
38
|
+
// Stream with options
|
|
29
39
|
inputDescriptor.buffer = [];
|
|
30
40
|
}
|
|
31
41
|
} else if (!is.defined(input) && !is.defined(inputOptions) && is.object(containerOptions) && containerOptions.allowStream) {
|
|
32
|
-
// Stream
|
|
42
|
+
// Stream without options
|
|
33
43
|
inputDescriptor.buffer = [];
|
|
34
44
|
} else {
|
|
35
45
|
throw new Error(`Unsupported input '${input}' of type ${typeof input}${
|
|
@@ -187,9 +197,9 @@ function _isStreamInput () {
|
|
|
187
197
|
* - `size`: Total size of image in bytes, for Stream and Buffer input only
|
|
188
198
|
* - `width`: Number of pixels wide (EXIF orientation is not taken into consideration)
|
|
189
199
|
* - `height`: Number of pixels high (EXIF orientation is not taken into consideration)
|
|
190
|
-
* - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.
|
|
200
|
+
* - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsInterpretation)
|
|
191
201
|
* - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
|
|
192
|
-
* - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://github.
|
|
202
|
+
* - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsBandFormat)
|
|
193
203
|
* - `density`: Number of pixels per inch (DPI), if present
|
|
194
204
|
* - `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK
|
|
195
205
|
* - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
|
|
@@ -278,7 +288,7 @@ function metadata (callback) {
|
|
|
278
288
|
* - `minY` (y-coordinate of one of the pixel where the minimum lies)
|
|
279
289
|
* - `maxX` (x-coordinate of one of the pixel where the maximum lies)
|
|
280
290
|
* - `maxY` (y-coordinate of one of the pixel where the maximum lies)
|
|
281
|
-
* - `isOpaque`:
|
|
291
|
+
* - `isOpaque`: Is the image fully opaque? Will be `true` if the image has no alpha channel or if every pixel is fully opaque.
|
|
282
292
|
* - `entropy`: Histogram-based estimation of greyscale entropy, discarding alpha channel if any (experimental)
|
|
283
293
|
*
|
|
284
294
|
* @example
|
|
@@ -331,32 +341,6 @@ function stats (callback) {
|
|
|
331
341
|
}
|
|
332
342
|
}
|
|
333
343
|
|
|
334
|
-
/**
|
|
335
|
-
* @private
|
|
336
|
-
*/
|
|
337
|
-
const limitInputPixels = util.deprecate(function limitInputPixels (limit) {
|
|
338
|
-
// if we pass in false we represent the integer as 0 to disable
|
|
339
|
-
if (limit === false) {
|
|
340
|
-
limit = 0;
|
|
341
|
-
} else if (limit === true) {
|
|
342
|
-
limit = Math.pow(0x3FFF, 2);
|
|
343
|
-
}
|
|
344
|
-
if (is.integer(limit) && limit >= 0) {
|
|
345
|
-
this.options.input.limitInputPixels = limit;
|
|
346
|
-
} else {
|
|
347
|
-
throw is.invalidParameterError('limitInputPixels', 'integer', limit);
|
|
348
|
-
}
|
|
349
|
-
return this;
|
|
350
|
-
}, 'limitInputPixels is deprecated, use sharp(input, { limitInputPixels: false }) instead');
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* @private
|
|
354
|
-
*/
|
|
355
|
-
const sequentialRead = util.deprecate(function sequentialRead (sequentialRead) {
|
|
356
|
-
this.options.input.sequentialRead = is.bool(sequentialRead) ? sequentialRead : true;
|
|
357
|
-
return this;
|
|
358
|
-
}, 'sequentialRead is deprecated, use sharp(input, { sequentialRead: true }) instead');
|
|
359
|
-
|
|
360
344
|
/**
|
|
361
345
|
* Decorate the Sharp prototype with input-related functions.
|
|
362
346
|
* @private
|
|
@@ -364,15 +348,13 @@ const sequentialRead = util.deprecate(function sequentialRead (sequentialRead) {
|
|
|
364
348
|
module.exports = function (Sharp) {
|
|
365
349
|
Object.assign(Sharp.prototype, {
|
|
366
350
|
// Private
|
|
351
|
+
_inputOptionsFromObject,
|
|
367
352
|
_createInputDescriptor,
|
|
368
353
|
_write,
|
|
369
354
|
_flattenBufferIn,
|
|
370
355
|
_isStreamInput,
|
|
371
356
|
// Public
|
|
372
357
|
metadata,
|
|
373
|
-
stats
|
|
374
|
-
// Deprecated
|
|
375
|
-
limitInputPixels,
|
|
376
|
-
sequentialRead
|
|
358
|
+
stats
|
|
377
359
|
});
|
|
378
360
|
};
|
package/lib/libvips.js
CHANGED
|
@@ -8,8 +8,9 @@ const semver = require('semver');
|
|
|
8
8
|
const platform = require('./platform');
|
|
9
9
|
|
|
10
10
|
const env = process.env;
|
|
11
|
-
const
|
|
11
|
+
const minimumLibvipsVersionLabelled = env.npm_package_config_libvips || /* istanbul ignore next */
|
|
12
12
|
require('../package.json').config.libvips;
|
|
13
|
+
const minimumLibvipsVersion = semver.coerce(minimumLibvipsVersionLabelled).version;
|
|
13
14
|
|
|
14
15
|
const spawnSyncOptions = {
|
|
15
16
|
encoding: 'utf8',
|
|
@@ -93,11 +94,12 @@ const useGlobalLibvips = function () {
|
|
|
93
94
|
};
|
|
94
95
|
|
|
95
96
|
module.exports = {
|
|
96
|
-
minimumLibvipsVersion
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
minimumLibvipsVersion,
|
|
98
|
+
minimumLibvipsVersionLabelled,
|
|
99
|
+
cachePath,
|
|
100
|
+
globalLibvipsVersion,
|
|
101
|
+
hasVendoredLibvips,
|
|
102
|
+
pkgConfigPath,
|
|
103
|
+
useGlobalLibvips,
|
|
104
|
+
mkdirSync
|
|
103
105
|
};
|
package/lib/output.js
CHANGED
|
@@ -517,7 +517,9 @@ function heif (options) {
|
|
|
517
517
|
}
|
|
518
518
|
|
|
519
519
|
/**
|
|
520
|
-
* Force output to be raw, uncompressed
|
|
520
|
+
* Force output to be raw, uncompressed, 8-bit unsigned integer (unit8) pixel data.
|
|
521
|
+
* Pixel ordering is left-to-right, top-to-bottom, without padding.
|
|
522
|
+
* Channel ordering will be RGB or RGBA for non-greyscale colourspaces.
|
|
521
523
|
*
|
|
522
524
|
* @example
|
|
523
525
|
* // Extract raw RGB pixel data from JPEG input
|
|
@@ -525,6 +527,15 @@ function heif (options) {
|
|
|
525
527
|
* .raw()
|
|
526
528
|
* .toBuffer({ resolveWithObject: true });
|
|
527
529
|
*
|
|
530
|
+
* @example
|
|
531
|
+
* // Extract alpha channel as raw pixel data from PNG input
|
|
532
|
+
* const data = await sharp('input.png')
|
|
533
|
+
* .ensureAlpha()
|
|
534
|
+
* .extractChannel(3)
|
|
535
|
+
* .colourspace('b-w')
|
|
536
|
+
* .raw()
|
|
537
|
+
* .toBuffer();
|
|
538
|
+
*
|
|
528
539
|
* @returns {Sharp}
|
|
529
540
|
*/
|
|
530
541
|
function raw () {
|
|
@@ -557,7 +568,7 @@ function raw () {
|
|
|
557
568
|
* @param {String} [options.depth] how deep to make the pyramid, possible values are `onepixel`, `onetile` or `one`, default based on layout.
|
|
558
569
|
* @param {Number} [options.skipBlanks=-1] threshold to skip tile generation, a value 0 - 255 for 8-bit images or 0 - 65535 for 16-bit images
|
|
559
570
|
* @param {String} [options.container='fs'] tile container, with value `fs` (filesystem) or `zip` (compressed file).
|
|
560
|
-
* @param {String} [options.layout='dz'] filesystem layout, possible values are `dz`, `zoomify` or `google`.
|
|
571
|
+
* @param {String} [options.layout='dz'] filesystem layout, possible values are `dz`, `iiif`, `zoomify` or `google`.
|
|
561
572
|
* @returns {Sharp}
|
|
562
573
|
* @throws {Error} Invalid parameters
|
|
563
574
|
*/
|
|
@@ -592,10 +603,10 @@ function tile (options) {
|
|
|
592
603
|
}
|
|
593
604
|
// Layout
|
|
594
605
|
if (is.defined(options.layout)) {
|
|
595
|
-
if (is.string(options.layout) && is.inArray(options.layout, ['dz', 'google', 'zoomify'])) {
|
|
606
|
+
if (is.string(options.layout) && is.inArray(options.layout, ['dz', 'google', 'iiif', 'zoomify'])) {
|
|
596
607
|
this.options.tileLayout = options.layout;
|
|
597
608
|
} else {
|
|
598
|
-
throw is.invalidParameterError('layout', 'one of: dz, google, zoomify', options.layout);
|
|
609
|
+
throw is.invalidParameterError('layout', 'one of: dz, google, iiif, zoomify', options.layout);
|
|
599
610
|
}
|
|
600
611
|
}
|
|
601
612
|
// Angle of rotation,
|
package/lib/resize.js
CHANGED
|
@@ -85,21 +85,30 @@ const mapFitToCanvas = {
|
|
|
85
85
|
outside: 'min'
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
function isRotationExpected (options) {
|
|
92
|
+
return (options.angle % 360) !== 0 || options.useExifOrientation === true || options.rotationAngle !== 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
88
95
|
/**
|
|
89
96
|
* Resize image to `width`, `height` or `width x height`.
|
|
90
97
|
*
|
|
91
98
|
* When both a `width` and `height` are provided, the possible methods by which the image should **fit** these are:
|
|
92
|
-
* - `cover`:
|
|
93
|
-
* - `contain`:
|
|
99
|
+
* - `cover`: (default) Preserving aspect ratio, ensure the image covers both provided dimensions by cropping/clipping to fit.
|
|
100
|
+
* - `contain`: Preserving aspect ratio, contain within both provided dimensions using "letterboxing" where necessary.
|
|
94
101
|
* - `fill`: Ignore the aspect ratio of the input and stretch to both provided dimensions.
|
|
95
102
|
* - `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
103
|
* - `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.
|
|
104
|
+
*
|
|
97
105
|
* Some of these values are based on the [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) CSS property.
|
|
98
106
|
*
|
|
99
107
|
* When using a `fit` of `cover` or `contain`, the default **position** is `centre`. Other options are:
|
|
100
108
|
* - `sharp.position`: `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`.
|
|
101
109
|
* - `sharp.gravity`: `north`, `northeast`, `east`, `southeast`, `south`, `southwest`, `west`, `northwest`, `center` or `centre`.
|
|
102
110
|
* - `sharp.strategy`: `cover` only, dynamically crop using either the `entropy` or `attention` strategy.
|
|
111
|
+
*
|
|
103
112
|
* Some of these values are based on the [object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) CSS property.
|
|
104
113
|
*
|
|
105
114
|
* The experimental strategy-based approach resizes so one dimension is at its target length
|
|
@@ -367,7 +376,7 @@ function extract (options) {
|
|
|
367
376
|
}
|
|
368
377
|
}, this);
|
|
369
378
|
// Ensure existing rotation occurs before pre-resize extraction
|
|
370
|
-
if (suffix === 'Pre' && (
|
|
379
|
+
if (suffix === 'Pre' && isRotationExpected(this.options)) {
|
|
371
380
|
this.options.rotateBeforePreExtract = true;
|
|
372
381
|
}
|
|
373
382
|
return this;
|
|
@@ -391,6 +400,9 @@ function trim (threshold) {
|
|
|
391
400
|
} else {
|
|
392
401
|
throw is.invalidParameterError('threshold', 'number greater than zero', threshold);
|
|
393
402
|
}
|
|
403
|
+
if (this.options.trimThreshold && isRotationExpected(this.options)) {
|
|
404
|
+
this.options.rotateBeforePreExtract = true;
|
|
405
|
+
}
|
|
394
406
|
return this;
|
|
395
407
|
}
|
|
396
408
|
|
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.25.2",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://github.com/lovell/sharp",
|
|
7
7
|
"contributors": [
|
|
@@ -65,10 +65,11 @@
|
|
|
65
65
|
"Andargor <andargor@yahoo.com>",
|
|
66
66
|
"Paul Neave <paul.neave@gmail.com>",
|
|
67
67
|
"Brendan Kennedy <brenwken@gmail.com>",
|
|
68
|
-
"Brychan Bennett-Odlum <git@brychan.io>"
|
|
68
|
+
"Brychan Bennett-Odlum <git@brychan.io>",
|
|
69
|
+
"Edward Silverton <e.silverton@gmail.com>"
|
|
69
70
|
],
|
|
70
71
|
"scripts": {
|
|
71
|
-
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
|
|
72
|
+
"install": "(node install/libvips && node install/dll-copy && prebuild-install --runtime=napi) || (node-gyp rebuild && node install/dll-copy)",
|
|
72
73
|
"clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
|
|
73
74
|
"test": "semistandard && cpplint && npm run test-unit && npm run test-licensing && prebuild-ci",
|
|
74
75
|
"test-unit": "nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js",
|
|
@@ -109,40 +110,45 @@
|
|
|
109
110
|
"dependencies": {
|
|
110
111
|
"color": "^3.1.2",
|
|
111
112
|
"detect-libc": "^1.0.3",
|
|
112
|
-
"
|
|
113
|
+
"node-addon-api": "^2.0.0",
|
|
113
114
|
"npmlog": "^4.1.2",
|
|
114
115
|
"prebuild-install": "^5.3.3",
|
|
115
|
-
"semver": "^7.1.
|
|
116
|
+
"semver": "^7.1.3",
|
|
116
117
|
"simple-get": "^3.1.0",
|
|
117
|
-
"tar": "^
|
|
118
|
+
"tar": "^6.0.1",
|
|
118
119
|
"tunnel-agent": "^0.6.0"
|
|
119
120
|
},
|
|
120
121
|
"devDependencies": {
|
|
121
|
-
"async": "^3.
|
|
122
|
+
"async": "^3.2.0",
|
|
122
123
|
"cc": "^2.0.1",
|
|
123
124
|
"decompress-zip": "^0.3.2",
|
|
124
125
|
"documentation": "^12.1.4",
|
|
125
126
|
"exif-reader": "^1.0.3",
|
|
126
127
|
"icc": "^1.0.0",
|
|
127
128
|
"license-checker": "^25.0.1",
|
|
128
|
-
"mocha": "^7.
|
|
129
|
-
"mock-fs": "^4.
|
|
129
|
+
"mocha": "^7.1.1",
|
|
130
|
+
"mock-fs": "^4.11.0",
|
|
130
131
|
"nyc": "^15.0.0",
|
|
131
132
|
"prebuild": "^10.0.0",
|
|
132
133
|
"prebuild-ci": "^3.1.0",
|
|
133
|
-
"rimraf": "^3.0.
|
|
134
|
+
"rimraf": "^3.0.2",
|
|
134
135
|
"semistandard": "^14.2.0"
|
|
135
136
|
},
|
|
136
137
|
"license": "Apache-2.0",
|
|
137
138
|
"config": {
|
|
138
|
-
"libvips": "8.9.
|
|
139
|
+
"libvips": "8.9.1"
|
|
139
140
|
},
|
|
140
141
|
"engines": {
|
|
141
|
-
"node": ">=10
|
|
142
|
+
"node": ">=10"
|
|
142
143
|
},
|
|
143
144
|
"funding": {
|
|
144
145
|
"url": "https://opencollective.com/libvips"
|
|
145
146
|
},
|
|
147
|
+
"binary": {
|
|
148
|
+
"napi_versions": [
|
|
149
|
+
3
|
|
150
|
+
]
|
|
151
|
+
},
|
|
146
152
|
"semistandard": {
|
|
147
153
|
"env": [
|
|
148
154
|
"mocha"
|
package/src/common.cc
CHANGED
|
@@ -19,9 +19,7 @@
|
|
|
19
19
|
#include <queue>
|
|
20
20
|
#include <mutex> // NOLINT(build/c++11)
|
|
21
21
|
|
|
22
|
-
#include <
|
|
23
|
-
#include <node_buffer.h>
|
|
24
|
-
#include <nan.h>
|
|
22
|
+
#include <napi.h>
|
|
25
23
|
#include <vips/vips8>
|
|
26
24
|
|
|
27
25
|
#include "common.h"
|
|
@@ -30,66 +28,77 @@ using vips::VImage;
|
|
|
30
28
|
|
|
31
29
|
namespace sharp {
|
|
32
30
|
|
|
33
|
-
// Convenience methods to access the attributes of a
|
|
34
|
-
bool HasAttr(
|
|
35
|
-
return
|
|
31
|
+
// Convenience methods to access the attributes of a Napi::Object
|
|
32
|
+
bool HasAttr(Napi::Object obj, std::string attr) {
|
|
33
|
+
return obj.Has(attr);
|
|
36
34
|
}
|
|
37
|
-
std::string AttrAsStr(
|
|
38
|
-
return
|
|
35
|
+
std::string AttrAsStr(Napi::Object obj, std::string attr) {
|
|
36
|
+
return obj.Get(attr).As<Napi::String>();
|
|
39
37
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
uint32_t AttrAsUint32(Napi::Object obj, std::string attr) {
|
|
39
|
+
return obj.Get(attr).As<Napi::Number>().Uint32Value();
|
|
40
|
+
}
|
|
41
|
+
int32_t AttrAsInt32(Napi::Object obj, std::string attr) {
|
|
42
|
+
return obj.Get(attr).As<Napi::Number>().Int32Value();
|
|
43
|
+
}
|
|
44
|
+
double AttrAsDouble(Napi::Object obj, std::string attr) {
|
|
45
|
+
return obj.Get(attr).As<Napi::Number>().DoubleValue();
|
|
46
|
+
}
|
|
47
|
+
double AttrAsDouble(Napi::Object obj, unsigned int const attr) {
|
|
48
|
+
return obj.Get(attr).As<Napi::Number>().DoubleValue();
|
|
49
|
+
}
|
|
50
|
+
bool AttrAsBool(Napi::Object obj, std::string attr) {
|
|
51
|
+
return obj.Get(attr).As<Napi::Boolean>().Value();
|
|
52
|
+
}
|
|
53
|
+
std::vector<double> AttrAsRgba(Napi::Object obj, std::string attr) {
|
|
54
|
+
Napi::Array background = obj.Get(attr).As<Napi::Array>();
|
|
55
|
+
std::vector<double> rgba(background.Length());
|
|
56
|
+
for (unsigned int i = 0; i < background.Length(); i++) {
|
|
57
|
+
rgba[i] = AttrAsDouble(background, i);
|
|
45
58
|
}
|
|
46
59
|
return rgba;
|
|
47
60
|
}
|
|
48
61
|
|
|
49
|
-
// Create an InputDescriptor instance from a
|
|
50
|
-
InputDescriptor* CreateInputDescriptor(
|
|
51
|
-
v8::Local<v8::Object> input, std::vector<v8::Local<v8::Object>> &buffersToPersist
|
|
52
|
-
) {
|
|
53
|
-
Nan::HandleScope();
|
|
62
|
+
// Create an InputDescriptor instance from a Napi::Object describing an input image
|
|
63
|
+
InputDescriptor* CreateInputDescriptor(Napi::Object input) {
|
|
54
64
|
InputDescriptor *descriptor = new InputDescriptor;
|
|
55
65
|
if (HasAttr(input, "file")) {
|
|
56
66
|
descriptor->file = AttrAsStr(input, "file");
|
|
57
67
|
} else if (HasAttr(input, "buffer")) {
|
|
58
|
-
|
|
59
|
-
descriptor->bufferLength =
|
|
60
|
-
descriptor->buffer =
|
|
68
|
+
Napi::Buffer<char> buffer = input.Get("buffer").As<Napi::Buffer<char>>();
|
|
69
|
+
descriptor->bufferLength = buffer.Length();
|
|
70
|
+
descriptor->buffer = buffer.Data();
|
|
61
71
|
descriptor->isBuffer = TRUE;
|
|
62
|
-
buffersToPersist.push_back(buffer);
|
|
63
72
|
}
|
|
64
|
-
descriptor->failOnError =
|
|
73
|
+
descriptor->failOnError = AttrAsBool(input, "failOnError");
|
|
65
74
|
// Density for vector-based input
|
|
66
75
|
if (HasAttr(input, "density")) {
|
|
67
|
-
descriptor->density =
|
|
76
|
+
descriptor->density = AttrAsDouble(input, "density");
|
|
68
77
|
}
|
|
69
78
|
// Raw pixel input
|
|
70
79
|
if (HasAttr(input, "rawChannels")) {
|
|
71
|
-
descriptor->rawChannels =
|
|
72
|
-
descriptor->rawWidth =
|
|
73
|
-
descriptor->rawHeight =
|
|
80
|
+
descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
|
|
81
|
+
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
|
82
|
+
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
|
74
83
|
}
|
|
75
84
|
// Multi-page input (GIF, TIFF, PDF)
|
|
76
85
|
if (HasAttr(input, "pages")) {
|
|
77
|
-
descriptor->pages =
|
|
86
|
+
descriptor->pages = AttrAsInt32(input, "pages");
|
|
78
87
|
}
|
|
79
88
|
if (HasAttr(input, "page")) {
|
|
80
|
-
descriptor->page =
|
|
89
|
+
descriptor->page = AttrAsUint32(input, "page");
|
|
81
90
|
}
|
|
82
91
|
// Create new image
|
|
83
92
|
if (HasAttr(input, "createChannels")) {
|
|
84
|
-
descriptor->createChannels =
|
|
85
|
-
descriptor->createWidth =
|
|
86
|
-
descriptor->createHeight =
|
|
93
|
+
descriptor->createChannels = AttrAsUint32(input, "createChannels");
|
|
94
|
+
descriptor->createWidth = AttrAsUint32(input, "createWidth");
|
|
95
|
+
descriptor->createHeight = AttrAsUint32(input, "createHeight");
|
|
87
96
|
descriptor->createBackground = AttrAsRgba(input, "createBackground");
|
|
88
97
|
}
|
|
89
98
|
// Limit input images to a given number of pixels, where pixels = width * height
|
|
90
|
-
descriptor->limitInputPixels =
|
|
99
|
+
descriptor->limitInputPixels = AttrAsUint32(input, "limitInputPixels");
|
|
91
100
|
// Allow switch from random to sequential access
|
|
92
|
-
descriptor->access =
|
|
101
|
+
descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
|
93
102
|
return descriptor;
|
|
94
103
|
}
|
|
95
104
|
|
|
@@ -439,11 +448,9 @@ namespace sharp {
|
|
|
439
448
|
/*
|
|
440
449
|
Called when a Buffer undergoes GC, required to support mixed runtime libraries in Windows
|
|
441
450
|
*/
|
|
442
|
-
void
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
}
|
|
451
|
+
std::function<void(void*, char*)> FreeCallback = [](void*, char* data) {
|
|
452
|
+
g_free(data);
|
|
453
|
+
};
|
|
447
454
|
|
|
448
455
|
/*
|
|
449
456
|
Temporary buffer of warnings
|