sharp 0.27.1 → 0.30.5
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 +19 -18
- package/binding.gyp +15 -14
- package/install/can-compile.js +11 -0
- package/install/dll-copy.js +10 -10
- package/install/libvips.js +128 -47
- package/lib/agent.js +1 -1
- package/lib/channel.js +38 -14
- package/lib/colour.js +51 -1
- package/lib/composite.js +19 -2
- package/lib/constructor.js +47 -46
- package/lib/input.js +112 -18
- package/lib/is.js +19 -5
- package/lib/libvips.js +64 -29
- package/lib/operation.js +239 -35
- package/lib/output.js +398 -116
- package/lib/platform.js +5 -3
- package/lib/resize.js +61 -15
- package/lib/sharp.js +32 -0
- package/lib/utility.js +58 -19
- package/package.json +46 -24
- package/src/common.cc +202 -52
- package/src/common.h +59 -10
- package/src/libvips/cplusplus/VConnection.cpp +0 -26
- package/src/libvips/cplusplus/VImage.cpp +88 -32
- package/src/libvips/cplusplus/VInterpolate.cpp +0 -13
- package/src/libvips/cplusplus/vips-operators.cpp +213 -1
- package/src/metadata.cc +26 -0
- package/src/metadata.h +4 -0
- package/src/operations.cc +141 -7
- package/src/operations.h +32 -3
- package/src/pipeline.cc +454 -306
- package/src/pipeline.h +64 -29
- package/src/sharp.cc +1 -0
- package/src/utilities.cc +17 -1
- package/src/utilities.h +1 -0
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# sharp
|
|
2
2
|
|
|
3
|
-
<img src="https://cdn.jsdelivr.net/gh/lovell/sharp@
|
|
3
|
+
<img src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
|
|
4
4
|
|
|
5
5
|
The typical use case for this high speed Node.js module
|
|
6
6
|
is to convert large images in common formats to
|
|
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
|
|
@@ -16,9 +16,17 @@ Lanczos resampling ensures quality is not sacrificed for speed.
|
|
|
16
16
|
As well as image resizing, operations such as
|
|
17
17
|
rotation, extraction, compositing and gamma correction are available.
|
|
18
18
|
|
|
19
|
-
Most modern macOS, Windows and Linux systems running Node.js
|
|
19
|
+
Most modern macOS, Windows and Linux systems running Node.js >= 12.13.0
|
|
20
20
|
do not require any additional install or runtime dependencies.
|
|
21
21
|
|
|
22
|
+
## Documentation
|
|
23
|
+
|
|
24
|
+
Visit [sharp.pixelplumbing.com](https://sharp.pixelplumbing.com/) for complete
|
|
25
|
+
[installation instructions](https://sharp.pixelplumbing.com/install),
|
|
26
|
+
[API documentation](https://sharp.pixelplumbing.com/api-constructor),
|
|
27
|
+
[benchmark tests](https://sharp.pixelplumbing.com/performance) and
|
|
28
|
+
[changelog](https://sharp.pixelplumbing.com/changelog).
|
|
29
|
+
|
|
22
30
|
## Examples
|
|
23
31
|
|
|
24
32
|
```sh
|
|
@@ -43,6 +51,7 @@ sharp(inputBuffer)
|
|
|
43
51
|
sharp('input.jpg')
|
|
44
52
|
.rotate()
|
|
45
53
|
.resize(200)
|
|
54
|
+
.jpeg({ mozjpeg: true })
|
|
46
55
|
.toBuffer()
|
|
47
56
|
.then( data => { ... })
|
|
48
57
|
.catch( err => { ... });
|
|
@@ -84,25 +93,17 @@ readableStream
|
|
|
84
93
|
.pipe(writableStream);
|
|
85
94
|
```
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
[](https://nodejs.org/dist/latest/docs/api/n-api.html#n_api_n_api_version_matrix)
|
|
89
|
-
|
|
90
|
-
### Documentation
|
|
96
|
+
## Contributing
|
|
91
97
|
|
|
92
|
-
|
|
93
|
-
[installation instructions](https://sharp.pixelplumbing.com/install),
|
|
94
|
-
[API documentation](https://sharp.pixelplumbing.com/api-constructor),
|
|
95
|
-
[benchmark tests](https://sharp.pixelplumbing.com/performance) and
|
|
96
|
-
[changelog](https://sharp.pixelplumbing.com/changelog).
|
|
97
|
-
|
|
98
|
-
### Contributing
|
|
99
|
-
|
|
100
|
-
A [guide for contributors](https://github.com/lovell/sharp/blob/master/.github/CONTRIBUTING.md)
|
|
98
|
+
A [guide for contributors](https://github.com/lovell/sharp/blob/main/.github/CONTRIBUTING.md)
|
|
101
99
|
covers reporting bugs, requesting features and submitting code changes.
|
|
102
100
|
|
|
103
|
-
|
|
101
|
+
[](https://coveralls.io/r/lovell/sharp?branch=main)
|
|
102
|
+
[](https://nodejs.org/dist/latest/docs/api/n-api.html#n_api_n_api_version_matrix)
|
|
103
|
+
|
|
104
|
+
## Licensing
|
|
104
105
|
|
|
105
|
-
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.
|
|
106
107
|
|
|
107
108
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
108
109
|
you may not use this file except in compliance with the License.
|
package/binding.gyp
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
'variables': {
|
|
3
3
|
'vips_version': '<!(node -p "require(\'./lib/libvips\').minimumLibvipsVersion")',
|
|
4
|
-
'
|
|
4
|
+
'platform_and_arch': '<!(node -p "require(\'./lib/platform\')()")',
|
|
5
|
+
'sharp_vendor_dir': './vendor/<(vips_version)/<(platform_and_arch)'
|
|
5
6
|
},
|
|
6
7
|
'targets': [{
|
|
7
8
|
'target_name': 'libvips-cpp',
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
'msvs_settings': {
|
|
38
39
|
'VCCLCompilerTool': {
|
|
39
40
|
'ExceptionHandling': 1,
|
|
41
|
+
'Optimization': 1,
|
|
40
42
|
'WholeProgramOptimization': 'true'
|
|
41
43
|
},
|
|
42
44
|
'VCLibrarianTool': {
|
|
@@ -65,9 +67,9 @@
|
|
|
65
67
|
}]
|
|
66
68
|
]
|
|
67
69
|
}, {
|
|
68
|
-
'target_name': 'sharp',
|
|
70
|
+
'target_name': 'sharp-<(platform_and_arch)',
|
|
69
71
|
'defines': [
|
|
70
|
-
'NAPI_VERSION=
|
|
72
|
+
'NAPI_VERSION=5'
|
|
71
73
|
],
|
|
72
74
|
'dependencies': [
|
|
73
75
|
'<!(node -p "require(\'node-addon-api\').gyp")',
|
|
@@ -138,32 +140,30 @@
|
|
|
138
140
|
}],
|
|
139
141
|
['OS == "mac"', {
|
|
140
142
|
'link_settings': {
|
|
141
|
-
'library_dirs': ['
|
|
143
|
+
'library_dirs': ['../<(sharp_vendor_dir)/lib'],
|
|
142
144
|
'libraries': [
|
|
143
|
-
'libvips-cpp.42.dylib'
|
|
144
|
-
'libvips.42.dylib'
|
|
145
|
+
'libvips-cpp.42.dylib'
|
|
145
146
|
]
|
|
146
147
|
},
|
|
147
148
|
'xcode_settings': {
|
|
148
149
|
'OTHER_LDFLAGS': [
|
|
149
150
|
# Ensure runtime linking is relative to sharp.node
|
|
150
|
-
'-Wl,-rpath,\'@loader_path
|
|
151
|
+
'-Wl,-rpath,\'@loader_path/../../<(sharp_vendor_dir)/lib\''
|
|
151
152
|
]
|
|
152
153
|
}
|
|
153
154
|
}],
|
|
154
155
|
['OS == "linux"', {
|
|
155
156
|
'defines': [
|
|
156
|
-
'_GLIBCXX_USE_CXX11_ABI=
|
|
157
|
+
'_GLIBCXX_USE_CXX11_ABI=1'
|
|
157
158
|
],
|
|
158
159
|
'link_settings': {
|
|
159
|
-
'library_dirs': ['
|
|
160
|
+
'library_dirs': ['../<(sharp_vendor_dir)/lib'],
|
|
160
161
|
'libraries': [
|
|
161
|
-
'-l:libvips-cpp.so.42'
|
|
162
|
-
'-l:libvips.so.42'
|
|
162
|
+
'-l:libvips-cpp.so.42'
|
|
163
163
|
],
|
|
164
164
|
'ldflags': [
|
|
165
165
|
# Ensure runtime linking is relative to sharp.node
|
|
166
|
-
'-Wl,-s -Wl,--disable-new-dtags -Wl,-rpath=\'$$ORIGIN
|
|
166
|
+
'-Wl,-s -Wl,--disable-new-dtags -Wl,-rpath=\'$$ORIGIN/../../<(sharp_vendor_dir)/lib\''
|
|
167
167
|
]
|
|
168
168
|
}
|
|
169
169
|
}]
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
'-std=c++0x',
|
|
175
175
|
'-fexceptions',
|
|
176
176
|
'-Wall',
|
|
177
|
-
'-
|
|
177
|
+
'-Os'
|
|
178
178
|
],
|
|
179
179
|
'xcode_settings': {
|
|
180
180
|
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
'OTHER_CPLUSPLUSFLAGS': [
|
|
185
185
|
'-fexceptions',
|
|
186
186
|
'-Wall',
|
|
187
|
-
'-
|
|
187
|
+
'-Oz'
|
|
188
188
|
]
|
|
189
189
|
},
|
|
190
190
|
'configurations': {
|
|
@@ -204,6 +204,7 @@
|
|
|
204
204
|
'msvs_settings': {
|
|
205
205
|
'VCCLCompilerTool': {
|
|
206
206
|
'ExceptionHandling': 1,
|
|
207
|
+
'Optimization': 1,
|
|
207
208
|
'WholeProgramOptimization': 'true'
|
|
208
209
|
},
|
|
209
210
|
'VCLibrarianTool': {
|
package/install/dll-copy.js
CHANGED
|
@@ -4,21 +4,20 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
6
|
const libvips = require('../lib/libvips');
|
|
7
|
-
const
|
|
7
|
+
const platform = require('../lib/platform');
|
|
8
8
|
|
|
9
9
|
const minimumLibvipsVersion = libvips.minimumLibvipsVersion;
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const buildReleaseDir = path.join(
|
|
15
|
-
|
|
11
|
+
const platformAndArch = platform();
|
|
12
|
+
|
|
13
|
+
if (platformAndArch.startsWith('win32')) {
|
|
14
|
+
const buildReleaseDir = path.join(__dirname, '..', 'build', 'Release');
|
|
15
|
+
libvips.log(`Creating ${buildReleaseDir}`);
|
|
16
16
|
try {
|
|
17
|
-
libvips.mkdirSync(buildDir);
|
|
18
17
|
libvips.mkdirSync(buildReleaseDir);
|
|
19
18
|
} catch (err) {}
|
|
20
|
-
const vendorLibDir = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, 'lib');
|
|
21
|
-
|
|
19
|
+
const vendorLibDir = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platformAndArch, 'lib');
|
|
20
|
+
libvips.log(`Copying DLLs from ${vendorLibDir} to ${buildReleaseDir}`);
|
|
22
21
|
try {
|
|
23
22
|
fs
|
|
24
23
|
.readdirSync(vendorLibDir)
|
|
@@ -32,6 +31,7 @@ if (platform === 'win32') {
|
|
|
32
31
|
);
|
|
33
32
|
});
|
|
34
33
|
} catch (err) {
|
|
35
|
-
|
|
34
|
+
libvips.log(err);
|
|
35
|
+
process.exit(1);
|
|
36
36
|
}
|
|
37
37
|
}
|
package/install/libvips.js
CHANGED
|
@@ -5,10 +5,11 @@ 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
|
-
const
|
|
11
|
-
const
|
|
11
|
+
const semverLessThan = require('semver/functions/lt');
|
|
12
|
+
const semverSatisfies = require('semver/functions/satisfies');
|
|
12
13
|
const simpleGet = require('simple-get');
|
|
13
14
|
const tarFs = require('tar-fs');
|
|
14
15
|
|
|
@@ -18,38 +19,91 @@ 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
|
|
|
26
|
+
const hasSharpPrebuild = [
|
|
27
|
+
'darwin-x64',
|
|
28
|
+
'darwin-arm64',
|
|
29
|
+
'linux-arm64',
|
|
30
|
+
'linux-x64',
|
|
31
|
+
'linuxmusl-x64',
|
|
32
|
+
'linuxmusl-arm64',
|
|
33
|
+
'win32-ia32',
|
|
34
|
+
'win32-x64'
|
|
35
|
+
];
|
|
36
|
+
|
|
25
37
|
const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
|
|
38
|
+
const localLibvipsDir = process.env.npm_config_sharp_libvips_local_prebuilds || '';
|
|
26
39
|
const distHost = process.env.npm_config_sharp_libvips_binary_host || 'https://github.com/lovell/sharp-libvips/releases/download';
|
|
27
40
|
const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `${distHost}/v${minimumLibvipsVersionLabelled}/`;
|
|
28
|
-
const
|
|
41
|
+
const installationForced = !!(process.env.npm_config_sharp_install_force || process.env.SHARP_INSTALL_FORCE);
|
|
29
42
|
|
|
30
43
|
const fail = function (err) {
|
|
31
|
-
|
|
44
|
+
libvips.log(err);
|
|
32
45
|
if (err.code === 'EACCES') {
|
|
33
|
-
|
|
46
|
+
libvips.log('Are you trying to install as a root or sudo user?');
|
|
47
|
+
libvips.log('- For npm <= v6, try again with the "--unsafe-perm" flag');
|
|
48
|
+
libvips.log('- For npm >= v8, the user must own the directory "npm install" is run in');
|
|
34
49
|
}
|
|
35
|
-
|
|
36
|
-
npmLog.info('sharp', 'Please see https://sharp.pixelplumbing.com/install for required dependencies');
|
|
50
|
+
libvips.log('Please see https://sharp.pixelplumbing.com/install for required dependencies');
|
|
37
51
|
process.exit(1);
|
|
38
52
|
};
|
|
39
53
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
54
|
+
const handleError = function (err) {
|
|
55
|
+
if (installationForced) {
|
|
56
|
+
libvips.log(`Installation warning: ${err.message}`);
|
|
57
|
+
} else {
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const verifyIntegrity = function (platformAndArch) {
|
|
63
|
+
const expected = libvips.integrity(platformAndArch);
|
|
64
|
+
if (installationForced || !expected) {
|
|
65
|
+
libvips.log(`Integrity check skipped for ${platformAndArch}`);
|
|
66
|
+
return new stream.PassThrough();
|
|
67
|
+
}
|
|
68
|
+
const hash = createHash('sha512');
|
|
69
|
+
return new stream.Transform({
|
|
70
|
+
transform: function (chunk, _encoding, done) {
|
|
71
|
+
hash.update(chunk);
|
|
72
|
+
done(null, chunk);
|
|
73
|
+
},
|
|
74
|
+
flush: function (done) {
|
|
75
|
+
const digest = `sha512-${hash.digest('base64')}`;
|
|
76
|
+
if (expected !== digest) {
|
|
77
|
+
libvips.removeVendoredLibvips();
|
|
78
|
+
libvips.log(`Integrity expected: ${expected}`);
|
|
79
|
+
libvips.log(`Integrity received: ${digest}`);
|
|
80
|
+
done(new Error(`Integrity check failed for ${platformAndArch}`));
|
|
81
|
+
} else {
|
|
82
|
+
libvips.log(`Integrity check passed for ${platformAndArch}`);
|
|
83
|
+
done();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const extractTarball = function (tarPath, platformAndArch) {
|
|
90
|
+
const versionedVendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platformAndArch);
|
|
44
91
|
libvips.mkdirSync(versionedVendorPath);
|
|
92
|
+
|
|
93
|
+
const ignoreVendorInclude = hasSharpPrebuild.includes(platformAndArch) && !process.env.npm_config_build_from_source;
|
|
94
|
+
const ignore = function (name) {
|
|
95
|
+
return ignoreVendorInclude && name.includes('include/');
|
|
96
|
+
};
|
|
97
|
+
|
|
45
98
|
stream.pipeline(
|
|
46
99
|
fs.createReadStream(tarPath),
|
|
47
|
-
|
|
48
|
-
|
|
100
|
+
verifyIntegrity(platformAndArch),
|
|
101
|
+
new zlib.BrotliDecompress(),
|
|
102
|
+
tarFs.extract(versionedVendorPath, { ignore }),
|
|
49
103
|
function (err) {
|
|
50
104
|
if (err) {
|
|
51
105
|
if (/unexpected end of file/.test(err.message)) {
|
|
52
|
-
|
|
106
|
+
fail(new Error(`Please delete ${tarPath} as it is not a valid tarball`));
|
|
53
107
|
}
|
|
54
108
|
fail(err);
|
|
55
109
|
}
|
|
@@ -62,11 +116,11 @@ try {
|
|
|
62
116
|
|
|
63
117
|
if (useGlobalLibvips) {
|
|
64
118
|
const globalLibvipsVersion = libvips.globalLibvipsVersion();
|
|
65
|
-
|
|
66
|
-
|
|
119
|
+
libvips.log(`Detected globally-installed libvips v${globalLibvipsVersion}`);
|
|
120
|
+
libvips.log('Building from source via node-gyp');
|
|
67
121
|
process.exit(1);
|
|
68
122
|
} else if (libvips.hasVendoredLibvips()) {
|
|
69
|
-
|
|
123
|
+
libvips.log(`Using existing vendored libvips v${minimumLibvipsVersion}`);
|
|
70
124
|
} else {
|
|
71
125
|
// Is this arch/platform supported?
|
|
72
126
|
const arch = process.env.npm_config_arch || process.arch;
|
|
@@ -74,33 +128,45 @@ try {
|
|
|
74
128
|
if (arch === 'ia32' && !platformAndArch.startsWith('win32')) {
|
|
75
129
|
throw new Error(`Intel Architecture 32-bit systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
76
130
|
}
|
|
131
|
+
if (platformAndArch === 'darwin-arm64') {
|
|
132
|
+
throw new Error("Please run 'brew install vips' to install libvips on Apple M1 (ARM64) systems");
|
|
133
|
+
}
|
|
77
134
|
if (platformAndArch === 'freebsd-x64' || platformAndArch === 'openbsd-x64' || platformAndArch === 'sunos-x64') {
|
|
78
135
|
throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
79
136
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
137
|
+
// Linux libc version check
|
|
138
|
+
const libcFamily = detectLibc.familySync();
|
|
139
|
+
const libcVersion = detectLibc.versionSync();
|
|
140
|
+
if (libcFamily === detectLibc.GLIBC && libcVersion && minimumGlibcVersionByArch[arch]) {
|
|
141
|
+
if (semverLessThan(`${libcVersion}.0`, `${minimumGlibcVersionByArch[arch]}.0`)) {
|
|
142
|
+
handleError(new Error(`Use with glibc ${libcVersion} requires manual installation of libvips >= ${minimumLibvipsVersion}`));
|
|
83
143
|
}
|
|
84
144
|
}
|
|
85
|
-
|
|
145
|
+
if (libcFamily === detectLibc.MUSL && libcVersion) {
|
|
146
|
+
if (semverLessThan(libcVersion, '1.1.24')) {
|
|
147
|
+
handleError(new Error(`Use with musl ${libcVersion} requires manual installation of libvips >= ${minimumLibvipsVersion}`));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Node.js minimum version check
|
|
86
151
|
const supportedNodeVersion = process.env.npm_package_engines_node || require('../package.json').engines.node;
|
|
87
|
-
if (!
|
|
88
|
-
|
|
152
|
+
if (!semverSatisfies(process.versions.node, supportedNodeVersion)) {
|
|
153
|
+
handleError(new Error(`Expected Node.js version ${supportedNodeVersion} but found ${process.versions.node}`));
|
|
89
154
|
}
|
|
90
155
|
|
|
91
|
-
const extension = supportsBrotli ? 'br' : 'gz';
|
|
92
|
-
|
|
93
156
|
// Download to per-process temporary file
|
|
94
|
-
const tarFilename = ['libvips',
|
|
157
|
+
const tarFilename = ['libvips', minimumLibvipsVersionLabelled, platformAndArch].join('-') + '.tar.br';
|
|
95
158
|
const tarPathCache = path.join(libvips.cachePath(), tarFilename);
|
|
96
159
|
if (fs.existsSync(tarPathCache)) {
|
|
97
|
-
|
|
98
|
-
extractTarball(tarPathCache);
|
|
160
|
+
libvips.log(`Using cached ${tarPathCache}`);
|
|
161
|
+
extractTarball(tarPathCache, platformAndArch);
|
|
162
|
+
} else if (localLibvipsDir) {
|
|
163
|
+
// If localLibvipsDir is given try to use binaries from local directory
|
|
164
|
+
const tarPathLocal = path.join(path.resolve(localLibvipsDir), `v${minimumLibvipsVersionLabelled}`, tarFilename);
|
|
165
|
+
libvips.log(`Using local libvips from ${tarPathLocal}`);
|
|
166
|
+
extractTarball(tarPathLocal, platformAndArch);
|
|
99
167
|
} else {
|
|
100
|
-
const tarPathTemp = path.join(os.tmpdir(), `${process.pid}-${tarFilename}`);
|
|
101
|
-
const tmpFile = fs.createWriteStream(tarPathTemp);
|
|
102
168
|
const url = distBaseUrl + tarFilename;
|
|
103
|
-
|
|
169
|
+
libvips.log(`Downloading ${url}`);
|
|
104
170
|
simpleGet({ url: url, agent: agent() }, function (err, response) {
|
|
105
171
|
if (err) {
|
|
106
172
|
fail(err);
|
|
@@ -109,24 +175,39 @@ try {
|
|
|
109
175
|
} else if (response.statusCode !== 200) {
|
|
110
176
|
fail(new Error(`Status ${response.statusCode} ${response.statusMessage}`));
|
|
111
177
|
} else {
|
|
178
|
+
const tarPathTemp = path.join(os.tmpdir(), `${process.pid}-${tarFilename}`);
|
|
179
|
+
const tmpFileStream = fs.createWriteStream(tarPathTemp);
|
|
112
180
|
response
|
|
113
|
-
.on('error',
|
|
114
|
-
|
|
181
|
+
.on('error', function (err) {
|
|
182
|
+
tmpFileStream.destroy(err);
|
|
183
|
+
})
|
|
184
|
+
.on('close', function () {
|
|
185
|
+
if (!response.complete) {
|
|
186
|
+
tmpFileStream.destroy(new Error('Download incomplete (connection was terminated)'));
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
.pipe(tmpFileStream);
|
|
190
|
+
tmpFileStream
|
|
191
|
+
.on('error', function (err) {
|
|
192
|
+
// Clean up temporary file
|
|
193
|
+
try {
|
|
194
|
+
fs.unlinkSync(tarPathTemp);
|
|
195
|
+
} catch (e) {}
|
|
196
|
+
fail(err);
|
|
197
|
+
})
|
|
198
|
+
.on('close', function () {
|
|
199
|
+
try {
|
|
200
|
+
// Attempt to rename
|
|
201
|
+
fs.renameSync(tarPathTemp, tarPathCache);
|
|
202
|
+
} catch (err) {
|
|
203
|
+
// Fall back to copy and unlink
|
|
204
|
+
fs.copyFileSync(tarPathTemp, tarPathCache);
|
|
205
|
+
fs.unlinkSync(tarPathTemp);
|
|
206
|
+
}
|
|
207
|
+
extractTarball(tarPathCache, platformAndArch);
|
|
208
|
+
});
|
|
115
209
|
}
|
|
116
210
|
});
|
|
117
|
-
tmpFile
|
|
118
|
-
.on('error', fail)
|
|
119
|
-
.on('close', function () {
|
|
120
|
-
try {
|
|
121
|
-
// Attempt to rename
|
|
122
|
-
fs.renameSync(tarPathTemp, tarPathCache);
|
|
123
|
-
} catch (err) {
|
|
124
|
-
// Fall back to copy and unlink
|
|
125
|
-
fs.copyFileSync(tarPathTemp, tarPathCache);
|
|
126
|
-
fs.unlinkSync(tarPathTemp);
|
|
127
|
-
}
|
|
128
|
-
extractTarball(tarPathCache);
|
|
129
|
-
});
|
|
130
211
|
}
|
|
131
212
|
}
|
|
132
213
|
} catch (err) {
|
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/channel.js
CHANGED
|
@@ -15,6 +15,8 @@ const bool = {
|
|
|
15
15
|
/**
|
|
16
16
|
* Remove alpha channel, if any. This is a no-op if the image does not have an alpha channel.
|
|
17
17
|
*
|
|
18
|
+
* See also {@link /api-operation#flatten|flatten}.
|
|
19
|
+
*
|
|
18
20
|
* @example
|
|
19
21
|
* sharp('rgba.png')
|
|
20
22
|
* .removeAlpha()
|
|
@@ -30,21 +32,39 @@ function removeAlpha () {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
|
-
* Ensure
|
|
35
|
+
* Ensure the output image has an alpha transparency channel.
|
|
36
|
+
* If missing, the added alpha channel will have the specified
|
|
37
|
+
* transparency level, defaulting to fully-opaque (1).
|
|
38
|
+
* This is a no-op if the image already has an alpha channel.
|
|
34
39
|
*
|
|
35
40
|
* @since 0.21.2
|
|
36
41
|
*
|
|
37
42
|
* @example
|
|
38
|
-
*
|
|
43
|
+
* // rgba.png will be a 4 channel image with a fully-opaque alpha channel
|
|
44
|
+
* await sharp('rgb.jpg')
|
|
39
45
|
* .ensureAlpha()
|
|
40
|
-
* .toFile('rgba.png'
|
|
41
|
-
* // rgba.png is a 4 channel image with a fully opaque alpha channel
|
|
42
|
-
* });
|
|
46
|
+
* .toFile('rgba.png')
|
|
43
47
|
*
|
|
48
|
+
* @example
|
|
49
|
+
* // rgba is a 4 channel image with a fully-transparent alpha channel
|
|
50
|
+
* const rgba = await sharp(rgb)
|
|
51
|
+
* .ensureAlpha(0)
|
|
52
|
+
* .toBuffer();
|
|
53
|
+
*
|
|
54
|
+
* @param {number} [alpha=1] - alpha transparency level (0=fully-transparent, 1=fully-opaque)
|
|
44
55
|
* @returns {Sharp}
|
|
56
|
+
* @throws {Error} Invalid alpha transparency level
|
|
45
57
|
*/
|
|
46
|
-
function ensureAlpha () {
|
|
47
|
-
|
|
58
|
+
function ensureAlpha (alpha) {
|
|
59
|
+
if (is.defined(alpha)) {
|
|
60
|
+
if (is.number(alpha) && is.inRange(alpha, 0, 1)) {
|
|
61
|
+
this.options.ensureAlpha = alpha;
|
|
62
|
+
} else {
|
|
63
|
+
throw is.invalidParameterError('alpha', 'number between 0 and 1', alpha);
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
this.options.ensureAlpha = 1;
|
|
67
|
+
}
|
|
48
68
|
return this;
|
|
49
69
|
}
|
|
50
70
|
|
|
@@ -52,13 +72,17 @@ function ensureAlpha () {
|
|
|
52
72
|
* Extract a single channel from a multi-channel image.
|
|
53
73
|
*
|
|
54
74
|
* @example
|
|
55
|
-
*
|
|
75
|
+
* // green.jpg is a greyscale image containing the green channel of the input
|
|
76
|
+
* await sharp(input)
|
|
56
77
|
* .extractChannel('green')
|
|
57
|
-
* .
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
78
|
+
* .toFile('green.jpg');
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* // red1 is the red value of the first pixel, red2 the second pixel etc.
|
|
82
|
+
* const [red1, red2, ...] = await sharp(input)
|
|
83
|
+
* .extractChannel(0)
|
|
84
|
+
* .raw()
|
|
85
|
+
* .toBuffer();
|
|
62
86
|
*
|
|
63
87
|
* @param {number|string} channel - zero-indexed channel/band number to extract, or `red`, `green`, `blue` or `alpha`.
|
|
64
88
|
* @returns {Sharp}
|
|
@@ -74,7 +98,7 @@ function extractChannel (channel) {
|
|
|
74
98
|
} else {
|
|
75
99
|
throw is.invalidParameterError('channel', 'integer or one of: red, green, blue, alpha', channel);
|
|
76
100
|
}
|
|
77
|
-
return this;
|
|
101
|
+
return this.toColourspace('b-w');
|
|
78
102
|
}
|
|
79
103
|
|
|
80
104
|
/**
|
package/lib/colour.js
CHANGED
|
@@ -19,6 +19,11 @@ const colourspace = {
|
|
|
19
19
|
* Tint the image using the provided chroma while preserving the image luminance.
|
|
20
20
|
* An alpha channel may be present and will be unchanged by the operation.
|
|
21
21
|
*
|
|
22
|
+
* @example
|
|
23
|
+
* const output = await sharp(input)
|
|
24
|
+
* .tint({ r: 255, g: 240, b: 16 })
|
|
25
|
+
* .toBuffer();
|
|
26
|
+
*
|
|
22
27
|
* @param {string|Object} rgb - parsed by the [color](https://www.npmjs.org/package/color) module to extract chroma values.
|
|
23
28
|
* @returns {Sharp}
|
|
24
29
|
* @throws {Error} Invalid parameter
|
|
@@ -37,6 +42,10 @@ function tint (rgb) {
|
|
|
37
42
|
* This may be overridden by other sharp operations such as `toColourspace('b-w')`,
|
|
38
43
|
* which will produce an output image containing one color channel.
|
|
39
44
|
* An alpha channel may be present, and will be unchanged by the operation.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const output = await sharp(input).greyscale().toBuffer();
|
|
48
|
+
*
|
|
40
49
|
* @param {Boolean} [greyscale=true]
|
|
41
50
|
* @returns {Sharp}
|
|
42
51
|
*/
|
|
@@ -54,6 +63,45 @@ function grayscale (grayscale) {
|
|
|
54
63
|
return this.greyscale(grayscale);
|
|
55
64
|
}
|
|
56
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Set the pipeline colourspace.
|
|
68
|
+
*
|
|
69
|
+
* The input image will be converted to the provided colourspace at the start of the pipeline.
|
|
70
|
+
* All operations will use this colourspace before converting to the output colourspace, as defined by {@link toColourspace}.
|
|
71
|
+
*
|
|
72
|
+
* This feature is experimental and has not yet been fully-tested with all operations.
|
|
73
|
+
*
|
|
74
|
+
* @since 0.29.0
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* // Run pipeline in 16 bits per channel RGB while converting final result to 8 bits per channel sRGB.
|
|
78
|
+
* await sharp(input)
|
|
79
|
+
* .pipelineColourspace('rgb16')
|
|
80
|
+
* .toColourspace('srgb')
|
|
81
|
+
* .toFile('16bpc-pipeline-to-8bpc-output.png')
|
|
82
|
+
*
|
|
83
|
+
* @param {string} [colourspace] - pipeline colourspace e.g. `rgb16`, `scrgb`, `lab`, `grey16` [...](https://github.com/libvips/libvips/blob/41cff4e9d0838498487a00623462204eb10ee5b8/libvips/iofuncs/enumtypes.c#L774)
|
|
84
|
+
* @returns {Sharp}
|
|
85
|
+
* @throws {Error} Invalid parameters
|
|
86
|
+
*/
|
|
87
|
+
function pipelineColourspace (colourspace) {
|
|
88
|
+
if (!is.string(colourspace)) {
|
|
89
|
+
throw is.invalidParameterError('colourspace', 'string', colourspace);
|
|
90
|
+
}
|
|
91
|
+
this.options.colourspaceInput = colourspace;
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Alternative spelling of `pipelineColourspace`.
|
|
97
|
+
* @param {string} [colorspace] - pipeline colorspace.
|
|
98
|
+
* @returns {Sharp}
|
|
99
|
+
* @throws {Error} Invalid parameters
|
|
100
|
+
*/
|
|
101
|
+
function pipelineColorspace (colorspace) {
|
|
102
|
+
return this.pipelineColourspace(colorspace);
|
|
103
|
+
}
|
|
104
|
+
|
|
57
105
|
/**
|
|
58
106
|
* Set the output colourspace.
|
|
59
107
|
* By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
|
@@ -64,7 +112,7 @@ function grayscale (grayscale) {
|
|
|
64
112
|
* .toColourspace('rgb16')
|
|
65
113
|
* .toFile('16-bpp.png')
|
|
66
114
|
*
|
|
67
|
-
* @param {string} [colourspace] - output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/libvips/libvips/blob/
|
|
115
|
+
* @param {string} [colourspace] - output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/libvips/libvips/blob/3c0bfdf74ce1dc37a6429bed47fa76f16e2cd70a/libvips/iofuncs/enumtypes.c#L777-L794)
|
|
68
116
|
* @returns {Sharp}
|
|
69
117
|
* @throws {Error} Invalid parameters
|
|
70
118
|
*/
|
|
@@ -119,6 +167,8 @@ module.exports = function (Sharp) {
|
|
|
119
167
|
tint,
|
|
120
168
|
greyscale,
|
|
121
169
|
grayscale,
|
|
170
|
+
pipelineColourspace,
|
|
171
|
+
pipelineColorspace,
|
|
122
172
|
toColourspace,
|
|
123
173
|
toColorspace,
|
|
124
174
|
// Private
|