sharp 0.29.3 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/binding.gyp +2 -0
- package/install/libvips.js +39 -8
- package/lib/constructor.js +10 -3
- package/lib/input.js +21 -4
- package/lib/libvips.js +16 -2
- package/lib/operation.js +14 -1
- package/lib/output.js +128 -69
- package/lib/platform.js +1 -1
- package/lib/resize.js +19 -0
- package/lib/sharp.js +2 -1
- package/lib/utility.js +20 -2
- package/package.json +27 -12
- package/src/common.cc +93 -19
- package/src/common.h +29 -5
- package/src/libvips/cplusplus/VImage.cpp +34 -16
- package/src/libvips/cplusplus/vips-operators.cpp +29 -1
- package/src/metadata.cc +6 -0
- package/src/metadata.h +1 -0
- package/src/operations.cc +94 -0
- package/src/operations.h +12 -0
- package/src/pipeline.cc +294 -259
- package/src/pipeline.h +15 -17
- package/src/sharp.cc +16 -0
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
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
|
|
7
|
-
smaller, web-friendly JPEG, PNG, WebP and AVIF images of varying dimensions.
|
|
7
|
+
smaller, web-friendly JPEG, PNG, WebP, GIF and AVIF images of varying dimensions.
|
|
8
8
|
|
|
9
9
|
Resizing an image is typically 4x-5x faster than using the
|
|
10
10
|
quickest ImageMagick and GraphicsMagick settings
|
|
@@ -103,7 +103,7 @@ covers reporting bugs, requesting features and submitting code changes.
|
|
|
103
103
|
|
|
104
104
|
## Licensing
|
|
105
105
|
|
|
106
|
-
Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Lovell Fuller and contributors.
|
|
106
|
+
Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Lovell Fuller and contributors.
|
|
107
107
|
|
|
108
108
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
109
109
|
you may not use this file except in compliance with the License.
|
package/binding.gyp
CHANGED
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
'VCCLCompilerTool': {
|
|
40
40
|
'ExceptionHandling': 1,
|
|
41
41
|
'Optimization': 1,
|
|
42
|
+
'RuntimeLibrary': '2', # /MD
|
|
42
43
|
'WholeProgramOptimization': 'true'
|
|
43
44
|
},
|
|
44
45
|
'VCLibrarianTool': {
|
|
@@ -205,6 +206,7 @@
|
|
|
205
206
|
'VCCLCompilerTool': {
|
|
206
207
|
'ExceptionHandling': 1,
|
|
207
208
|
'Optimization': 1,
|
|
209
|
+
'RuntimeLibrary': '2', # /MD
|
|
208
210
|
'WholeProgramOptimization': 'true'
|
|
209
211
|
},
|
|
210
212
|
'VCLibrarianTool': {
|
package/install/libvips.js
CHANGED
|
@@ -5,6 +5,7 @@ const os = require('os');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const stream = require('stream');
|
|
7
7
|
const zlib = require('zlib');
|
|
8
|
+
const { createHash } = require('crypto');
|
|
8
9
|
|
|
9
10
|
const detectLibc = require('detect-libc');
|
|
10
11
|
const semverLessThan = require('semver/functions/lt');
|
|
@@ -18,7 +19,7 @@ const platform = require('../lib/platform');
|
|
|
18
19
|
|
|
19
20
|
const minimumGlibcVersionByArch = {
|
|
20
21
|
arm: '2.28',
|
|
21
|
-
arm64: '2.
|
|
22
|
+
arm64: '2.17',
|
|
22
23
|
x64: '2.17'
|
|
23
24
|
};
|
|
24
25
|
|
|
@@ -55,6 +56,33 @@ const handleError = function (err) {
|
|
|
55
56
|
}
|
|
56
57
|
};
|
|
57
58
|
|
|
59
|
+
const verifyIntegrity = function (platformAndArch) {
|
|
60
|
+
const expected = libvips.integrity(platformAndArch);
|
|
61
|
+
if (installationForced || !expected) {
|
|
62
|
+
libvips.log(`Integrity check skipped for ${platformAndArch}`);
|
|
63
|
+
return new stream.PassThrough();
|
|
64
|
+
}
|
|
65
|
+
const hash = createHash('sha512');
|
|
66
|
+
return new stream.Transform({
|
|
67
|
+
transform: function (chunk, _encoding, done) {
|
|
68
|
+
hash.update(chunk);
|
|
69
|
+
done(null, chunk);
|
|
70
|
+
},
|
|
71
|
+
flush: function (done) {
|
|
72
|
+
const digest = `sha512-${hash.digest('base64')}`;
|
|
73
|
+
if (expected !== digest) {
|
|
74
|
+
libvips.removeVendoredLibvips();
|
|
75
|
+
libvips.log(`Integrity expected: ${expected}`);
|
|
76
|
+
libvips.log(`Integrity received: ${digest}`);
|
|
77
|
+
done(new Error(`Integrity check failed for ${platformAndArch}`));
|
|
78
|
+
} else {
|
|
79
|
+
libvips.log(`Integrity check passed for ${platformAndArch}`);
|
|
80
|
+
done();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
|
|
58
86
|
const extractTarball = function (tarPath, platformAndArch) {
|
|
59
87
|
const versionedVendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platformAndArch);
|
|
60
88
|
libvips.mkdirSync(versionedVendorPath);
|
|
@@ -66,6 +94,7 @@ const extractTarball = function (tarPath, platformAndArch) {
|
|
|
66
94
|
|
|
67
95
|
stream.pipeline(
|
|
68
96
|
fs.createReadStream(tarPath),
|
|
97
|
+
verifyIntegrity(platformAndArch),
|
|
69
98
|
new zlib.BrotliDecompress(),
|
|
70
99
|
tarFs.extract(versionedVendorPath, { ignore }),
|
|
71
100
|
function (err) {
|
|
@@ -103,14 +132,16 @@ try {
|
|
|
103
132
|
throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
104
133
|
}
|
|
105
134
|
// Linux libc version check
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
135
|
+
const libcFamily = detectLibc.familySync();
|
|
136
|
+
const libcVersion = detectLibc.versionSync();
|
|
137
|
+
if (libcFamily === detectLibc.GLIBC && libcVersion && minimumGlibcVersionByArch[arch]) {
|
|
138
|
+
if (semverLessThan(`${libcVersion}.0`, `${minimumGlibcVersionByArch[arch]}.0`)) {
|
|
139
|
+
handleError(new Error(`Use with glibc ${libcVersion} requires manual installation of libvips >= ${minimumLibvipsVersion}`));
|
|
109
140
|
}
|
|
110
141
|
}
|
|
111
|
-
if (
|
|
112
|
-
if (semverLessThan(
|
|
113
|
-
handleError(new Error(`Use with musl ${
|
|
142
|
+
if (libcFamily === detectLibc.MUSL && libcVersion) {
|
|
143
|
+
if (semverLessThan(libcVersion, '1.1.24')) {
|
|
144
|
+
handleError(new Error(`Use with musl ${libcVersion} requires manual installation of libvips >= ${minimumLibvipsVersion}`));
|
|
114
145
|
}
|
|
115
146
|
}
|
|
116
147
|
// Node.js minimum version check
|
|
@@ -120,7 +151,7 @@ try {
|
|
|
120
151
|
}
|
|
121
152
|
|
|
122
153
|
// Download to per-process temporary file
|
|
123
|
-
const tarFilename = ['libvips',
|
|
154
|
+
const tarFilename = ['libvips', minimumLibvipsVersionLabelled, platformAndArch].join('-') + '.tar.br';
|
|
124
155
|
const tarPathCache = path.join(libvips.cachePath(), tarFilename);
|
|
125
156
|
if (fs.existsSync(tarPathCache)) {
|
|
126
157
|
libvips.log(`Using cached ${tarPathCache}`);
|
package/lib/constructor.js
CHANGED
|
@@ -13,7 +13,7 @@ const debuglog = util.debuglog('sharp');
|
|
|
13
13
|
/**
|
|
14
14
|
* Constructor factory to create an instance of `sharp`, to which further methods are chained.
|
|
15
15
|
*
|
|
16
|
-
* JPEG, PNG, WebP, AVIF or TIFF format image data can be streamed out from this object.
|
|
16
|
+
* JPEG, PNG, WebP, GIF, AVIF or TIFF format image data can be streamed out from this object.
|
|
17
17
|
* When using Stream based output, derived attributes are available from the `info` event.
|
|
18
18
|
*
|
|
19
19
|
* Non-critical problems encountered during processing are emitted as `warning` events.
|
|
@@ -103,6 +103,7 @@ const debuglog = util.debuglog('sharp');
|
|
|
103
103
|
* @param {number|boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
|
|
104
104
|
* (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
|
|
105
105
|
* An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
|
|
106
|
+
* @param {boolean} [options.unlimited=false] - Set this to `true` to remove safety features that help prevent memory exhaustion (SVG, PNG).
|
|
106
107
|
* @param {boolean} [options.sequentialRead=false] - Set this to `true` to use sequential rather than random access where possible.
|
|
107
108
|
* This can reduce memory usage and might improve performance on some systems.
|
|
108
109
|
* @param {number} [options.density=72] - number representing the DPI for vector images in the range 1 to 100000.
|
|
@@ -165,6 +166,7 @@ const Sharp = function (input, options) {
|
|
|
165
166
|
extendRight: 0,
|
|
166
167
|
extendBackground: [0, 0, 0, 255],
|
|
167
168
|
withoutEnlargement: false,
|
|
169
|
+
withoutReduction: false,
|
|
168
170
|
affineMatrix: [],
|
|
169
171
|
affineBackground: [0, 0, 0, 255],
|
|
170
172
|
affineIdx: 0,
|
|
@@ -233,6 +235,7 @@ const Sharp = function (input, options) {
|
|
|
233
235
|
pngAdaptiveFiltering: false,
|
|
234
236
|
pngPalette: false,
|
|
235
237
|
pngQuality: 100,
|
|
238
|
+
pngEffort: 7,
|
|
236
239
|
pngBitdepth: 8,
|
|
237
240
|
pngDither: 1,
|
|
238
241
|
jp2Quality: 80,
|
|
@@ -245,7 +248,10 @@ const Sharp = function (input, options) {
|
|
|
245
248
|
webpLossless: false,
|
|
246
249
|
webpNearLossless: false,
|
|
247
250
|
webpSmartSubsample: false,
|
|
248
|
-
|
|
251
|
+
webpEffort: 4,
|
|
252
|
+
gifBitdepth: 8,
|
|
253
|
+
gifEffort: 7,
|
|
254
|
+
gifDither: 1,
|
|
249
255
|
tiffQuality: 80,
|
|
250
256
|
tiffCompression: 'jpeg',
|
|
251
257
|
tiffPredictor: 'horizontal',
|
|
@@ -256,10 +262,11 @@ const Sharp = function (input, options) {
|
|
|
256
262
|
tiffTileWidth: 256,
|
|
257
263
|
tiffXres: 1.0,
|
|
258
264
|
tiffYres: 1.0,
|
|
265
|
+
tiffResolutionUnit: 'inch',
|
|
259
266
|
heifQuality: 50,
|
|
260
267
|
heifLossless: false,
|
|
261
268
|
heifCompression: 'av1',
|
|
262
|
-
|
|
269
|
+
heifEffort: 4,
|
|
263
270
|
heifChromaSubsampling: '4:4:4',
|
|
264
271
|
rawDepth: 'uchar',
|
|
265
272
|
tileSize: 256,
|
package/lib/input.js
CHANGED
|
@@ -9,9 +9,9 @@ const sharp = require('./sharp');
|
|
|
9
9
|
* @private
|
|
10
10
|
*/
|
|
11
11
|
function _inputOptionsFromObject (obj) {
|
|
12
|
-
const { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages, subifd } = obj;
|
|
13
|
-
return [raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages, subifd].some(is.defined)
|
|
14
|
-
? { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages, subifd }
|
|
12
|
+
const { raw, density, limitInputPixels, unlimited, sequentialRead, failOnError, animated, page, pages, subifd } = obj;
|
|
13
|
+
return [raw, density, limitInputPixels, unlimited, sequentialRead, failOnError, animated, page, pages, subifd].some(is.defined)
|
|
14
|
+
? { raw, density, limitInputPixels, unlimited, sequentialRead, failOnError, animated, page, pages, subifd }
|
|
15
15
|
: undefined;
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -23,6 +23,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
23
23
|
const inputDescriptor = {
|
|
24
24
|
failOnError: true,
|
|
25
25
|
limitInputPixels: Math.pow(0x3FFF, 2),
|
|
26
|
+
unlimited: false,
|
|
26
27
|
sequentialRead: false
|
|
27
28
|
};
|
|
28
29
|
if (is.string(input)) {
|
|
@@ -83,6 +84,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
83
84
|
throw is.invalidParameterError('limitInputPixels', 'integer >= 0', inputOptions.limitInputPixels);
|
|
84
85
|
}
|
|
85
86
|
}
|
|
87
|
+
// unlimited
|
|
88
|
+
if (is.defined(inputOptions.unlimited)) {
|
|
89
|
+
if (is.bool(inputOptions.unlimited)) {
|
|
90
|
+
inputDescriptor.unlimited = inputOptions.unlimited;
|
|
91
|
+
} else {
|
|
92
|
+
throw is.invalidParameterError('unlimited', 'boolean', inputOptions.unlimited);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
86
95
|
// sequentialRead
|
|
87
96
|
if (is.defined(inputOptions.sequentialRead)) {
|
|
88
97
|
if (is.bool(inputOptions.sequentialRead)) {
|
|
@@ -281,7 +290,11 @@ function _isStreamInput () {
|
|
|
281
290
|
}
|
|
282
291
|
|
|
283
292
|
/**
|
|
284
|
-
* Fast access to (uncached) image metadata without decoding any compressed
|
|
293
|
+
* Fast access to (uncached) image metadata without decoding any compressed pixel data.
|
|
294
|
+
*
|
|
295
|
+
* This is taken from the header of the input image.
|
|
296
|
+
* It does not include operations, such as resize, to be applied to the output image.
|
|
297
|
+
*
|
|
285
298
|
* A `Promise` is returned when `callback` is not provided.
|
|
286
299
|
*
|
|
287
300
|
* - `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
|
|
@@ -303,6 +316,7 @@ function _isStreamInput () {
|
|
|
303
316
|
* - `subifds`: Number of Sub Image File Directories in an OME-TIFF image
|
|
304
317
|
* - `background`: Default background colour, if present, for PNG (bKGD) and GIF images, either an RGB Object or a single greyscale value
|
|
305
318
|
* - `compression`: The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC)
|
|
319
|
+
* - `resolutionUnit`: The unit of resolution (density), either `inch` or `cm`, if present
|
|
306
320
|
* - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
|
307
321
|
* - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
|
308
322
|
* - `orientation`: Number value of the EXIF Orientation header, if present
|
|
@@ -313,6 +327,9 @@ function _isStreamInput () {
|
|
|
313
327
|
* - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
|
314
328
|
*
|
|
315
329
|
* @example
|
|
330
|
+
* const metadata = await sharp(input).metadata();
|
|
331
|
+
*
|
|
332
|
+
* @example
|
|
316
333
|
* const image = sharp(inputJpg);
|
|
317
334
|
* image
|
|
318
335
|
* .metadata()
|
package/lib/libvips.js
CHANGED
|
@@ -8,10 +8,11 @@ const semverCoerce = require('semver/functions/coerce');
|
|
|
8
8
|
const semverGreaterThanOrEqualTo = require('semver/functions/gte');
|
|
9
9
|
|
|
10
10
|
const platform = require('./platform');
|
|
11
|
+
const { config } = require('../package.json');
|
|
11
12
|
|
|
12
13
|
const env = process.env;
|
|
13
14
|
const minimumLibvipsVersionLabelled = env.npm_package_config_libvips || /* istanbul ignore next */
|
|
14
|
-
|
|
15
|
+
config.libvips;
|
|
15
16
|
const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
|
|
16
17
|
|
|
17
18
|
const spawnSyncOptions = {
|
|
@@ -19,6 +20,8 @@ const spawnSyncOptions = {
|
|
|
19
20
|
shell: true
|
|
20
21
|
};
|
|
21
22
|
|
|
23
|
+
const vendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platform());
|
|
24
|
+
|
|
22
25
|
const mkdirSync = function (dirPath) {
|
|
23
26
|
try {
|
|
24
27
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
@@ -39,6 +42,10 @@ const cachePath = function () {
|
|
|
39
42
|
return libvipsCachePath;
|
|
40
43
|
};
|
|
41
44
|
|
|
45
|
+
const integrity = function (platformAndArch) {
|
|
46
|
+
return env[`npm_package_config_integrity_${platformAndArch.replace('-', '_')}`] || config.integrity[platformAndArch];
|
|
47
|
+
};
|
|
48
|
+
|
|
42
49
|
const log = function (item) {
|
|
43
50
|
if (item instanceof Error) {
|
|
44
51
|
console.error(`sharp: Installation error: ${item.message}`);
|
|
@@ -67,10 +74,15 @@ const globalLibvipsVersion = function () {
|
|
|
67
74
|
};
|
|
68
75
|
|
|
69
76
|
const hasVendoredLibvips = function () {
|
|
70
|
-
const vendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platform());
|
|
71
77
|
return fs.existsSync(vendorPath);
|
|
72
78
|
};
|
|
73
79
|
|
|
80
|
+
/* istanbul ignore next */
|
|
81
|
+
const removeVendoredLibvips = function () {
|
|
82
|
+
const rm = fs.rmSync ? fs.rmSync : fs.rmdirSync;
|
|
83
|
+
rm(vendorPath, { recursive: true, maxRetries: 3, force: true });
|
|
84
|
+
};
|
|
85
|
+
|
|
74
86
|
const pkgConfigPath = function () {
|
|
75
87
|
if (process.platform !== 'win32') {
|
|
76
88
|
const brewPkgConfigPath = spawnSync('which brew >/dev/null 2>&1 && eval $(brew --env) && echo $PKG_CONFIG_LIBDIR', spawnSyncOptions).stdout || '';
|
|
@@ -99,9 +111,11 @@ module.exports = {
|
|
|
99
111
|
minimumLibvipsVersion,
|
|
100
112
|
minimumLibvipsVersionLabelled,
|
|
101
113
|
cachePath,
|
|
114
|
+
integrity,
|
|
102
115
|
log,
|
|
103
116
|
globalLibvipsVersion,
|
|
104
117
|
hasVendoredLibvips,
|
|
118
|
+
removeVendoredLibvips,
|
|
105
119
|
pkgConfigPath,
|
|
106
120
|
useGlobalLibvips,
|
|
107
121
|
mkdirSync
|
package/lib/operation.js
CHANGED
|
@@ -245,8 +245,21 @@ function median (size) {
|
|
|
245
245
|
|
|
246
246
|
/**
|
|
247
247
|
* Blur the image.
|
|
248
|
-
*
|
|
248
|
+
*
|
|
249
|
+
* When used without parameters, performs a fast 3x3 box blur (equivalent to a box linear filter).
|
|
250
|
+
*
|
|
249
251
|
* When a `sigma` is provided, performs a slower, more accurate Gaussian blur.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* const boxBlurred = await sharp(input)
|
|
255
|
+
* .blur()
|
|
256
|
+
* .toBuffer();
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* const gaussianBlurred = await sharp(input)
|
|
260
|
+
* .blur(5)
|
|
261
|
+
* .toBuffer();
|
|
262
|
+
*
|
|
250
263
|
* @param {number} [sigma] a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
|
|
251
264
|
* @returns {Sharp}
|
|
252
265
|
* @throws {Error} Invalid parameters
|