sharp 0.28.1 → 0.28.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/install/libvips.js +20 -9
- package/lib/agent.js +1 -1
- package/lib/constructor.js +3 -0
- package/lib/input.js +7 -0
- package/lib/libvips.js +5 -3
- package/lib/operation.js +1 -1
- package/lib/output.js +15 -1
- package/package.json +10 -7
- package/src/common.cc +7 -3
- package/src/common.h +2 -0
- package/src/pipeline.cc +7 -1
- package/src/pipeline.h +2 -0
package/install/libvips.js
CHANGED
|
@@ -7,7 +7,8 @@ const stream = require('stream');
|
|
|
7
7
|
const zlib = require('zlib');
|
|
8
8
|
|
|
9
9
|
const detectLibc = require('detect-libc');
|
|
10
|
-
const
|
|
10
|
+
const semverLessThan = require('semver/functions/lt');
|
|
11
|
+
const semverSatisfies = require('semver/functions/satisfies');
|
|
11
12
|
const simpleGet = require('simple-get');
|
|
12
13
|
const tarFs = require('tar-fs');
|
|
13
14
|
|
|
@@ -35,6 +36,7 @@ const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
|
|
|
35
36
|
const distHost = process.env.npm_config_sharp_libvips_binary_host || 'https://github.com/lovell/sharp-libvips/releases/download';
|
|
36
37
|
const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `${distHost}/v${minimumLibvipsVersionLabelled}/`;
|
|
37
38
|
const supportsBrotli = ('BrotliDecompress' in zlib);
|
|
39
|
+
const installationForced = !!(process.env.npm_config_sharp_install_force || process.env.SHARP_INSTALL_FORCE);
|
|
38
40
|
|
|
39
41
|
const fail = function (err) {
|
|
40
42
|
libvips.log(err);
|
|
@@ -46,6 +48,14 @@ const fail = function (err) {
|
|
|
46
48
|
process.exit(1);
|
|
47
49
|
};
|
|
48
50
|
|
|
51
|
+
const handleError = function (err) {
|
|
52
|
+
if (installationForced) {
|
|
53
|
+
libvips.log(`Installation warning: ${err.message}`);
|
|
54
|
+
} else {
|
|
55
|
+
throw err;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
49
59
|
const extractTarball = function (tarPath, platformAndArch) {
|
|
50
60
|
const vendorPath = path.join(__dirname, '..', 'vendor');
|
|
51
61
|
libvips.mkdirSync(vendorPath);
|
|
@@ -95,20 +105,21 @@ try {
|
|
|
95
105
|
if (platformAndArch === 'freebsd-x64' || platformAndArch === 'openbsd-x64' || platformAndArch === 'sunos-x64') {
|
|
96
106
|
throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
97
107
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
108
|
+
// Linux libc version check
|
|
109
|
+
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version && minimumGlibcVersionByArch[arch]) {
|
|
110
|
+
if (semverLessThan(`${detectLibc.version}.0`, `${minimumGlibcVersionByArch[arch]}.0`)) {
|
|
111
|
+
handleError(new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`));
|
|
101
112
|
}
|
|
102
113
|
}
|
|
103
114
|
if (detectLibc.family === detectLibc.MUSL && detectLibc.version) {
|
|
104
|
-
if (
|
|
105
|
-
|
|
115
|
+
if (semverLessThan(detectLibc.version, '1.1.24')) {
|
|
116
|
+
handleError(new Error(`Use with musl ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`));
|
|
106
117
|
}
|
|
107
118
|
}
|
|
108
|
-
|
|
119
|
+
// Node.js minimum version check
|
|
109
120
|
const supportedNodeVersion = process.env.npm_package_engines_node || require('../package.json').engines.node;
|
|
110
|
-
if (!
|
|
111
|
-
|
|
121
|
+
if (!semverSatisfies(process.versions.node, supportedNodeVersion)) {
|
|
122
|
+
handleError(new Error(`Expected Node.js version ${supportedNodeVersion} but found ${process.versions.node}`));
|
|
112
123
|
}
|
|
113
124
|
|
|
114
125
|
const extension = supportsBrotli ? 'br' : 'gz';
|
package/lib/agent.js
CHANGED
|
@@ -25,7 +25,7 @@ module.exports = function () {
|
|
|
25
25
|
? tunnelAgent.httpsOverHttps
|
|
26
26
|
: tunnelAgent.httpsOverHttp;
|
|
27
27
|
const proxyAuth = proxy.username && proxy.password
|
|
28
|
-
? `${proxy.username}:${proxy.password}`
|
|
28
|
+
? `${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password)}`
|
|
29
29
|
: null;
|
|
30
30
|
return tunnel({
|
|
31
31
|
proxy: {
|
package/lib/constructor.js
CHANGED
|
@@ -139,6 +139,8 @@ const debuglog = util.debuglog('sharp');
|
|
|
139
139
|
* @param {number} [options.raw.width] - integral number of pixels wide.
|
|
140
140
|
* @param {number} [options.raw.height] - integral number of pixels high.
|
|
141
141
|
* @param {number} [options.raw.channels] - integral number of channels, between 1 and 4.
|
|
142
|
+
* @param {boolean} [options.raw.premultiplied] - specifies that the raw input has already been premultiplied, set to `true`
|
|
143
|
+
* to avoid sharp premultiplying the image. (optional, default `false`)
|
|
142
144
|
* @param {Object} [options.create] - describes a new image to be created.
|
|
143
145
|
* @param {number} [options.create.width] - integral number of pixels wide.
|
|
144
146
|
* @param {number} [options.create.height] - integral number of pixels high.
|
|
@@ -231,6 +233,7 @@ const Sharp = function (input, options) {
|
|
|
231
233
|
streamOut: false,
|
|
232
234
|
withMetadata: false,
|
|
233
235
|
withMetadataOrientation: -1,
|
|
236
|
+
withMetadataDensity: 0,
|
|
234
237
|
withMetadataIcc: '',
|
|
235
238
|
withMetadataStrs: {},
|
|
236
239
|
resolveWithObject: false,
|
package/lib/input.js
CHANGED
|
@@ -30,9 +30,15 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
30
30
|
inputDescriptor.file = input;
|
|
31
31
|
} else if (is.buffer(input)) {
|
|
32
32
|
// Buffer
|
|
33
|
+
if (input.length === 0) {
|
|
34
|
+
throw Error('Input Buffer is empty');
|
|
35
|
+
}
|
|
33
36
|
inputDescriptor.buffer = input;
|
|
34
37
|
} else if (is.uint8Array(input)) {
|
|
35
38
|
// Uint8Array or Uint8ClampedArray
|
|
39
|
+
if (input.length === 0) {
|
|
40
|
+
throw Error('Input Bit Array is empty');
|
|
41
|
+
}
|
|
36
42
|
inputDescriptor.buffer = Buffer.from(input.buffer);
|
|
37
43
|
} else if (is.plainObject(input) && !is.defined(inputOptions)) {
|
|
38
44
|
// Plain Object descriptor, e.g. create
|
|
@@ -97,6 +103,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
97
103
|
inputDescriptor.rawWidth = inputOptions.raw.width;
|
|
98
104
|
inputDescriptor.rawHeight = inputOptions.raw.height;
|
|
99
105
|
inputDescriptor.rawChannels = inputOptions.raw.channels;
|
|
106
|
+
inputDescriptor.rawPremultiplied = !!inputOptions.raw.premultiplied;
|
|
100
107
|
} else {
|
|
101
108
|
throw new Error('Expected width, height and channels for raw pixel input');
|
|
102
109
|
}
|
package/lib/libvips.js
CHANGED
|
@@ -4,13 +4,15 @@ const fs = require('fs');
|
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const spawnSync = require('child_process').spawnSync;
|
|
7
|
-
const
|
|
7
|
+
const semverCoerce = require('semver/functions/coerce');
|
|
8
|
+
const semverGreaterThanOrEqualTo = require('semver/functions/gte');
|
|
9
|
+
|
|
8
10
|
const platform = require('./platform');
|
|
9
11
|
|
|
10
12
|
const env = process.env;
|
|
11
13
|
const minimumLibvipsVersionLabelled = env.npm_package_config_libvips || /* istanbul ignore next */
|
|
12
14
|
require('../package.json').config.libvips;
|
|
13
|
-
const minimumLibvipsVersion =
|
|
15
|
+
const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
|
|
14
16
|
|
|
15
17
|
const spawnSyncOptions = {
|
|
16
18
|
encoding: 'utf8',
|
|
@@ -105,7 +107,7 @@ const useGlobalLibvips = function () {
|
|
|
105
107
|
}
|
|
106
108
|
const globalVipsVersion = globalLibvipsVersion();
|
|
107
109
|
return !!globalVipsVersion && /* istanbul ignore next */
|
|
108
|
-
|
|
110
|
+
semverGreaterThanOrEqualTo(globalVipsVersion, minimumLibvipsVersion);
|
|
109
111
|
};
|
|
110
112
|
|
|
111
113
|
module.exports = {
|
package/lib/operation.js
CHANGED
package/lib/output.js
CHANGED
|
@@ -150,7 +150,7 @@ function toBuffer (options, callback) {
|
|
|
150
150
|
*
|
|
151
151
|
* @example
|
|
152
152
|
* // Set "IFD0-Copyright" in output EXIF metadata
|
|
153
|
-
* await sharp(input)
|
|
153
|
+
* const data = await sharp(input)
|
|
154
154
|
* .withMetadata({
|
|
155
155
|
* exif: {
|
|
156
156
|
* IFD0: {
|
|
@@ -160,10 +160,17 @@ function toBuffer (options, callback) {
|
|
|
160
160
|
* })
|
|
161
161
|
* .toBuffer();
|
|
162
162
|
*
|
|
163
|
+
* * @example
|
|
164
|
+
* // Set output metadata to 96 DPI
|
|
165
|
+
* const data = await sharp(input)
|
|
166
|
+
* .withMetadata({ density: 96 })
|
|
167
|
+
* .toBuffer();
|
|
168
|
+
*
|
|
163
169
|
* @param {Object} [options]
|
|
164
170
|
* @param {number} [options.orientation] value between 1 and 8, used to update the EXIF `Orientation` tag.
|
|
165
171
|
* @param {string} [options.icc] filesystem path to output ICC profile, defaults to sRGB.
|
|
166
172
|
* @param {Object<Object>} [options.exif={}] Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
|
|
173
|
+
* @param {number} [options.density] Number of pixels per inch (DPI).
|
|
167
174
|
* @returns {Sharp}
|
|
168
175
|
* @throws {Error} Invalid parameters
|
|
169
176
|
*/
|
|
@@ -177,6 +184,13 @@ function withMetadata (options) {
|
|
|
177
184
|
throw is.invalidParameterError('orientation', 'integer between 1 and 8', options.orientation);
|
|
178
185
|
}
|
|
179
186
|
}
|
|
187
|
+
if (is.defined(options.density)) {
|
|
188
|
+
if (is.number(options.density) && options.density > 0) {
|
|
189
|
+
this.options.withMetadataDensity = options.density;
|
|
190
|
+
} else {
|
|
191
|
+
throw is.invalidParameterError('density', 'positive number', options.density);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
180
194
|
if (is.defined(options.icc)) {
|
|
181
195
|
if (is.string(options.icc)) {
|
|
182
196
|
this.options.withMetadataIcc = options.icc;
|
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, AVIF and TIFF images",
|
|
4
|
-
"version": "0.28.
|
|
4
|
+
"version": "0.28.2",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://github.com/lovell/sharp",
|
|
7
7
|
"contributors": [
|
|
@@ -74,12 +74,15 @@
|
|
|
74
74
|
"Christian Flintrup <chr@gigahost.dk>",
|
|
75
75
|
"Manan Jadhav <manan@motionden.com>",
|
|
76
76
|
"Leon Radley <leon@radley.se>",
|
|
77
|
-
"alza54 <alza54@thiocod.in>"
|
|
77
|
+
"alza54 <alza54@thiocod.in>",
|
|
78
|
+
"Jacob Smith <jacob@frende.me>",
|
|
79
|
+
"Michael Nutt <michael@nutt.im>"
|
|
78
80
|
],
|
|
79
81
|
"scripts": {
|
|
80
82
|
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
|
|
81
83
|
"clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
|
|
82
|
-
"test": "
|
|
84
|
+
"test": "npm run test-lint && npm run test-unit && npm run test-licensing",
|
|
85
|
+
"test-lint": "semistandard && cpplint",
|
|
83
86
|
"test-unit": "nyc --reporter=lcov --branches=99 mocha --slow=1000 --timeout=60000 ./test/unit/*.js",
|
|
84
87
|
"test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;MIT\"",
|
|
85
88
|
"test-coverage": "./test/coverage/report.sh",
|
|
@@ -120,7 +123,7 @@
|
|
|
120
123
|
"color": "^3.1.3",
|
|
121
124
|
"detect-libc": "^1.0.3",
|
|
122
125
|
"node-addon-api": "^3.1.0",
|
|
123
|
-
"prebuild-install": "^6.1.
|
|
126
|
+
"prebuild-install": "^6.1.2",
|
|
124
127
|
"semver": "^7.3.5",
|
|
125
128
|
"simple-get": "^3.1.0",
|
|
126
129
|
"tar-fs": "^2.1.1",
|
|
@@ -130,12 +133,12 @@
|
|
|
130
133
|
"async": "^3.2.0",
|
|
131
134
|
"cc": "^3.0.1",
|
|
132
135
|
"decompress-zip": "^0.3.3",
|
|
133
|
-
"documentation": "^13.2.
|
|
136
|
+
"documentation": "^13.2.5",
|
|
134
137
|
"exif-reader": "^1.0.3",
|
|
135
138
|
"icc": "^2.0.0",
|
|
136
139
|
"license-checker": "^25.0.1",
|
|
137
|
-
"mocha": "^8.
|
|
138
|
-
"mock-fs": "^4.
|
|
140
|
+
"mocha": "^8.4.0",
|
|
141
|
+
"mock-fs": "^4.14.0",
|
|
139
142
|
"nyc": "^15.1.0",
|
|
140
143
|
"prebuild": "^10.0.1",
|
|
141
144
|
"rimraf": "^3.0.2",
|
package/src/common.cc
CHANGED
|
@@ -95,6 +95,7 @@ namespace sharp {
|
|
|
95
95
|
descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
|
|
96
96
|
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
|
97
97
|
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
|
98
|
+
descriptor->rawPremultiplied = AttrAsBool(input, "rawPremultiplied");
|
|
98
99
|
}
|
|
99
100
|
// Multi-page input (GIF, TIFF, PDF)
|
|
100
101
|
if (HasAttr(input, "pages")) {
|
|
@@ -235,6 +236,7 @@ namespace sharp {
|
|
|
235
236
|
{ "VipsForeignLoadFits", ImageType::FITS },
|
|
236
237
|
{ "VipsForeignLoadOpenexr", ImageType::EXR },
|
|
237
238
|
{ "VipsForeignLoadVips", ImageType::VIPS },
|
|
239
|
+
{ "VipsForeignLoadVipsFile", ImageType::VIPS },
|
|
238
240
|
{ "VipsForeignLoadRaw", ImageType::RAW }
|
|
239
241
|
};
|
|
240
242
|
|
|
@@ -301,6 +303,9 @@ namespace sharp {
|
|
|
301
303
|
} else {
|
|
302
304
|
image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
|
|
303
305
|
}
|
|
306
|
+
if (descriptor->rawPremultiplied) {
|
|
307
|
+
image = image.unpremultiply();
|
|
308
|
+
}
|
|
304
309
|
imageType = ImageType::RAW;
|
|
305
310
|
} else {
|
|
306
311
|
// Compressed data
|
|
@@ -520,9 +525,8 @@ namespace sharp {
|
|
|
520
525
|
VImage SetDensity(VImage image, const double density) {
|
|
521
526
|
const double pixelsPerMm = density / 25.4;
|
|
522
527
|
VImage copy = image.copy();
|
|
523
|
-
copy.
|
|
524
|
-
copy.
|
|
525
|
-
copy.set(VIPS_META_RESOLUTION_UNIT, "in");
|
|
528
|
+
copy.get_image()->Xres = pixelsPerMm;
|
|
529
|
+
copy.get_image()->Yres = pixelsPerMm;
|
|
526
530
|
return copy;
|
|
527
531
|
}
|
|
528
532
|
|
package/src/common.h
CHANGED
|
@@ -57,6 +57,7 @@ namespace sharp {
|
|
|
57
57
|
int rawChannels;
|
|
58
58
|
int rawWidth;
|
|
59
59
|
int rawHeight;
|
|
60
|
+
bool rawPremultiplied;
|
|
60
61
|
int pages;
|
|
61
62
|
int page;
|
|
62
63
|
int level;
|
|
@@ -80,6 +81,7 @@ namespace sharp {
|
|
|
80
81
|
rawChannels(0),
|
|
81
82
|
rawWidth(0),
|
|
82
83
|
rawHeight(0),
|
|
84
|
+
rawPremultiplied(false),
|
|
83
85
|
pages(1),
|
|
84
86
|
page(0),
|
|
85
87
|
level(0),
|
package/src/pipeline.cc
CHANGED
|
@@ -226,7 +226,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
226
226
|
if (
|
|
227
227
|
xshrink == yshrink && xshrink >= 2 * shrink_on_load_factor &&
|
|
228
228
|
(inputImageType == sharp::ImageType::JPEG || inputImageType == sharp::ImageType::WEBP) &&
|
|
229
|
-
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0
|
|
229
|
+
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0 &&
|
|
230
|
+
image.width() > 3 && image.height() > 3
|
|
230
231
|
) {
|
|
231
232
|
if (xshrink >= 8 * shrink_on_load_factor) {
|
|
232
233
|
xfactor = xfactor / 8;
|
|
@@ -721,6 +722,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
721
722
|
if (baton->withMetadata && baton->withMetadataOrientation != -1) {
|
|
722
723
|
image = sharp::SetExifOrientation(image, baton->withMetadataOrientation);
|
|
723
724
|
}
|
|
725
|
+
// Override pixel density
|
|
726
|
+
if (baton->withMetadataDensity > 0) {
|
|
727
|
+
image = sharp::SetDensity(image, baton->withMetadataDensity);
|
|
728
|
+
}
|
|
724
729
|
// Metadata key/value pairs, e.g. EXIF
|
|
725
730
|
if (!baton->withMetadataStrs.empty()) {
|
|
726
731
|
image = image.copy();
|
|
@@ -1384,6 +1389,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1384
1389
|
baton->fileOut = sharp::AttrAsStr(options, "fileOut");
|
|
1385
1390
|
baton->withMetadata = sharp::AttrAsBool(options, "withMetadata");
|
|
1386
1391
|
baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
|
|
1392
|
+
baton->withMetadataDensity = sharp::AttrAsDouble(options, "withMetadataDensity");
|
|
1387
1393
|
baton->withMetadataIcc = sharp::AttrAsStr(options, "withMetadataIcc");
|
|
1388
1394
|
Napi::Object mdStrs = options.Get("withMetadataStrs").As<Napi::Object>();
|
|
1389
1395
|
Napi::Array mdStrKeys = mdStrs.GetPropertyNames();
|
package/src/pipeline.h
CHANGED
|
@@ -168,6 +168,7 @@ struct PipelineBaton {
|
|
|
168
168
|
std::string err;
|
|
169
169
|
bool withMetadata;
|
|
170
170
|
int withMetadataOrientation;
|
|
171
|
+
double withMetadataDensity;
|
|
171
172
|
std::string withMetadataIcc;
|
|
172
173
|
std::unordered_map<std::string, std::string> withMetadataStrs;
|
|
173
174
|
std::unique_ptr<double[]> convKernel;
|
|
@@ -290,6 +291,7 @@ struct PipelineBaton {
|
|
|
290
291
|
heifLossless(false),
|
|
291
292
|
withMetadata(false),
|
|
292
293
|
withMetadataOrientation(-1),
|
|
294
|
+
withMetadataDensity(0.0),
|
|
293
295
|
convKernelWidth(0),
|
|
294
296
|
convKernelHeight(0),
|
|
295
297
|
convKernelScale(0.0),
|