sharp 0.25.4 → 0.26.3
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/binding.gyp +54 -67
- package/install/dll-copy.js +3 -1
- package/install/libvips.js +28 -13
- package/lib/constructor.js +16 -2
- package/lib/input.js +15 -6
- package/lib/libvips.js +1 -7
- package/lib/operation.js +99 -0
- package/lib/output.js +96 -7
- package/lib/platform.js +2 -1
- package/lib/resize.js +2 -1
- package/lib/utility.js +22 -1
- package/package.json +22 -16
- package/src/common.cc +122 -57
- package/src/common.h +23 -3
- package/src/libvips/cplusplus/VImage.cpp +451 -450
- package/src/libvips/cplusplus/vips-operators.cpp +117 -1
- package/src/metadata.cc +1 -1
- package/src/operations.cc +0 -23
- package/src/operations.h +0 -10
- package/src/pipeline.cc +100 -16
- package/src/pipeline.h +24 -2
- package/src/stats.cc +25 -6
- package/src/stats.h +7 -1
package/binding.gyp
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
+
'variables': {
|
|
3
|
+
'vips_version': '<!(node -p "require(\'./lib/libvips\').minimumLibvipsVersion")',
|
|
4
|
+
'sharp_vendor_dir': '<(module_root_dir)/vendor/<(vips_version)'
|
|
5
|
+
},
|
|
2
6
|
'targets': [{
|
|
3
7
|
'target_name': 'libvips-cpp',
|
|
4
8
|
'conditions': [
|
|
@@ -16,15 +20,18 @@
|
|
|
16
20
|
'src/libvips/cplusplus/VImage.cpp'
|
|
17
21
|
],
|
|
18
22
|
'include_dirs': [
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
],
|
|
23
|
-
'libraries': [
|
|
24
|
-
'../vendor/lib/libvips.lib',
|
|
25
|
-
'../vendor/lib/libglib-2.0.lib',
|
|
26
|
-
'../vendor/lib/libgobject-2.0.lib'
|
|
23
|
+
'<(sharp_vendor_dir)/include',
|
|
24
|
+
'<(sharp_vendor_dir)/include/glib-2.0',
|
|
25
|
+
'<(sharp_vendor_dir)/lib/glib-2.0/include'
|
|
27
26
|
],
|
|
27
|
+
'link_settings': {
|
|
28
|
+
'library_dirs': ['<(sharp_vendor_dir)/lib'],
|
|
29
|
+
'libraries': [
|
|
30
|
+
'libvips.lib',
|
|
31
|
+
'libglib-2.0.lib',
|
|
32
|
+
'libgobject-2.0.lib'
|
|
33
|
+
],
|
|
34
|
+
},
|
|
28
35
|
'configurations': {
|
|
29
36
|
'Release': {
|
|
30
37
|
'msvs_settings': {
|
|
@@ -70,8 +77,8 @@
|
|
|
70
77
|
'runtime_link%': 'shared',
|
|
71
78
|
'conditions': [
|
|
72
79
|
['OS != "win"', {
|
|
73
|
-
'pkg_config_path': '<!(node -
|
|
74
|
-
'use_global_libvips': '<!(node -
|
|
80
|
+
'pkg_config_path': '<!(node -p "require(\'./lib/libvips\').pkgConfigPath()")',
|
|
81
|
+
'use_global_libvips': '<!(node -p "Boolean(require(\'./lib/libvips\').useGlobalLibvips()).toString()")'
|
|
75
82
|
}, {
|
|
76
83
|
'pkg_config_path': '',
|
|
77
84
|
'use_global_libvips': ''
|
|
@@ -88,7 +95,7 @@
|
|
|
88
95
|
'src/sharp.cc'
|
|
89
96
|
],
|
|
90
97
|
'include_dirs': [
|
|
91
|
-
'
|
|
98
|
+
'<!(node -p "require(\'node-addon-api\').include_dir")',
|
|
92
99
|
],
|
|
93
100
|
'conditions': [
|
|
94
101
|
['use_global_libvips == "true"', {
|
|
@@ -110,9 +117,9 @@
|
|
|
110
117
|
}, {
|
|
111
118
|
# Use pre-built libvips stored locally within node_modules
|
|
112
119
|
'include_dirs': [
|
|
113
|
-
'
|
|
114
|
-
'
|
|
115
|
-
'
|
|
120
|
+
'<(sharp_vendor_dir)/include',
|
|
121
|
+
'<(sharp_vendor_dir)/include/glib-2.0',
|
|
122
|
+
'<(sharp_vendor_dir)/lib/glib-2.0/include'
|
|
116
123
|
],
|
|
117
124
|
'conditions': [
|
|
118
125
|
['OS == "win"', {
|
|
@@ -120,64 +127,45 @@
|
|
|
120
127
|
'_ALLOW_KEYWORD_MACROS',
|
|
121
128
|
'_FILE_OFFSET_BITS=64'
|
|
122
129
|
],
|
|
123
|
-
'
|
|
124
|
-
'
|
|
125
|
-
'
|
|
126
|
-
|
|
127
|
-
|
|
130
|
+
'link_settings': {
|
|
131
|
+
'library_dirs': ['<(sharp_vendor_dir)/lib'],
|
|
132
|
+
'libraries': [
|
|
133
|
+
'libvips.lib',
|
|
134
|
+
'libglib-2.0.lib',
|
|
135
|
+
'libgobject-2.0.lib'
|
|
136
|
+
]
|
|
137
|
+
}
|
|
128
138
|
}],
|
|
129
139
|
['OS == "mac"', {
|
|
130
|
-
'
|
|
131
|
-
'
|
|
132
|
-
'
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
'link_settings': {
|
|
141
|
+
'library_dirs': ['<(sharp_vendor_dir)/lib'],
|
|
142
|
+
'libraries': [
|
|
143
|
+
'libvips-cpp.42.dylib',
|
|
144
|
+
'libvips.42.dylib'
|
|
145
|
+
]
|
|
146
|
+
},
|
|
147
|
+
'xcode_settings': {
|
|
148
|
+
'OTHER_LDFLAGS': [
|
|
149
|
+
# Ensure runtime linking is relative to sharp.node
|
|
150
|
+
'-Wl,-rpath,\'@loader_path/../../vendor/<(vips_version)/lib\''
|
|
151
|
+
]
|
|
152
|
+
}
|
|
138
153
|
}],
|
|
139
154
|
['OS == "linux"', {
|
|
140
155
|
'defines': [
|
|
141
156
|
'_GLIBCXX_USE_CXX11_ABI=0'
|
|
142
157
|
],
|
|
143
|
-
'
|
|
144
|
-
'
|
|
145
|
-
'
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
'
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
'../vendor/lib/libfreetype.so',
|
|
155
|
-
'../vendor/lib/libfribidi.so',
|
|
156
|
-
'../vendor/lib/libgdk_pixbuf-2.0.so',
|
|
157
|
-
'../vendor/lib/libgif.so',
|
|
158
|
-
'../vendor/lib/libgio-2.0.so',
|
|
159
|
-
'../vendor/lib/libgmodule-2.0.so',
|
|
160
|
-
'../vendor/lib/libgsf-1.so',
|
|
161
|
-
'../vendor/lib/libgthread-2.0.so',
|
|
162
|
-
'../vendor/lib/libharfbuzz.so',
|
|
163
|
-
'../vendor/lib/libjpeg.so',
|
|
164
|
-
'../vendor/lib/liblcms2.so',
|
|
165
|
-
'../vendor/lib/liborc-0.4.so',
|
|
166
|
-
'../vendor/lib/libpango-1.0.so',
|
|
167
|
-
'../vendor/lib/libpangocairo-1.0.so',
|
|
168
|
-
'../vendor/lib/libpangoft2-1.0.so',
|
|
169
|
-
'../vendor/lib/libpixman-1.so',
|
|
170
|
-
'../vendor/lib/libpng.so',
|
|
171
|
-
'../vendor/lib/librsvg-2.so',
|
|
172
|
-
'../vendor/lib/libtiff.so',
|
|
173
|
-
'../vendor/lib/libwebp.so',
|
|
174
|
-
'../vendor/lib/libwebpdemux.so',
|
|
175
|
-
'../vendor/lib/libwebpmux.so',
|
|
176
|
-
'../vendor/lib/libxml2.so',
|
|
177
|
-
'../vendor/lib/libz.so',
|
|
178
|
-
# Ensure runtime linking is relative to sharp.node
|
|
179
|
-
'-Wl,-s -Wl,--disable-new-dtags -Wl,-rpath=\'$${ORIGIN}/../../vendor/lib\''
|
|
180
|
-
]
|
|
158
|
+
'link_settings': {
|
|
159
|
+
'library_dirs': ['<(sharp_vendor_dir)/lib'],
|
|
160
|
+
'libraries': [
|
|
161
|
+
'-l:libvips-cpp.so.42',
|
|
162
|
+
'-l:libvips.so.42'
|
|
163
|
+
],
|
|
164
|
+
'ldflags': [
|
|
165
|
+
# Ensure runtime linking is relative to sharp.node
|
|
166
|
+
'-Wl,-s -Wl,--disable-new-dtags -Wl,-rpath=\'$$ORIGIN/../../vendor/<(vips_version)/lib\''
|
|
167
|
+
]
|
|
168
|
+
}
|
|
181
169
|
}]
|
|
182
170
|
]
|
|
183
171
|
}]
|
|
@@ -190,8 +178,7 @@
|
|
|
190
178
|
],
|
|
191
179
|
'xcode_settings': {
|
|
192
180
|
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
|
|
193
|
-
'
|
|
194
|
-
'MACOSX_DEPLOYMENT_TARGET': '10.7',
|
|
181
|
+
'MACOSX_DEPLOYMENT_TARGET': '10.9',
|
|
195
182
|
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
|
|
196
183
|
'GCC_ENABLE_CPP_RTTI': 'YES',
|
|
197
184
|
'OTHER_CPLUSPLUSFLAGS': [
|
package/install/dll-copy.js
CHANGED
|
@@ -6,6 +6,8 @@ const path = require('path');
|
|
|
6
6
|
const libvips = require('../lib/libvips');
|
|
7
7
|
const npmLog = require('npmlog');
|
|
8
8
|
|
|
9
|
+
const minimumLibvipsVersion = libvips.minimumLibvipsVersion;
|
|
10
|
+
|
|
9
11
|
const platform = process.env.npm_config_platform || process.platform;
|
|
10
12
|
if (platform === 'win32') {
|
|
11
13
|
const buildDir = path.join(__dirname, '..', 'build');
|
|
@@ -15,7 +17,7 @@ if (platform === 'win32') {
|
|
|
15
17
|
libvips.mkdirSync(buildDir);
|
|
16
18
|
libvips.mkdirSync(buildReleaseDir);
|
|
17
19
|
} catch (err) {}
|
|
18
|
-
const vendorLibDir = path.join(__dirname, '..', 'vendor', 'lib');
|
|
20
|
+
const vendorLibDir = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, 'lib');
|
|
19
21
|
npmLog.info('sharp', `Copying DLLs from ${vendorLibDir} to ${buildReleaseDir}`);
|
|
20
22
|
try {
|
|
21
23
|
fs
|
package/install/libvips.js
CHANGED
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const path = require('path');
|
|
6
|
+
const stream = require('stream');
|
|
7
|
+
const zlib = require('zlib');
|
|
6
8
|
|
|
7
9
|
const detectLibc = require('detect-libc');
|
|
8
10
|
const npmLog = require('npmlog');
|
|
9
11
|
const semver = require('semver');
|
|
10
12
|
const simpleGet = require('simple-get');
|
|
11
|
-
const
|
|
13
|
+
const tarFs = require('tar-fs');
|
|
12
14
|
|
|
13
15
|
const agent = require('../lib/agent');
|
|
14
16
|
const libvips = require('../lib/libvips');
|
|
@@ -23,6 +25,7 @@ const minimumGlibcVersionByArch = {
|
|
|
23
25
|
const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
|
|
24
26
|
const distHost = process.env.npm_config_sharp_libvips_binary_host || 'https://github.com/lovell/sharp-libvips/releases/download';
|
|
25
27
|
const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `${distHost}/v${minimumLibvipsVersionLabelled}/`;
|
|
28
|
+
const supportsBrotli = ('BrotliDecompress' in zlib);
|
|
26
29
|
|
|
27
30
|
const fail = function (err) {
|
|
28
31
|
npmLog.error('sharp', err.message);
|
|
@@ -37,22 +40,26 @@ const fail = function (err) {
|
|
|
37
40
|
const extractTarball = function (tarPath) {
|
|
38
41
|
const vendorPath = path.join(__dirname, '..', 'vendor');
|
|
39
42
|
libvips.mkdirSync(vendorPath);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
|
|
43
|
+
const versionedVendorPath = path.join(vendorPath, minimumLibvipsVersion);
|
|
44
|
+
libvips.mkdirSync(versionedVendorPath);
|
|
45
|
+
stream.pipeline(
|
|
46
|
+
fs.createReadStream(tarPath),
|
|
47
|
+
supportsBrotli ? new zlib.BrotliDecompress() : new zlib.Gunzip(),
|
|
48
|
+
tarFs.extract(versionedVendorPath),
|
|
49
|
+
function (err) {
|
|
50
|
+
if (err) {
|
|
51
|
+
if (/unexpected end of file/.test(err.message)) {
|
|
52
|
+
npmLog.error('sharp', `Please delete ${tarPath} as it is not a valid tarball`);
|
|
53
|
+
}
|
|
54
|
+
fail(err);
|
|
49
55
|
}
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
}
|
|
57
|
+
);
|
|
52
58
|
};
|
|
53
59
|
|
|
54
60
|
try {
|
|
55
61
|
const useGlobalLibvips = libvips.useGlobalLibvips();
|
|
62
|
+
|
|
56
63
|
if (useGlobalLibvips) {
|
|
57
64
|
const globalLibvipsVersion = libvips.globalLibvipsVersion();
|
|
58
65
|
npmLog.info('sharp', `Detected globally-installed libvips v${globalLibvipsVersion}`);
|
|
@@ -75,8 +82,16 @@ try {
|
|
|
75
82
|
throw new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
76
83
|
}
|
|
77
84
|
}
|
|
85
|
+
|
|
86
|
+
const supportedNodeVersion = process.env.npm_package_engines_node || require('../package.json').engines.node;
|
|
87
|
+
if (!semver.satisfies(process.versions.node, supportedNodeVersion)) {
|
|
88
|
+
throw new Error(`Expected Node.js version ${supportedNodeVersion} but found ${process.versions.node}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const extension = supportsBrotli ? 'br' : 'gz';
|
|
92
|
+
|
|
78
93
|
// Download to per-process temporary file
|
|
79
|
-
const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.
|
|
94
|
+
const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.' + extension;
|
|
80
95
|
const tarPathCache = path.join(libvips.cachePath(), tarFilename);
|
|
81
96
|
if (fs.existsSync(tarPathCache)) {
|
|
82
97
|
npmLog.info('sharp', `Using cached ${tarPathCache}`);
|
package/lib/constructor.js
CHANGED
|
@@ -86,6 +86,10 @@ const debuglog = util.debuglog('sharp');
|
|
|
86
86
|
* .toBuffer()
|
|
87
87
|
* .then( ... );
|
|
88
88
|
*
|
|
89
|
+
* @example
|
|
90
|
+
* // Convert an animated GIF to an animated WebP
|
|
91
|
+
* await sharp('in.gif', { animated: true }).toFile('out.webp');
|
|
92
|
+
*
|
|
89
93
|
* @param {(Buffer|string)} [input] - if present, can be
|
|
90
94
|
* a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
|
|
91
95
|
* a String containing the filesystem path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
|
|
@@ -98,10 +102,11 @@ const debuglog = util.debuglog('sharp');
|
|
|
98
102
|
* An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
|
|
99
103
|
* @param {boolean} [options.sequentialRead=false] - Set this to `true` to use sequential rather than random access where possible.
|
|
100
104
|
* This can reduce memory usage and might improve performance on some systems.
|
|
101
|
-
* @param {number} [options.density=72] - number representing the DPI for vector images.
|
|
105
|
+
* @param {number} [options.density=72] - number representing the DPI for vector images in the range 1 to 100000.
|
|
102
106
|
* @param {number} [options.pages=1] - number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages.
|
|
103
107
|
* @param {number} [options.page=0] - page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based.
|
|
104
108
|
* @param {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based.
|
|
109
|
+
* @param {boolean} [options.animated=false] - Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`).
|
|
105
110
|
* @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering.
|
|
106
111
|
* @param {number} [options.raw.width]
|
|
107
112
|
* @param {number} [options.raw.height]
|
|
@@ -150,6 +155,13 @@ const Sharp = function (input, options) {
|
|
|
150
155
|
extendRight: 0,
|
|
151
156
|
extendBackground: [0, 0, 0, 255],
|
|
152
157
|
withoutEnlargement: false,
|
|
158
|
+
affineMatrix: [],
|
|
159
|
+
affineBackground: [0, 0, 0, 255],
|
|
160
|
+
affineIdx: 0,
|
|
161
|
+
affineIdy: 0,
|
|
162
|
+
affineOdx: 0,
|
|
163
|
+
affineOdy: 0,
|
|
164
|
+
affineInterpolator: this.constructor.interpolators.bilinear,
|
|
153
165
|
kernel: 'lanczos3',
|
|
154
166
|
fastShrinkOnLoad: true,
|
|
155
167
|
// operations
|
|
@@ -187,6 +199,7 @@ const Sharp = function (input, options) {
|
|
|
187
199
|
streamOut: false,
|
|
188
200
|
withMetadata: false,
|
|
189
201
|
withMetadataOrientation: -1,
|
|
202
|
+
withMetadataIcc: '',
|
|
190
203
|
resolveWithObject: false,
|
|
191
204
|
// output format
|
|
192
205
|
jpegQuality: 80,
|
|
@@ -214,7 +227,7 @@ const Sharp = function (input, options) {
|
|
|
214
227
|
tiffCompression: 'jpeg',
|
|
215
228
|
tiffPredictor: 'horizontal',
|
|
216
229
|
tiffPyramid: false,
|
|
217
|
-
|
|
230
|
+
tiffBitdepth: 8,
|
|
218
231
|
tiffTile: false,
|
|
219
232
|
tiffTileHeight: 256,
|
|
220
233
|
tiffTileWidth: 256,
|
|
@@ -232,6 +245,7 @@ const Sharp = function (input, options) {
|
|
|
232
245
|
tileAngle: 0,
|
|
233
246
|
tileSkipBlanks: -1,
|
|
234
247
|
tileBackground: [255, 255, 255, 255],
|
|
248
|
+
tileCentre: false,
|
|
235
249
|
linearA: 1,
|
|
236
250
|
linearB: 0,
|
|
237
251
|
// Function to notify of libvips warnings
|
package/lib/input.js
CHANGED
|
@@ -9,9 +9,9 @@ const sharp = require('../build/Release/sharp.node');
|
|
|
9
9
|
* @private
|
|
10
10
|
*/
|
|
11
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 }
|
|
12
|
+
const { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages } = obj;
|
|
13
|
+
return [raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages].some(is.defined)
|
|
14
|
+
? { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages }
|
|
15
15
|
: undefined;
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -57,10 +57,10 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
57
57
|
}
|
|
58
58
|
// Density
|
|
59
59
|
if (is.defined(inputOptions.density)) {
|
|
60
|
-
if (is.inRange(inputOptions.density, 1,
|
|
60
|
+
if (is.inRange(inputOptions.density, 1, 100000)) {
|
|
61
61
|
inputDescriptor.density = inputOptions.density;
|
|
62
62
|
} else {
|
|
63
|
-
throw is.invalidParameterError('density', 'number between 1 and
|
|
63
|
+
throw is.invalidParameterError('density', 'number between 1 and 100000', inputOptions.density);
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
// limitInputPixels
|
|
@@ -99,6 +99,13 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
// Multi-page input (GIF, TIFF, PDF)
|
|
102
|
+
if (is.defined(inputOptions.animated)) {
|
|
103
|
+
if (is.bool(inputOptions.animated)) {
|
|
104
|
+
inputDescriptor.pages = inputOptions.animated ? -1 : 1;
|
|
105
|
+
} else {
|
|
106
|
+
throw is.invalidParameterError('animated', 'boolean', inputOptions.animated);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
102
109
|
if (is.defined(inputOptions.pages)) {
|
|
103
110
|
if (is.integer(inputOptions.pages) && is.inRange(inputOptions.pages, -1, 100000)) {
|
|
104
111
|
inputDescriptor.pages = inputOptions.pages;
|
|
@@ -300,6 +307,7 @@ function metadata (callback) {
|
|
|
300
307
|
* - `isOpaque`: Is the image fully opaque? Will be `true` if the image has no alpha channel or if every pixel is fully opaque.
|
|
301
308
|
* - `entropy`: Histogram-based estimation of greyscale entropy, discarding alpha channel if any (experimental)
|
|
302
309
|
* - `sharpness`: Estimation of greyscale sharpness based on the standard deviation of a Laplacian convolution, discarding alpha channel if any (experimental)
|
|
310
|
+
* - `dominant`: Object containing most dominant sRGB colour based on a 4096-bin 3D histogram (experimental)
|
|
303
311
|
*
|
|
304
312
|
* @example
|
|
305
313
|
* const image = sharp(inputJpg);
|
|
@@ -310,7 +318,8 @@ function metadata (callback) {
|
|
|
310
318
|
* });
|
|
311
319
|
*
|
|
312
320
|
* @example
|
|
313
|
-
* const { entropy, sharpness } = await sharp(input).stats();
|
|
321
|
+
* const { entropy, sharpness, dominant } = await sharp(input).stats();
|
|
322
|
+
* const { r, g, b } = dominant;
|
|
314
323
|
*
|
|
315
324
|
* @param {Function} [callback] - called with the arguments `(err, stats)`
|
|
316
325
|
* @returns {Promise<Object>}
|
package/lib/libvips.js
CHANGED
|
@@ -48,17 +48,11 @@ const globalLibvipsVersion = function () {
|
|
|
48
48
|
|
|
49
49
|
const hasVendoredLibvips = function () {
|
|
50
50
|
const currentPlatformId = platform();
|
|
51
|
-
const vendorPath = path.join(__dirname, '..', 'vendor');
|
|
52
|
-
let vendorVersionId;
|
|
51
|
+
const vendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion);
|
|
53
52
|
let vendorPlatformId;
|
|
54
53
|
try {
|
|
55
|
-
vendorVersionId = require(path.join(vendorPath, 'versions.json')).vips;
|
|
56
54
|
vendorPlatformId = require(path.join(vendorPath, 'platform.json'));
|
|
57
55
|
} catch (err) {}
|
|
58
|
-
/* istanbul ignore if */
|
|
59
|
-
if (vendorVersionId && vendorVersionId !== minimumLibvipsVersion) {
|
|
60
|
-
throw new Error(`Found vendored libvips v${vendorVersionId} but require v${minimumLibvipsVersion}. Please remove the 'node_modules/sharp/vendor' directory and run 'npm install'.`);
|
|
61
|
-
}
|
|
62
56
|
/* istanbul ignore else */
|
|
63
57
|
if (vendorPlatformId) {
|
|
64
58
|
/* istanbul ignore else */
|
package/lib/operation.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { flatten: flattenArray } = require('array-flatten');
|
|
3
4
|
const color = require('color');
|
|
4
5
|
const is = require('./is');
|
|
5
6
|
|
|
@@ -82,6 +83,103 @@ function flop (flop) {
|
|
|
82
83
|
return this;
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Perform an affine transform on an image. This operation will always occur after resizing, extraction and rotation, if any.
|
|
88
|
+
*
|
|
89
|
+
* You must provide an array of length 4 or a 2x2 affine transformation matrix.
|
|
90
|
+
* By default, new pixels are filled with a black background. You can provide a background color with the `background` option.
|
|
91
|
+
* A particular interpolator may also be specified. Set the `interpolator` option to an attribute of the `sharp.interpolator` Object e.g. `sharp.interpolator.nohalo`.
|
|
92
|
+
*
|
|
93
|
+
* In the case of a 2x2 matrix, the transform is:
|
|
94
|
+
* - X = `matrix[0, 0]` \* (x + `idx`) + `matrix[0, 1]` \* (y + `idy`) + `odx`
|
|
95
|
+
* - Y = `matrix[1, 0]` \* (x + `idx`) + `matrix[1, 1]` \* (y + `idy`) + `ody`
|
|
96
|
+
*
|
|
97
|
+
* where:
|
|
98
|
+
* - x and y are the coordinates in input image.
|
|
99
|
+
* - X and Y are the coordinates in output image.
|
|
100
|
+
* - (0,0) is the upper left corner.
|
|
101
|
+
*
|
|
102
|
+
* @since 0.27.0
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* const pipeline = sharp()
|
|
106
|
+
* .affine([[1, 0.3], [0.1, 0.7]], {
|
|
107
|
+
* background: 'white',
|
|
108
|
+
* interpolate: sharp.interpolators.nohalo
|
|
109
|
+
* })
|
|
110
|
+
* .toBuffer((err, outputBuffer, info) => {
|
|
111
|
+
* // outputBuffer contains the transformed image
|
|
112
|
+
* // info.width and info.height contain the new dimensions
|
|
113
|
+
* });
|
|
114
|
+
*
|
|
115
|
+
* inputStream
|
|
116
|
+
* .pipe(pipeline);
|
|
117
|
+
*
|
|
118
|
+
* @param {Array<Array<number>>|Array<number>} matrix - affine transformation matrix
|
|
119
|
+
* @param {Object} [options] - if present, is an Object with optional attributes.
|
|
120
|
+
* @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.
|
|
121
|
+
* @param {Number} [options.idx=0] - input horizontal offset
|
|
122
|
+
* @param {Number} [options.idy=0] - input vertical offset
|
|
123
|
+
* @param {Number} [options.odx=0] - output horizontal offset
|
|
124
|
+
* @param {Number} [options.ody=0] - output vertical offset
|
|
125
|
+
* @param {String} [options.interpolator=sharp.interpolators.bicubic] - interpolator
|
|
126
|
+
* @returns {Sharp}
|
|
127
|
+
* @throws {Error} Invalid parameters
|
|
128
|
+
*/
|
|
129
|
+
function affine (matrix, options) {
|
|
130
|
+
const flatMatrix = flattenArray(matrix);
|
|
131
|
+
if (flatMatrix.length === 4 && flatMatrix.every(is.number)) {
|
|
132
|
+
this.options.affineMatrix = flatMatrix;
|
|
133
|
+
} else {
|
|
134
|
+
throw is.invalidParameterError('matrix', '1x4 or 2x2 array', matrix);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (is.defined(options)) {
|
|
138
|
+
if (is.object(options)) {
|
|
139
|
+
this._setBackgroundColourOption('affineBackground', options.background);
|
|
140
|
+
if (is.defined(options.idx)) {
|
|
141
|
+
if (is.number(options.idx)) {
|
|
142
|
+
this.options.affineIdx = options.idx;
|
|
143
|
+
} else {
|
|
144
|
+
throw is.invalidParameterError('options.idx', 'number', options.idx);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (is.defined(options.idy)) {
|
|
148
|
+
if (is.number(options.idy)) {
|
|
149
|
+
this.options.affineIdy = options.idy;
|
|
150
|
+
} else {
|
|
151
|
+
throw is.invalidParameterError('options.idy', 'number', options.idy);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (is.defined(options.odx)) {
|
|
155
|
+
if (is.number(options.odx)) {
|
|
156
|
+
this.options.affineOdx = options.odx;
|
|
157
|
+
} else {
|
|
158
|
+
throw is.invalidParameterError('options.odx', 'number', options.odx);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (is.defined(options.ody)) {
|
|
162
|
+
if (is.number(options.ody)) {
|
|
163
|
+
this.options.affineOdy = options.ody;
|
|
164
|
+
} else {
|
|
165
|
+
throw is.invalidParameterError('options.ody', 'number', options.ody);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (is.defined(options.interpolator)) {
|
|
169
|
+
if (is.inArray(options.interpolator, Object.values(this.constructor.interpolators))) {
|
|
170
|
+
this.options.affineInterpolator = options.interpolator;
|
|
171
|
+
} else {
|
|
172
|
+
throw is.invalidParameterError('options.interpolator', 'valid interpolator name', options.interpolator);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
throw is.invalidParameterError('options', 'object', options);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return this;
|
|
181
|
+
}
|
|
182
|
+
|
|
85
183
|
/**
|
|
86
184
|
* Sharpen the image.
|
|
87
185
|
* When used without parameters, performs a fast, mild sharpen of the output image.
|
|
@@ -482,6 +580,7 @@ module.exports = function (Sharp) {
|
|
|
482
580
|
rotate,
|
|
483
581
|
flip,
|
|
484
582
|
flop,
|
|
583
|
+
affine,
|
|
485
584
|
sharpen,
|
|
486
585
|
median,
|
|
487
586
|
blur,
|