sharp 0.25.3 → 0.26.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/README.md CHANGED
@@ -16,7 +16,7 @@ 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 v10+
19
+ Most modern macOS, Windows and Linux systems running Node.js v10.16.0+
20
20
  do not require any additional install or runtime dependencies.
21
21
 
22
22
  ## Examples
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,23 +20,38 @@
16
20
  'src/libvips/cplusplus/VImage.cpp'
17
21
  ],
18
22
  'include_dirs': [
19
- 'vendor/include',
20
- 'vendor/include/glib-2.0',
21
- 'vendor/lib/glib-2.0/include'
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': {
31
38
  'VCCLCompilerTool': {
32
- 'ExceptionHandling': 1
39
+ 'ExceptionHandling': 1,
40
+ 'WholeProgramOptimization': 'true'
41
+ },
42
+ 'VCLibrarianTool': {
43
+ 'AdditionalOptions': [
44
+ '/LTCG:INCREMENTAL'
45
+ ]
33
46
  },
34
47
  'VCLinkerTool': {
35
- 'ImageHasSafeExceptionHandlers': 'false'
48
+ 'ImageHasSafeExceptionHandlers': 'false',
49
+ 'OptimizeReferences': 2,
50
+ 'EnableCOMDATFolding': 2,
51
+ 'LinkIncremental': 1,
52
+ 'AdditionalOptions': [
53
+ '/LTCG:INCREMENTAL'
54
+ ]
36
55
  }
37
56
  },
38
57
  'msvs_disabled_warnings': [
@@ -58,8 +77,8 @@
58
77
  'runtime_link%': 'shared',
59
78
  'conditions': [
60
79
  ['OS != "win"', {
61
- 'pkg_config_path': '<!(node -e "console.log(require(\'./lib/libvips\').pkgConfigPath())")',
62
- 'use_global_libvips': '<!(node -e "console.log(Boolean(require(\'./lib/libvips\').useGlobalLibvips()).toString())")'
80
+ 'pkg_config_path': '<!(node -p "require(\'./lib/libvips\').pkgConfigPath()")',
81
+ 'use_global_libvips': '<!(node -p "Boolean(require(\'./lib/libvips\').useGlobalLibvips()).toString()")'
63
82
  }, {
64
83
  'pkg_config_path': '',
65
84
  'use_global_libvips': ''
@@ -76,7 +95,7 @@
76
95
  'src/sharp.cc'
77
96
  ],
78
97
  'include_dirs': [
79
- '<!@(node -p "require(\'node-addon-api\').include")',
98
+ '<!(node -p "require(\'node-addon-api\').include_dir")',
80
99
  ],
81
100
  'conditions': [
82
101
  ['use_global_libvips == "true"', {
@@ -98,9 +117,9 @@
98
117
  }, {
99
118
  # Use pre-built libvips stored locally within node_modules
100
119
  'include_dirs': [
101
- 'vendor/include',
102
- 'vendor/include/glib-2.0',
103
- 'vendor/lib/glib-2.0/include'
120
+ '<(sharp_vendor_dir)/include',
121
+ '<(sharp_vendor_dir)/include/glib-2.0',
122
+ '<(sharp_vendor_dir)/lib/glib-2.0/include'
104
123
  ],
105
124
  'conditions': [
106
125
  ['OS == "win"', {
@@ -108,64 +127,45 @@
108
127
  '_ALLOW_KEYWORD_MACROS',
109
128
  '_FILE_OFFSET_BITS=64'
110
129
  ],
111
- 'libraries': [
112
- '../vendor/lib/libvips.lib',
113
- '../vendor/lib/libglib-2.0.lib',
114
- '../vendor/lib/libgobject-2.0.lib'
115
- ]
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
+ }
116
138
  }],
117
139
  ['OS == "mac"', {
118
- 'libraries': [
119
- '../vendor/lib/libvips-cpp.42.dylib',
120
- '../vendor/lib/libvips.42.dylib',
121
- '../vendor/lib/libglib-2.0.0.dylib',
122
- '../vendor/lib/libgobject-2.0.0.dylib',
123
- # Ensure runtime linking is relative to sharp.node
124
- '-rpath \'@loader_path/../../vendor/lib\''
125
- ]
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
+ }
126
153
  }],
127
154
  ['OS == "linux"', {
128
155
  'defines': [
129
156
  '_GLIBCXX_USE_CXX11_ABI=0'
130
157
  ],
131
- 'libraries': [
132
- '../vendor/lib/libvips-cpp.so',
133
- '../vendor/lib/libvips.so',
134
- '../vendor/lib/libglib-2.0.so',
135
- '../vendor/lib/libgobject-2.0.so',
136
- # Dependencies of dependencies, included for openSUSE support
137
- '../vendor/lib/libcairo.so',
138
- '../vendor/lib/libexif.so',
139
- '../vendor/lib/libexpat.so',
140
- '../vendor/lib/libffi.so',
141
- '../vendor/lib/libfontconfig.so',
142
- '../vendor/lib/libfreetype.so',
143
- '../vendor/lib/libfribidi.so',
144
- '../vendor/lib/libgdk_pixbuf-2.0.so',
145
- '../vendor/lib/libgif.so',
146
- '../vendor/lib/libgio-2.0.so',
147
- '../vendor/lib/libgmodule-2.0.so',
148
- '../vendor/lib/libgsf-1.so',
149
- '../vendor/lib/libgthread-2.0.so',
150
- '../vendor/lib/libharfbuzz.so',
151
- '../vendor/lib/libjpeg.so',
152
- '../vendor/lib/liblcms2.so',
153
- '../vendor/lib/liborc-0.4.so',
154
- '../vendor/lib/libpango-1.0.so',
155
- '../vendor/lib/libpangocairo-1.0.so',
156
- '../vendor/lib/libpangoft2-1.0.so',
157
- '../vendor/lib/libpixman-1.so',
158
- '../vendor/lib/libpng.so',
159
- '../vendor/lib/librsvg-2.so',
160
- '../vendor/lib/libtiff.so',
161
- '../vendor/lib/libwebp.so',
162
- '../vendor/lib/libwebpdemux.so',
163
- '../vendor/lib/libwebpmux.so',
164
- '../vendor/lib/libxml2.so',
165
- '../vendor/lib/libz.so',
166
- # Ensure runtime linking is relative to sharp.node
167
- '-Wl,--disable-new-dtags -Wl,-rpath=\'$${ORIGIN}/../../vendor/lib\''
168
- ]
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
+ }
169
169
  }]
170
170
  ]
171
171
  }]
@@ -178,8 +178,7 @@
178
178
  ],
179
179
  'xcode_settings': {
180
180
  'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
181
- 'CLANG_CXX_LIBRARY': 'libc++',
182
- 'MACOSX_DEPLOYMENT_TARGET': '10.7',
181
+ 'MACOSX_DEPLOYMENT_TARGET': '10.9',
183
182
  'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
184
183
  'GCC_ENABLE_CPP_RTTI': 'YES',
185
184
  'OTHER_CPLUSPLUSFLAGS': [
@@ -204,10 +203,22 @@
204
203
  ['OS == "win"', {
205
204
  'msvs_settings': {
206
205
  'VCCLCompilerTool': {
207
- 'ExceptionHandling': 1
206
+ 'ExceptionHandling': 1,
207
+ 'WholeProgramOptimization': 'true'
208
+ },
209
+ 'VCLibrarianTool': {
210
+ 'AdditionalOptions': [
211
+ '/LTCG:INCREMENTAL'
212
+ ]
208
213
  },
209
214
  'VCLinkerTool': {
210
- 'ImageHasSafeExceptionHandlers': 'false'
215
+ 'ImageHasSafeExceptionHandlers': 'false',
216
+ 'OptimizeReferences': 2,
217
+ 'EnableCOMDATFolding': 2,
218
+ 'LinkIncremental': 1,
219
+ 'AdditionalOptions': [
220
+ '/LTCG:INCREMENTAL'
221
+ ]
211
222
  }
212
223
  },
213
224
  'msvs_disabled_warnings': [
@@ -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
@@ -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 tar = require('tar');
13
+ const tarFs = require('tar-fs');
12
14
 
13
15
  const agent = require('../lib/agent');
14
16
  const libvips = require('../lib/libvips');
@@ -21,7 +23,8 @@ const minimumGlibcVersionByArch = {
21
23
  };
22
24
 
23
25
  const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
24
- const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `https://github.com/lovell/sharp-libvips/releases/download/v${minimumLibvipsVersionLabelled}/`;
26
+ const distHost = process.env.npm_config_sharp_libvips_binary_host || 'https://github.com/lovell/sharp-libvips/releases/download';
27
+ const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `${distHost}/v${minimumLibvipsVersionLabelled}/`;
25
28
 
26
29
  const fail = function (err) {
27
30
  npmLog.error('sharp', err.message);
@@ -36,18 +39,21 @@ const fail = function (err) {
36
39
  const extractTarball = function (tarPath) {
37
40
  const vendorPath = path.join(__dirname, '..', 'vendor');
38
41
  libvips.mkdirSync(vendorPath);
39
- tar
40
- .extract({
41
- file: tarPath,
42
- cwd: vendorPath,
43
- strict: true
44
- })
45
- .catch(function (err) {
46
- if (/unexpected end of file/.test(err.message)) {
47
- npmLog.error('sharp', `Please delete ${tarPath} as it is not a valid tarball`);
42
+ const versionedVendorPath = path.join(vendorPath, minimumLibvipsVersion);
43
+ libvips.mkdirSync(versionedVendorPath);
44
+ stream.pipeline(
45
+ fs.createReadStream(tarPath),
46
+ new zlib.BrotliDecompress(),
47
+ tarFs.extract(versionedVendorPath),
48
+ function (err) {
49
+ if (err) {
50
+ if (/unexpected end of file/.test(err.message)) {
51
+ npmLog.error('sharp', `Please delete ${tarPath} as it is not a valid tarball`);
52
+ }
53
+ fail(err);
48
54
  }
49
- fail(err);
50
- });
55
+ }
56
+ );
51
57
  };
52
58
 
53
59
  try {
@@ -74,8 +80,14 @@ try {
74
80
  throw new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
75
81
  }
76
82
  }
83
+
84
+ const supportedNodeVersion = process.env.npm_package_engines_node || require('../package.json').engines.node;
85
+ if (!semver.satisfies(process.versions.node, supportedNodeVersion)) {
86
+ throw new Error(`Expected Node.js version ${supportedNodeVersion} but found ${process.versions.node}`);
87
+ }
88
+
77
89
  // Download to per-process temporary file
78
- const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.gz';
90
+ const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.br';
79
91
  const tarPathCache = path.join(libvips.cachePath(), tarFilename);
80
92
  if (fs.existsSync(tarPathCache)) {
81
93
  npmLog.info('sharp', `Using cached ${tarPathCache}`);
package/lib/channel.js CHANGED
@@ -60,22 +60,19 @@ function ensureAlpha () {
60
60
  * // green.jpg is a greyscale image containing the green channel of the input
61
61
  * });
62
62
  *
63
- * @param {number|string} channel - zero-indexed band number to extract, or `red`, `green` or `blue` as alternative to `0`, `1` or `2` respectively.
63
+ * @param {number|string} channel - zero-indexed channel/band number to extract, or `red`, `green`, `blue` or `alpha`.
64
64
  * @returns {Sharp}
65
65
  * @throws {Error} Invalid channel
66
66
  */
67
67
  function extractChannel (channel) {
68
- if (channel === 'red') {
69
- channel = 0;
70
- } else if (channel === 'green') {
71
- channel = 1;
72
- } else if (channel === 'blue') {
73
- channel = 2;
68
+ const channelMap = { red: 0, green: 1, blue: 2, alpha: 3 };
69
+ if (Object.keys(channelMap).includes(channel)) {
70
+ channel = channelMap[channel];
74
71
  }
75
72
  if (is.integer(channel) && is.inRange(channel, 0, 4)) {
76
73
  this.options.extractChannel = channel;
77
74
  } else {
78
- throw is.invalidParameterError('channel', 'integer or one of: red, green, blue', channel);
75
+ throw is.invalidParameterError('channel', 'integer or one of: red, green, blue, alpha', channel);
79
76
  }
80
77
  return this;
81
78
  }
@@ -38,15 +38,20 @@ try {
38
38
  const debuglog = util.debuglog('sharp');
39
39
 
40
40
  /**
41
- * @constructs sharp
42
- *
43
41
  * Constructor factory to create an instance of `sharp`, to which further methods are chained.
44
42
  *
45
43
  * JPEG, PNG, WebP or TIFF format image data can be streamed out from this object.
46
44
  * When using Stream based output, derived attributes are available from the `info` event.
47
45
  *
46
+ * Non-critical problems encountered during processing are emitted as `warning` events.
47
+ *
48
48
  * Implements the [stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class.
49
49
  *
50
+ * @constructs Sharp
51
+ *
52
+ * @emits Sharp#info
53
+ * @emits Sharp#warning
54
+ *
50
55
  * @example
51
56
  * sharp('input.jpg')
52
57
  * .resize(300, 200)
@@ -81,30 +86,36 @@ const debuglog = util.debuglog('sharp');
81
86
  * .toBuffer()
82
87
  * .then( ... );
83
88
  *
84
- * @param {(Buffer|String)} [input] - if present, can be
89
+ * @example
90
+ * // Convert an animated GIF to an animated WebP
91
+ * await sharp('in.gif', { animated: true }).toFile('out.webp');
92
+ *
93
+ * @param {(Buffer|string)} [input] - if present, can be
85
94
  * a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
86
95
  * a String containing the filesystem path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
87
96
  * JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
88
97
  * @param {Object} [options] - if present, is an Object with optional attributes.
89
- * @param {Boolean} [options.failOnError=true] - by default halt processing and raise an error when loading invalid images.
98
+ * @param {boolean} [options.failOnError=true] - by default halt processing and raise an error when loading invalid images.
90
99
  * Set this flag to `false` if you'd rather apply a "best effort" to decode images, even if the data is corrupt or invalid.
91
- * @param {Number|Boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
100
+ * @param {number|boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
92
101
  * (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
93
102
  * An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
94
- * @param {Boolean} [options.sequentialRead=false] - Set this to `true` to use sequential rather than random access where possible.
103
+ * @param {boolean} [options.sequentialRead=false] - Set this to `true` to use sequential rather than random access where possible.
95
104
  * This can reduce memory usage and might improve performance on some systems.
96
- * @param {Number} [options.density=72] - number representing the DPI for vector images.
97
- * @param {Number} [options.pages=1] - number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages.
98
- * @param {Number} [options.page=0] - page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based.
105
+ * @param {number} [options.density=72] - number representing the DPI for vector images in the range 1 to 100000.
106
+ * @param {number} [options.pages=1] - number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages.
107
+ * @param {number} [options.page=0] - page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based.
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`).
99
110
  * @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering.
100
- * @param {Number} [options.raw.width]
101
- * @param {Number} [options.raw.height]
102
- * @param {Number} [options.raw.channels] - 1-4
111
+ * @param {number} [options.raw.width]
112
+ * @param {number} [options.raw.height]
113
+ * @param {number} [options.raw.channels] - 1-4
103
114
  * @param {Object} [options.create] - describes a new image to be created.
104
- * @param {Number} [options.create.width]
105
- * @param {Number} [options.create.height]
106
- * @param {Number} [options.create.channels] - 3-4
107
- * @param {String|Object} [options.create.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
115
+ * @param {number} [options.create.width]
116
+ * @param {number} [options.create.height]
117
+ * @param {number} [options.create.channels] - 3-4
118
+ * @param {string|Object} [options.create.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
108
119
  * @returns {Sharp}
109
120
  * @throws {Error} Invalid parameters
110
121
  */
@@ -181,6 +192,7 @@ const Sharp = function (input, options) {
181
192
  streamOut: false,
182
193
  withMetadata: false,
183
194
  withMetadataOrientation: -1,
195
+ withMetadataIcc: '',
184
196
  resolveWithObject: false,
185
197
  // output format
186
198
  jpegQuality: 80,
@@ -208,7 +220,7 @@ const Sharp = function (input, options) {
208
220
  tiffCompression: 'jpeg',
209
221
  tiffPredictor: 'horizontal',
210
222
  tiffPyramid: false,
211
- tiffSquash: false,
223
+ tiffBitdepth: 8,
212
224
  tiffTile: false,
213
225
  tiffTileHeight: 256,
214
226
  tiffTileWidth: 256,
@@ -226,10 +238,14 @@ const Sharp = function (input, options) {
226
238
  tileAngle: 0,
227
239
  tileSkipBlanks: -1,
228
240
  tileBackground: [255, 255, 255, 255],
241
+ tileCentre: false,
229
242
  linearA: 1,
230
243
  linearB: 0,
231
244
  // Function to notify of libvips warnings
232
- debuglog: debuglog,
245
+ debuglog: warning => {
246
+ this.emit('warning', warning);
247
+ debuglog(warning);
248
+ },
233
249
  // Function to notify of queue length changes
234
250
  queueListener: function (queueLength) {
235
251
  Sharp.queue.emit('change', queueLength);
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, 2400)) {
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 2400', inputOptions.density);
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;
@@ -113,6 +120,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
113
120
  throw is.invalidParameterError('page', 'integer between 0 and 100000', inputOptions.page);
114
121
  }
115
122
  }
123
+ // Multi-level input (OpenSlide)
124
+ if (is.defined(inputOptions.level)) {
125
+ if (is.integer(inputOptions.level) && is.inRange(inputOptions.level, 0, 256)) {
126
+ inputDescriptor.level = inputOptions.level;
127
+ } else {
128
+ throw is.invalidParameterError('level', 'integer between 0 and 256', inputOptions.level);
129
+ }
130
+ }
116
131
  // Create new image
117
132
  if (is.defined(inputOptions.create)) {
118
133
  if (
@@ -208,6 +223,7 @@ function _isStreamInput () {
208
223
  * - `loop`: Number of times to loop an animated image, zero refers to a continuous loop.
209
224
  * - `delay`: Delay in ms between each page in an animated image, provided as an array of integers.
210
225
  * - `pagePrimary`: Number of the primary page in a HEIF image
226
+ * - `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide
211
227
  * - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
212
228
  * - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
213
229
  * - `orientation`: Number value of the EXIF Orientation header, if present
@@ -290,6 +306,8 @@ function metadata (callback) {
290
306
  * - `maxY` (y-coordinate of one of the pixel where the maximum lies)
291
307
  * - `isOpaque`: Is the image fully opaque? Will be `true` if the image has no alpha channel or if every pixel is fully opaque.
292
308
  * - `entropy`: Histogram-based estimation of greyscale entropy, discarding alpha channel if any (experimental)
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)
293
311
  *
294
312
  * @example
295
313
  * const image = sharp(inputJpg);
@@ -299,6 +317,10 @@ function metadata (callback) {
299
317
  * // stats contains the channel-wise statistics array and the isOpaque value
300
318
  * });
301
319
  *
320
+ * @example
321
+ * const { entropy, sharpness, dominant } = await sharp(input).stats();
322
+ * const { r, g, b } = dominant;
323
+ *
302
324
  * @param {Function} [callback] - called with the arguments `(err, stats)`
303
325
  * @returns {Promise<Object>}
304
326
  */
package/lib/is.js CHANGED
@@ -21,7 +21,7 @@ const object = function (val) {
21
21
  * @private
22
22
  */
23
23
  const plainObject = function (val) {
24
- return object(val) && Object.prototype.toString.call(val) === '[object Object]';
24
+ return Object.prototype.toString.call(val) === '[object Object]';
25
25
  };
26
26
 
27
27
  /**
@@ -45,7 +45,7 @@ const bool = function (val) {
45
45
  * @private
46
46
  */
47
47
  const buffer = function (val) {
48
- return object(val) && val instanceof Buffer;
48
+ return val instanceof Buffer;
49
49
  };
50
50
 
51
51
  /**
@@ -69,7 +69,7 @@ const number = function (val) {
69
69
  * @private
70
70
  */
71
71
  const integer = function (val) {
72
- return number(val) && val % 1 === 0;
72
+ return Number.isInteger(val);
73
73
  };
74
74
 
75
75
  /**
@@ -85,7 +85,7 @@ const inRange = function (val, min, max) {
85
85
  * @private
86
86
  */
87
87
  const inArray = function (val, list) {
88
- return list.indexOf(val) !== -1;
88
+ return list.includes(val);
89
89
  };
90
90
 
91
91
  /**
package/lib/libvips.js CHANGED
@@ -48,24 +48,18 @@ 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 */
65
59
  if (currentPlatformId === vendorPlatformId) {
66
60
  return true;
67
61
  } else {
68
- throw new Error(`'${vendorPlatformId}' binaries cannot be used on the '${currentPlatformId}' platform. Please remove the 'node_modules/sharp/vendor' directory and run 'npm install'.`);
62
+ throw new Error(`'${vendorPlatformId}' binaries cannot be used on the '${currentPlatformId}' platform. Please remove the 'node_modules/sharp' directory and run 'npm install' on the '${currentPlatformId}' platform.`);
69
63
  }
70
64
  } else {
71
65
  return false;