sharp 0.20.8 → 0.21.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 +3 -3
- package/binding.gyp +5 -0
- package/docs/api-colour.md +1 -19
- package/docs/api-input.md +5 -2
- package/docs/api-operation.md +40 -115
- package/docs/api-resize.md +159 -109
- package/docs/api-utility.md +4 -7
- package/docs/changelog.md +41 -0
- package/docs/index.md +5 -4
- package/docs/install.md +18 -38
- package/docs/performance.md +14 -21
- package/install/libvips.js +21 -20
- package/lib/colour.js +34 -15
- package/lib/constructor.js +15 -39
- package/lib/input.js +5 -2
- package/lib/libvips.js +7 -1
- package/lib/operation.js +27 -118
- package/lib/platform.js +4 -1
- package/lib/resize.js +308 -104
- package/lib/utility.js +5 -8
- package/package.json +12 -11
- package/src/common.cc +45 -8
- package/src/common.h +9 -7
- package/src/libvips/cplusplus/VImage.cpp +95 -95
- package/src/libvips/cplusplus/vips-operators.cpp +268 -185
- package/src/metadata.cc +15 -0
- package/src/metadata.h +3 -0
- package/src/operations.cc +15 -48
- package/src/operations.h +1 -1
- package/src/pipeline.cc +39 -80
- package/src/pipeline.h +19 -13
- package/src/utilities.cc +1 -1
package/docs/performance.md
CHANGED
|
@@ -3,19 +3,17 @@
|
|
|
3
3
|
### Test environment
|
|
4
4
|
|
|
5
5
|
* AWS EC2 eu-west-1 [c5.large](https://aws.amazon.com/ec2/instance-types/c5/) (2x Xeon Platinum 8124M CPU @ 3.00GHz)
|
|
6
|
-
* Ubuntu
|
|
7
|
-
* Node.js
|
|
6
|
+
* Ubuntu 18.04 (hvm-ssd/ubuntu-bionic-18.04-amd64-server-20180912 ami-00035f41c82244dab)
|
|
7
|
+
* Node.js v10.11.0
|
|
8
8
|
|
|
9
9
|
### The contenders
|
|
10
10
|
|
|
11
|
-
* [jimp](https://www.npmjs.com/package/jimp) v0.
|
|
12
|
-
* [
|
|
13
|
-
* [mapnik](https://www.npmjs.org/package/mapnik) v3.6.2 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities.
|
|
11
|
+
* [jimp](https://www.npmjs.com/package/jimp) v0.5.3 - Image processing in pure JavaScript. Provides bicubic interpolation.
|
|
12
|
+
* [mapnik](https://www.npmjs.org/package/mapnik) v4.0.1 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities.
|
|
14
13
|
* [imagemagick-native](https://www.npmjs.com/package/imagemagick-native) v1.9.3 - Wrapper around libmagick++, supports Buffers only.
|
|
15
14
|
* [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*".
|
|
16
15
|
* [gm](https://www.npmjs.com/package/gm) v1.23.1 - Fully featured wrapper around GraphicsMagick's `gm` command line utility.
|
|
17
|
-
*
|
|
18
|
-
* sharp v0.19.0 / libvips v8.6.1 - Caching within libvips disabled to ensure a fair comparison.
|
|
16
|
+
* sharp v0.21.0 / libvips v8.7.0 - Caching within libvips disabled to ensure a fair comparison.
|
|
19
17
|
|
|
20
18
|
### The task
|
|
21
19
|
|
|
@@ -27,19 +25,14 @@ then compress to JPEG at a "quality" setting of 80.
|
|
|
27
25
|
|
|
28
26
|
| Module | Input | Output | Ops/sec | Speed-up |
|
|
29
27
|
| :----------------- | :----- | :----- | ------: | -------: |
|
|
30
|
-
| jimp
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
| imagemagick-native | buffer | buffer | 4.
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
| sharp | stream | stream | 24.43 | 21.4 |
|
|
39
|
-
| sharp | file | file | 25.97 | 22.7 |
|
|
40
|
-
| sharp | file | buffer | 26.00 | 22.8 |
|
|
41
|
-
| sharp | buffer | file | 26.33 | 23.0 |
|
|
42
|
-
| sharp | buffer | buffer | 26.43 | 23.1 |
|
|
28
|
+
| jimp | buffer | buffer | 0.71 | 1.0 |
|
|
29
|
+
| mapnik | buffer | buffer | 3.32 | 4.7 |
|
|
30
|
+
| gm | buffer | buffer | 3.97 | 5.6 |
|
|
31
|
+
| imagemagick-native | buffer | buffer | 4.06 | 5.7 |
|
|
32
|
+
| imagemagick | file | file | 4.24 | 6.0 |
|
|
33
|
+
| sharp | stream | stream | 25.30 | 35.6 |
|
|
34
|
+
| sharp | file | file | 26.17 | 36.9 |
|
|
35
|
+
| sharp | buffer | buffer | 26.45 | 37.3 |
|
|
43
36
|
|
|
44
37
|
Greater libvips performance can be expected with caching enabled (default)
|
|
45
38
|
and using 8+ core machines, especially those with larger L1/L2 CPU caches.
|
|
@@ -57,7 +50,7 @@ brew install mapnik
|
|
|
57
50
|
```
|
|
58
51
|
|
|
59
52
|
```sh
|
|
60
|
-
sudo apt-get install imagemagick libmagick++-dev graphicsmagick
|
|
53
|
+
sudo apt-get install imagemagick libmagick++-dev graphicsmagick libmapnik-dev
|
|
61
54
|
```
|
|
62
55
|
|
|
63
56
|
```sh
|
package/install/libvips.js
CHANGED
|
@@ -18,6 +18,12 @@ const platform = require('../lib/platform');
|
|
|
18
18
|
const minimumLibvipsVersion = libvips.minimumLibvipsVersion;
|
|
19
19
|
const distBaseUrl = process.env.SHARP_DIST_BASE_URL || `https://github.com/lovell/sharp-libvips/releases/download/v${minimumLibvipsVersion}/`;
|
|
20
20
|
|
|
21
|
+
const fail = function (err) {
|
|
22
|
+
npmLog.error('sharp', err.message);
|
|
23
|
+
npmLog.error('sharp', 'Please see http://sharp.pixelplumbing.com/page/install');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
};
|
|
26
|
+
|
|
21
27
|
const extractTarball = function (tarPath) {
|
|
22
28
|
const vendorPath = path.join(__dirname, '..', 'vendor');
|
|
23
29
|
libvips.mkdirSync(vendorPath);
|
|
@@ -27,9 +33,7 @@ const extractTarball = function (tarPath) {
|
|
|
27
33
|
cwd: vendorPath,
|
|
28
34
|
strict: true
|
|
29
35
|
})
|
|
30
|
-
.catch(
|
|
31
|
-
throw err;
|
|
32
|
-
});
|
|
36
|
+
.catch(fail);
|
|
33
37
|
};
|
|
34
38
|
|
|
35
39
|
try {
|
|
@@ -54,9 +58,6 @@ try {
|
|
|
54
58
|
if (platformAndArch === 'freebsd-x64') {
|
|
55
59
|
throw new Error(`FreeBSD systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
56
60
|
}
|
|
57
|
-
if (detectLibc.isNonGlibcLinux) {
|
|
58
|
-
throw new Error(`Use with ${detectLibc.family} libc requires manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
59
|
-
}
|
|
60
61
|
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version && semver.lt(`${detectLibc.version}.0`, '2.13.0')) {
|
|
61
62
|
throw new Error(`Use with glibc version ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
62
63
|
}
|
|
@@ -80,21 +81,21 @@ try {
|
|
|
80
81
|
}
|
|
81
82
|
response.pipe(tmpFile);
|
|
82
83
|
});
|
|
83
|
-
tmpFile
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
84
|
+
tmpFile
|
|
85
|
+
.on('error', fail)
|
|
86
|
+
.on('close', function () {
|
|
87
|
+
try {
|
|
88
|
+
// Attempt to rename
|
|
89
|
+
fs.renameSync(tarPathTemp, tarPathCache);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
// Fall back to copy and unlink
|
|
92
|
+
copyFileSync(tarPathTemp, tarPathCache);
|
|
93
|
+
fs.unlinkSync(tarPathTemp);
|
|
94
|
+
}
|
|
95
|
+
extractTarball(tarPathCache);
|
|
96
|
+
});
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
} catch (err) {
|
|
97
|
-
|
|
98
|
-
npmLog.error('sharp', 'Please see http://sharp.pixelplumbing.com/page/install');
|
|
99
|
-
process.exit(1);
|
|
100
|
+
fail(err);
|
|
100
101
|
}
|
package/lib/colour.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const deprecate = require('util').deprecate;
|
|
4
|
+
|
|
3
5
|
const color = require('color');
|
|
4
6
|
const is = require('./is');
|
|
5
7
|
|
|
@@ -16,25 +18,20 @@ const colourspace = {
|
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* Delegates to the _color_ module, which can throw an Error
|
|
23
|
-
* but is liberal in what it accepts, clipping values to sensible min/max.
|
|
24
|
-
* The alpha value is a float between `0` (transparent) and `1` (opaque).
|
|
25
|
-
*
|
|
26
|
-
* @param {String|Object} rgba - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
|
27
|
-
* @returns {Sharp}
|
|
28
|
-
* @throws {Error} Invalid parameter
|
|
21
|
+
* @deprecated
|
|
22
|
+
* @private
|
|
29
23
|
*/
|
|
30
24
|
function background (rgba) {
|
|
31
25
|
const colour = color(rgba);
|
|
32
|
-
|
|
26
|
+
const background = [
|
|
33
27
|
colour.red(),
|
|
34
28
|
colour.green(),
|
|
35
29
|
colour.blue(),
|
|
36
30
|
Math.round(colour.alpha() * 255)
|
|
37
31
|
];
|
|
32
|
+
this.options.resizeBackground = background;
|
|
33
|
+
this.options.extendBackground = background;
|
|
34
|
+
this.options.flattenBackground = background.slice(0, 3);
|
|
38
35
|
return this;
|
|
39
36
|
}
|
|
40
37
|
|
|
@@ -80,7 +77,7 @@ function grayscale (grayscale) {
|
|
|
80
77
|
/**
|
|
81
78
|
* Set the output colourspace.
|
|
82
79
|
* By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
|
83
|
-
* @param {String} [colourspace] - output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/
|
|
80
|
+
* @param {String} [colourspace] - output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
|
|
84
81
|
* @returns {Sharp}
|
|
85
82
|
* @throws {Error} Invalid parameters
|
|
86
83
|
*/
|
|
@@ -102,23 +99,45 @@ function toColorspace (colorspace) {
|
|
|
102
99
|
return this.toColourspace(colorspace);
|
|
103
100
|
}
|
|
104
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Update a colour attribute of the this.options Object.
|
|
104
|
+
* @private
|
|
105
|
+
* @param {String} key
|
|
106
|
+
* @param {String|Object} val
|
|
107
|
+
* @throws {Error} Invalid key
|
|
108
|
+
*/
|
|
109
|
+
function _setColourOption (key, val) {
|
|
110
|
+
if (is.object(val) || is.string(val)) {
|
|
111
|
+
const colour = color(val);
|
|
112
|
+
this.options[key] = [
|
|
113
|
+
colour.red(),
|
|
114
|
+
colour.green(),
|
|
115
|
+
colour.blue(),
|
|
116
|
+
Math.round(colour.alpha() * 255)
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
105
121
|
/**
|
|
106
122
|
* Decorate the Sharp prototype with colour-related functions.
|
|
107
123
|
* @private
|
|
108
124
|
*/
|
|
109
125
|
module.exports = function (Sharp) {
|
|
110
|
-
// Public instance functions
|
|
111
126
|
[
|
|
112
|
-
|
|
127
|
+
// Public
|
|
113
128
|
tint,
|
|
114
129
|
greyscale,
|
|
115
130
|
grayscale,
|
|
116
131
|
toColourspace,
|
|
117
|
-
toColorspace
|
|
132
|
+
toColorspace,
|
|
133
|
+
// Private
|
|
134
|
+
_setColourOption
|
|
118
135
|
].forEach(function (f) {
|
|
119
136
|
Sharp.prototype[f.name] = f;
|
|
120
137
|
});
|
|
121
138
|
// Class attributes
|
|
122
139
|
Sharp.colourspace = colourspace;
|
|
123
140
|
Sharp.colorspace = colourspace;
|
|
141
|
+
// Deprecated
|
|
142
|
+
Sharp.prototype.background = deprecate(background, 'background(background) is deprecated, use resize({ background }), extend({ background }) or flatten({ background }) instead');
|
|
124
143
|
};
|
package/lib/constructor.js
CHANGED
|
@@ -4,42 +4,10 @@ const path = require('path');
|
|
|
4
4
|
const util = require('util');
|
|
5
5
|
const stream = require('stream');
|
|
6
6
|
const events = require('events');
|
|
7
|
-
const semver = require('semver');
|
|
8
7
|
const is = require('./is');
|
|
9
|
-
const platform = require('./platform');
|
|
10
|
-
const sharp = require('../build/Release/sharp.node');
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
let vendorPlatformId;
|
|
15
|
-
try {
|
|
16
|
-
vendorPlatformId = require('../vendor/platform.json');
|
|
17
|
-
} catch (err) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const currentPlatformId = platform();
|
|
21
|
-
/* istanbul ignore if */
|
|
22
|
-
if (currentPlatformId !== vendorPlatformId) {
|
|
23
|
-
throw new Error(`'${vendorPlatformId}' binaries cannot be used on the '${currentPlatformId}' platform. Please remove the 'node_modules/sharp/vendor' directory and run 'npm rebuild'.`);
|
|
24
|
-
}
|
|
25
|
-
})();
|
|
26
|
-
|
|
27
|
-
// Versioning
|
|
28
|
-
let versions = {
|
|
29
|
-
vips: sharp.libvipsVersion()
|
|
30
|
-
};
|
|
31
|
-
(function () {
|
|
32
|
-
// Does libvips meet minimum requirement?
|
|
33
|
-
const libvipsVersionMin = require('../package.json').config.libvips;
|
|
34
|
-
/* istanbul ignore if */
|
|
35
|
-
if (semver.lt(versions.vips, libvipsVersionMin)) {
|
|
36
|
-
throw new Error('Found libvips ' + versions.vips + ' but require at least ' + libvipsVersionMin);
|
|
37
|
-
}
|
|
38
|
-
// Include versions of dependencies, if present
|
|
39
|
-
try {
|
|
40
|
-
versions = require('../vendor/versions.json');
|
|
41
|
-
} catch (err) {}
|
|
42
|
-
})();
|
|
9
|
+
require('./libvips').hasVendoredLibvips();
|
|
10
|
+
const sharp = require('../build/Release/sharp.node');
|
|
43
11
|
|
|
44
12
|
// Use NODE_DEBUG=sharp to enable libvips warnings
|
|
45
13
|
const debuglog = util.debuglog('sharp');
|
|
@@ -136,10 +104,12 @@ const Sharp = function (input, options) {
|
|
|
136
104
|
width: -1,
|
|
137
105
|
height: -1,
|
|
138
106
|
canvas: 'crop',
|
|
139
|
-
|
|
140
|
-
|
|
107
|
+
position: 0,
|
|
108
|
+
resizeBackground: [0, 0, 0, 255],
|
|
141
109
|
useExifOrientation: false,
|
|
142
110
|
angle: 0,
|
|
111
|
+
rotationAngle: 0,
|
|
112
|
+
rotationBackground: [0, 0, 0, 255],
|
|
143
113
|
rotateBeforePreExtract: false,
|
|
144
114
|
flip: false,
|
|
145
115
|
flop: false,
|
|
@@ -147,14 +117,15 @@ const Sharp = function (input, options) {
|
|
|
147
117
|
extendBottom: 0,
|
|
148
118
|
extendLeft: 0,
|
|
149
119
|
extendRight: 0,
|
|
120
|
+
extendBackground: [0, 0, 0, 255],
|
|
150
121
|
withoutEnlargement: false,
|
|
151
122
|
kernel: 'lanczos3',
|
|
152
123
|
fastShrinkOnLoad: true,
|
|
153
124
|
// operations
|
|
154
|
-
background: [0, 0, 0, 255],
|
|
155
125
|
tintA: 128,
|
|
156
126
|
tintB: 128,
|
|
157
127
|
flatten: false,
|
|
128
|
+
flattenBackground: [0, 0, 0],
|
|
158
129
|
negate: false,
|
|
159
130
|
medianSize: 0,
|
|
160
131
|
blurSigma: 0,
|
|
@@ -163,7 +134,7 @@ const Sharp = function (input, options) {
|
|
|
163
134
|
sharpenJagged: 2,
|
|
164
135
|
threshold: 0,
|
|
165
136
|
thresholdGrayscale: true,
|
|
166
|
-
|
|
137
|
+
trimThreshold: 0,
|
|
167
138
|
gamma: 0,
|
|
168
139
|
greyscale: false,
|
|
169
140
|
normalise: 0,
|
|
@@ -251,7 +222,12 @@ Sharp.format = sharp.format();
|
|
|
251
222
|
* @example
|
|
252
223
|
* console.log(sharp.versions);
|
|
253
224
|
*/
|
|
254
|
-
Sharp.versions =
|
|
225
|
+
Sharp.versions = {
|
|
226
|
+
vips: sharp.libvipsVersion()
|
|
227
|
+
};
|
|
228
|
+
try {
|
|
229
|
+
Sharp.versions = require('../vendor/versions.json');
|
|
230
|
+
} catch (err) {}
|
|
255
231
|
|
|
256
232
|
/**
|
|
257
233
|
* Export constructor.
|
package/lib/input.js
CHANGED
|
@@ -177,12 +177,15 @@ function clone () {
|
|
|
177
177
|
* A Promises/A+ promise is returned when `callback` is not provided.
|
|
178
178
|
*
|
|
179
179
|
* - `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
|
|
180
|
+
* - `size`: Total size of image in bytes, for Stream and Buffer input only
|
|
180
181
|
* - `width`: Number of pixels wide (EXIF orientation is not taken into consideration)
|
|
181
182
|
* - `height`: Number of pixels high (EXIF orientation is not taken into consideration)
|
|
182
|
-
* - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/
|
|
183
|
+
* - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L636)
|
|
183
184
|
* - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
|
|
184
|
-
* - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://github.com/
|
|
185
|
+
* - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672)
|
|
185
186
|
* - `density`: Number of pixels per inch (DPI), if present
|
|
187
|
+
* - `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
|
|
188
|
+
* - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
|
|
186
189
|
* - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
|
187
190
|
* - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
|
188
191
|
* - `orientation`: Number value of the EXIF Orientation header, if present
|
package/lib/libvips.js
CHANGED
|
@@ -44,10 +44,16 @@ const globalLibvipsVersion = function () {
|
|
|
44
44
|
|
|
45
45
|
const hasVendoredLibvips = function () {
|
|
46
46
|
const currentPlatformId = platform();
|
|
47
|
+
const vendorPath = path.join(__dirname, '..', 'vendor');
|
|
48
|
+
let vendorVersionId;
|
|
47
49
|
let vendorPlatformId;
|
|
48
50
|
try {
|
|
49
|
-
|
|
51
|
+
vendorVersionId = require(path.join(vendorPath, 'versions.json')).vips;
|
|
52
|
+
vendorPlatformId = require(path.join(vendorPath, 'platform.json'));
|
|
50
53
|
} catch (err) {}
|
|
54
|
+
if (vendorVersionId && vendorVersionId !== minimumLibvipsVersion) {
|
|
55
|
+
throw new Error(`Found vendored libvips v${vendorVersionId} but require v${minimumLibvipsVersion}. Please remove the 'node_modules/sharp/vendor' directory and run 'npm install'.`);
|
|
56
|
+
}
|
|
51
57
|
if (vendorPlatformId) {
|
|
52
58
|
if (currentPlatformId === vendorPlatformId) {
|
|
53
59
|
return true;
|
package/lib/operation.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const color = require('color');
|
|
3
4
|
const is = require('./is');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Rotate the output image by either an explicit angle
|
|
7
8
|
* or auto-orient based on the EXIF `Orientation` tag.
|
|
8
9
|
*
|
|
9
|
-
* If an angle is provided, it is converted to a valid
|
|
10
|
+
* If an angle is provided, it is converted to a valid positive degree rotation.
|
|
10
11
|
* For example, `-450` will produce a 270deg rotation.
|
|
11
12
|
*
|
|
13
|
+
* When rotating by an angle other than a multiple of 90,
|
|
14
|
+
* the background colour can be provided with the `background` option.
|
|
15
|
+
*
|
|
12
16
|
* If no angle is provided, it is determined from the EXIF data.
|
|
13
17
|
* Mirroring is supported and may infer the use of a flip operation.
|
|
14
18
|
*
|
|
@@ -28,64 +32,30 @@ const is = require('./is');
|
|
|
28
32
|
* });
|
|
29
33
|
* readableStream.pipe(pipeline);
|
|
30
34
|
*
|
|
31
|
-
* @param {Number} [angle=auto] angle of rotation
|
|
35
|
+
* @param {Number} [angle=auto] angle of rotation.
|
|
36
|
+
* @param {Object} [options] - if present, is an Object with optional attributes.
|
|
37
|
+
* @param {String|Object} [options.background="#000000"] parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
|
32
38
|
* @returns {Sharp}
|
|
33
39
|
* @throws {Error} Invalid parameters
|
|
34
40
|
*/
|
|
35
|
-
function rotate (angle) {
|
|
41
|
+
function rotate (angle, options) {
|
|
36
42
|
if (!is.defined(angle)) {
|
|
37
43
|
this.options.useExifOrientation = true;
|
|
38
44
|
} else if (is.integer(angle) && !(angle % 90)) {
|
|
39
45
|
this.options.angle = angle;
|
|
40
|
-
} else {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
* - Use `extract` after `resize` for post-resize extraction.
|
|
51
|
-
* - Use `extract` before and after for both.
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
* sharp(input)
|
|
55
|
-
* .extract({ left: left, top: top, width: width, height: height })
|
|
56
|
-
* .toFile(output, function(err) {
|
|
57
|
-
* // Extract a region of the input image, saving in the same format.
|
|
58
|
-
* });
|
|
59
|
-
* @example
|
|
60
|
-
* sharp(input)
|
|
61
|
-
* .extract({ left: leftOffsetPre, top: topOffsetPre, width: widthPre, height: heightPre })
|
|
62
|
-
* .resize(width, height)
|
|
63
|
-
* .extract({ left: leftOffsetPost, top: topOffsetPost, width: widthPost, height: heightPost })
|
|
64
|
-
* .toFile(output, function(err) {
|
|
65
|
-
* // Extract a region, resize, then extract from the resized image
|
|
66
|
-
* });
|
|
67
|
-
*
|
|
68
|
-
* @param {Object} options
|
|
69
|
-
* @param {Number} options.left - zero-indexed offset from left edge
|
|
70
|
-
* @param {Number} options.top - zero-indexed offset from top edge
|
|
71
|
-
* @param {Number} options.width - dimension of extracted image
|
|
72
|
-
* @param {Number} options.height - dimension of extracted image
|
|
73
|
-
* @returns {Sharp}
|
|
74
|
-
* @throws {Error} Invalid parameters
|
|
75
|
-
*/
|
|
76
|
-
function extract (options) {
|
|
77
|
-
const suffix = this.options.width === -1 && this.options.height === -1 ? 'Pre' : 'Post';
|
|
78
|
-
['left', 'top', 'width', 'height'].forEach(function (name) {
|
|
79
|
-
const value = options[name];
|
|
80
|
-
if (is.integer(value) && value >= 0) {
|
|
81
|
-
this.options[name + (name === 'left' || name === 'top' ? 'Offset' : '') + suffix] = value;
|
|
82
|
-
} else {
|
|
83
|
-
throw new Error('Non-integer value for ' + name + ' of ' + value);
|
|
46
|
+
} else if (is.number(angle)) {
|
|
47
|
+
this.options.rotationAngle = angle;
|
|
48
|
+
if (is.object(options) && options.background) {
|
|
49
|
+
const backgroundColour = color(options.background);
|
|
50
|
+
this.options.rotationBackground = [
|
|
51
|
+
backgroundColour.red(),
|
|
52
|
+
backgroundColour.green(),
|
|
53
|
+
backgroundColour.blue(),
|
|
54
|
+
Math.round(backgroundColour.alpha() * 255)
|
|
55
|
+
];
|
|
84
56
|
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (suffix === 'Pre' && ((this.options.angle % 360) !== 0 || this.options.useExifOrientation === true)) {
|
|
88
|
-
this.options.rotateBeforePreExtract = true;
|
|
57
|
+
} else {
|
|
58
|
+
throw new Error('Unsupported angle: must be a number.');
|
|
89
59
|
}
|
|
90
60
|
return this;
|
|
91
61
|
}
|
|
@@ -201,72 +171,14 @@ function blur (sigma) {
|
|
|
201
171
|
}
|
|
202
172
|
|
|
203
173
|
/**
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
* @example
|
|
208
|
-
* // Resize to 140 pixels wide, then add 10 transparent pixels
|
|
209
|
-
* // to the top, left and right edges and 20 to the bottom edge
|
|
210
|
-
* sharp(input)
|
|
211
|
-
* .resize(140)
|
|
212
|
-
* .background({r: 0, g: 0, b: 0, alpha: 0})
|
|
213
|
-
* .extend({top: 10, bottom: 20, left: 10, right: 10})
|
|
214
|
-
* ...
|
|
215
|
-
*
|
|
216
|
-
* @param {(Number|Object)} extend - single pixel count to add to all edges or an Object with per-edge counts
|
|
217
|
-
* @param {Number} [extend.top]
|
|
218
|
-
* @param {Number} [extend.left]
|
|
219
|
-
* @param {Number} [extend.bottom]
|
|
220
|
-
* @param {Number} [extend.right]
|
|
221
|
-
* @returns {Sharp}
|
|
222
|
-
* @throws {Error} Invalid parameters
|
|
223
|
-
*/
|
|
224
|
-
function extend (extend) {
|
|
225
|
-
if (is.integer(extend) && extend > 0) {
|
|
226
|
-
this.options.extendTop = extend;
|
|
227
|
-
this.options.extendBottom = extend;
|
|
228
|
-
this.options.extendLeft = extend;
|
|
229
|
-
this.options.extendRight = extend;
|
|
230
|
-
} else if (
|
|
231
|
-
is.object(extend) &&
|
|
232
|
-
is.integer(extend.top) && extend.top >= 0 &&
|
|
233
|
-
is.integer(extend.bottom) && extend.bottom >= 0 &&
|
|
234
|
-
is.integer(extend.left) && extend.left >= 0 &&
|
|
235
|
-
is.integer(extend.right) && extend.right >= 0
|
|
236
|
-
) {
|
|
237
|
-
this.options.extendTop = extend.top;
|
|
238
|
-
this.options.extendBottom = extend.bottom;
|
|
239
|
-
this.options.extendLeft = extend.left;
|
|
240
|
-
this.options.extendRight = extend.right;
|
|
241
|
-
} else {
|
|
242
|
-
throw new Error('Invalid edge extension ' + extend);
|
|
243
|
-
}
|
|
244
|
-
return this;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Merge alpha transparency channel, if any, with `background`.
|
|
249
|
-
* @param {Boolean} [flatten=true]
|
|
250
|
-
* @returns {Sharp}
|
|
251
|
-
*/
|
|
252
|
-
function flatten (flatten) {
|
|
253
|
-
this.options.flatten = is.bool(flatten) ? flatten : true;
|
|
254
|
-
return this;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel.
|
|
259
|
-
* @param {Number} [tolerance=10] value between 1 and 99 representing the percentage similarity.
|
|
174
|
+
* Merge alpha transparency channel, if any, with a background.
|
|
175
|
+
* @param {String|Object} [options.background={r: 0, g: 0, b: 0}] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black.
|
|
260
176
|
* @returns {Sharp}
|
|
261
|
-
* @throws {Error} Invalid parameters
|
|
262
177
|
*/
|
|
263
|
-
function
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
this.options.trimTolerance = tolerance;
|
|
268
|
-
} else {
|
|
269
|
-
throw new Error('Invalid trim tolerance (1 to 99) ' + tolerance);
|
|
178
|
+
function flatten (options) {
|
|
179
|
+
this.options.flatten = is.bool(options) ? options : true;
|
|
180
|
+
if (is.object(options)) {
|
|
181
|
+
this._setColourOption('flattenBackground', options.background);
|
|
270
182
|
}
|
|
271
183
|
return this;
|
|
272
184
|
}
|
|
@@ -460,15 +372,12 @@ function linear (a, b) {
|
|
|
460
372
|
module.exports = function (Sharp) {
|
|
461
373
|
[
|
|
462
374
|
rotate,
|
|
463
|
-
extract,
|
|
464
375
|
flip,
|
|
465
376
|
flop,
|
|
466
377
|
sharpen,
|
|
467
378
|
median,
|
|
468
379
|
blur,
|
|
469
|
-
extend,
|
|
470
380
|
flatten,
|
|
471
|
-
trim,
|
|
472
381
|
gamma,
|
|
473
382
|
negate,
|
|
474
383
|
normalise,
|
package/lib/platform.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const detectLibc = require('detect-libc');
|
|
4
|
+
|
|
3
5
|
module.exports = function () {
|
|
4
6
|
const arch = process.env.npm_config_arch || process.arch;
|
|
5
7
|
const platform = process.env.npm_config_platform || process.platform;
|
|
8
|
+
const libc = (platform === 'linux' && detectLibc.isNonGlibcLinux) ? detectLibc.family : '';
|
|
6
9
|
|
|
7
|
-
const platformId = [platform];
|
|
10
|
+
const platformId = [`${platform}${libc}`];
|
|
8
11
|
if (arch === 'arm' || arch === 'armhf' || arch === 'arm64') {
|
|
9
12
|
const armVersion = (arch === 'arm64') ? '8' : process.env.npm_config_armv || process.config.variables.arm_version || '6';
|
|
10
13
|
platformId.push(`armv${armVersion}`);
|