sharp 0.24.0 → 0.25.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
@@ -20,8 +20,7 @@ Lanczos resampling ensures quality is not sacrificed for speed.
20
20
  As well as image resizing, operations such as
21
21
  rotation, extraction, compositing and gamma correction are available.
22
22
 
23
- Most modern 64-bit macOS, Windows and Linux systems running
24
- Node versions 10, 12 and 13
23
+ Most modern macOS, Windows and Linux systems running Node.js v10+
25
24
  do not require any additional install or runtime dependencies.
26
25
 
27
26
  ## Examples
@@ -90,10 +89,10 @@ readableStream
90
89
  ### Documentation
91
90
 
92
91
  Visit [sharp.pixelplumbing.com](https://sharp.pixelplumbing.com/) for complete
93
- [installation instructions](https://sharp.pixelplumbing.com/page/install),
94
- [API documentation](https://sharp.pixelplumbing.com/page/api),
95
- [benchmark tests](https://sharp.pixelplumbing.com/page/performance) and
96
- [changelog](https://sharp.pixelplumbing.com/page/changelog).
92
+ [installation instructions](https://sharp.pixelplumbing.com/install),
93
+ [API documentation](https://sharp.pixelplumbing.com/api-constructor),
94
+ [benchmark tests](https://sharp.pixelplumbing.com/performance) and
95
+ [changelog](https://sharp.pixelplumbing.com/changelog).
97
96
 
98
97
  ### Contributing
99
98
 
package/binding.gyp CHANGED
@@ -30,6 +30,9 @@
30
30
  'msvs_settings': {
31
31
  'VCCLCompilerTool': {
32
32
  'ExceptionHandling': 1
33
+ },
34
+ 'VCLinkerTool': {
35
+ 'ImageHasSafeExceptionHandlers': 'false'
33
36
  }
34
37
  },
35
38
  'msvs_disabled_warnings': [
@@ -44,7 +47,11 @@
44
47
  ]
45
48
  }, {
46
49
  'target_name': 'sharp',
50
+ 'defines': [
51
+ 'NAPI_VERSION=3'
52
+ ],
47
53
  'dependencies': [
54
+ '<!(node -p "require(\'node-addon-api\').gyp")',
48
55
  'libvips-cpp'
49
56
  ],
50
57
  'variables': {
@@ -65,11 +72,11 @@
65
72
  'src/stats.cc',
66
73
  'src/operations.cc',
67
74
  'src/pipeline.cc',
68
- 'src/sharp.cc',
69
- 'src/utilities.cc'
75
+ 'src/utilities.cc',
76
+ 'src/sharp.cc'
70
77
  ],
71
78
  'include_dirs': [
72
- '<!(node -e "require(\'nan\')")'
79
+ '<!@(node -p "require(\'node-addon-api\').include")',
73
80
  ],
74
81
  'conditions': [
75
82
  ['use_global_libvips == "true"', {
@@ -189,10 +196,18 @@
189
196
  '-Wno-cast-function-type'
190
197
  ]
191
198
  }],
199
+ ['target_arch == "arm"', {
200
+ 'cflags_cc': [
201
+ '-Wno-psabi'
202
+ ]
203
+ }],
192
204
  ['OS == "win"', {
193
205
  'msvs_settings': {
194
206
  'VCCLCompilerTool': {
195
207
  'ExceptionHandling': 1
208
+ },
209
+ 'VCLinkerTool': {
210
+ 'ImageHasSafeExceptionHandlers': 'false'
196
211
  }
197
212
  },
198
213
  'msvs_disabled_warnings': [
@@ -14,8 +14,14 @@ const agent = require('../lib/agent');
14
14
  const libvips = require('../lib/libvips');
15
15
  const platform = require('../lib/platform');
16
16
 
17
- const minimumLibvipsVersion = libvips.minimumLibvipsVersion;
18
- 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${minimumLibvipsVersion}/`;
17
+ const minimumGlibcVersionByArch = {
18
+ arm: '2.28',
19
+ arm64: '2.29',
20
+ x64: '2.17'
21
+ };
22
+
23
+ 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}/`;
19
25
 
20
26
  const fail = function (err) {
21
27
  npmLog.error('sharp', err.message);
@@ -57,18 +63,14 @@ try {
57
63
  // Is this arch/platform supported?
58
64
  const arch = process.env.npm_config_arch || process.arch;
59
65
  const platformAndArch = platform();
60
- if (platformAndArch === 'win32-ia32') {
61
- throw new Error('Windows x86 (32-bit) node.exe is not supported');
62
- }
63
- if (arch === 'ia32') {
66
+ if (arch === 'ia32' && !platformAndArch.startsWith('win32')) {
64
67
  throw new Error(`Intel Architecture 32-bit systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
65
68
  }
66
69
  if (platformAndArch === 'freebsd-x64' || platformAndArch === 'openbsd-x64' || platformAndArch === 'sunos-x64') {
67
70
  throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
68
71
  }
69
72
  if (detectLibc.family === detectLibc.GLIBC && detectLibc.version) {
70
- const minimumGlibcVersion = arch === 'arm64' ? '2.29.0' : '2.17.0';
71
- if (semver.lt(`${detectLibc.version}.0`, minimumGlibcVersion)) {
73
+ if (semver.lt(`${detectLibc.version}.0`, `${minimumGlibcVersionByArch[arch]}.0`)) {
72
74
  throw new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
73
75
  }
74
76
  }
package/lib/channel.js CHANGED
@@ -54,9 +54,10 @@ function ensureAlpha () {
54
54
  * @example
55
55
  * sharp(input)
56
56
  * .extractChannel('green')
57
- * .toFile('input_green.jpg', function(err, info) {
57
+ * .toColourspace('b-w')
58
+ * .toFile('green.jpg', function(err, info) {
58
59
  * // info.channels === 1
59
- * // input_green.jpg contains the green channel of the input image
60
+ * // green.jpg is a greyscale image containing the green channel of the input
60
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.
package/lib/composite.js CHANGED
@@ -100,8 +100,7 @@ function composite (images) {
100
100
  if (!is.object(image)) {
101
101
  throw is.invalidParameterError('image to composite', 'object', image);
102
102
  }
103
- const { raw, density } = image;
104
- const inputOptions = (raw || density) ? { raw, density } : undefined;
103
+ const inputOptions = this._inputOptionsFromObject(image);
105
104
  const composite = {
106
105
  input: this._createInputDescriptor(image.input, inputOptions, { allowStream: false }),
107
106
  blend: 'over',
@@ -16,6 +16,8 @@ try {
16
16
  help.push('- Ensure the version of Node.js used at install time matches that used at runtime');
17
17
  } else if (/invalid ELF header/.test(err.message)) {
18
18
  help.push(`- Ensure "${process.platform}" is used at install time as well as runtime`);
19
+ } else if (/dylib/.test(err.message) && /Incompatible library version/.test(err.message)) {
20
+ help.push('- Run "brew update && brew upgrade vips"');
19
21
  } else if (/Cannot find module/.test(err.message)) {
20
22
  help.push('- Run "npm rebuild --verbose sharp" and look for errors');
21
23
  } else {
@@ -161,7 +163,7 @@ const Sharp = function (input, options) {
161
163
  gamma: 0,
162
164
  gammaOut: 0,
163
165
  greyscale: false,
164
- normalise: 0,
166
+ normalise: false,
165
167
  brightness: 1,
166
168
  saturation: 1,
167
169
  hue: 0,
@@ -217,6 +219,11 @@ const Sharp = function (input, options) {
217
219
  heifCompression: 'hevc',
218
220
  tileSize: 256,
219
221
  tileOverlap: 0,
222
+ tileContainer: 'fs',
223
+ tileLayout: 'dz',
224
+ tileFormat: 'last',
225
+ tileDepth: 'last',
226
+ tileAngle: 0,
220
227
  tileSkipBlanks: -1,
221
228
  tileBackground: [255, 255, 255, 255],
222
229
  linearA: 1,
package/lib/input.js CHANGED
@@ -1,10 +1,20 @@
1
1
  'use strict';
2
2
 
3
- const util = require('util');
4
3
  const color = require('color');
5
4
  const is = require('./is');
6
5
  const sharp = require('../build/Release/sharp.node');
7
6
 
7
+ /**
8
+ * Extract input options, if any, from an object.
9
+ * @private
10
+ */
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 }
15
+ : undefined;
16
+ }
17
+
8
18
  /**
9
19
  * Create Object containing input and input-related options.
10
20
  * @private
@@ -24,12 +34,12 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
24
34
  } else if (is.plainObject(input) && !is.defined(inputOptions)) {
25
35
  // Plain Object descriptor, e.g. create
26
36
  inputOptions = input;
27
- if (is.plainObject(inputOptions.raw) || is.bool(inputOptions.failOnError)) {
28
- // Raw Stream
37
+ if (_inputOptionsFromObject(inputOptions)) {
38
+ // Stream with options
29
39
  inputDescriptor.buffer = [];
30
40
  }
31
41
  } else if (!is.defined(input) && !is.defined(inputOptions) && is.object(containerOptions) && containerOptions.allowStream) {
32
- // Stream
42
+ // Stream without options
33
43
  inputDescriptor.buffer = [];
34
44
  } else {
35
45
  throw new Error(`Unsupported input '${input}' of type ${typeof input}${
@@ -187,9 +197,9 @@ function _isStreamInput () {
187
197
  * - `size`: Total size of image in bytes, for Stream and Buffer input only
188
198
  * - `width`: Number of pixels wide (EXIF orientation is not taken into consideration)
189
199
  * - `height`: Number of pixels high (EXIF orientation is not taken into consideration)
190
- * - `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)
200
+ * - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsInterpretation)
191
201
  * - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
192
- * - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672)
202
+ * - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsBandFormat)
193
203
  * - `density`: Number of pixels per inch (DPI), if present
194
204
  * - `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
195
205
  * - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
@@ -278,7 +288,7 @@ function metadata (callback) {
278
288
  * - `minY` (y-coordinate of one of the pixel where the minimum lies)
279
289
  * - `maxX` (x-coordinate of one of the pixel where the maximum lies)
280
290
  * - `maxY` (y-coordinate of one of the pixel where the maximum lies)
281
- * - `isOpaque`: Value to identify if the image is opaque or transparent, based on the presence and use of alpha channel
291
+ * - `isOpaque`: Is the image fully opaque? Will be `true` if the image has no alpha channel or if every pixel is fully opaque.
282
292
  * - `entropy`: Histogram-based estimation of greyscale entropy, discarding alpha channel if any (experimental)
283
293
  *
284
294
  * @example
@@ -331,32 +341,6 @@ function stats (callback) {
331
341
  }
332
342
  }
333
343
 
334
- /**
335
- * @private
336
- */
337
- const limitInputPixels = util.deprecate(function limitInputPixels (limit) {
338
- // if we pass in false we represent the integer as 0 to disable
339
- if (limit === false) {
340
- limit = 0;
341
- } else if (limit === true) {
342
- limit = Math.pow(0x3FFF, 2);
343
- }
344
- if (is.integer(limit) && limit >= 0) {
345
- this.options.input.limitInputPixels = limit;
346
- } else {
347
- throw is.invalidParameterError('limitInputPixels', 'integer', limit);
348
- }
349
- return this;
350
- }, 'limitInputPixels is deprecated, use sharp(input, { limitInputPixels: false }) instead');
351
-
352
- /**
353
- * @private
354
- */
355
- const sequentialRead = util.deprecate(function sequentialRead (sequentialRead) {
356
- this.options.input.sequentialRead = is.bool(sequentialRead) ? sequentialRead : true;
357
- return this;
358
- }, 'sequentialRead is deprecated, use sharp(input, { sequentialRead: true }) instead');
359
-
360
344
  /**
361
345
  * Decorate the Sharp prototype with input-related functions.
362
346
  * @private
@@ -364,15 +348,13 @@ const sequentialRead = util.deprecate(function sequentialRead (sequentialRead) {
364
348
  module.exports = function (Sharp) {
365
349
  Object.assign(Sharp.prototype, {
366
350
  // Private
351
+ _inputOptionsFromObject,
367
352
  _createInputDescriptor,
368
353
  _write,
369
354
  _flattenBufferIn,
370
355
  _isStreamInput,
371
356
  // Public
372
357
  metadata,
373
- stats,
374
- // Deprecated
375
- limitInputPixels,
376
- sequentialRead
358
+ stats
377
359
  });
378
360
  };
package/lib/libvips.js CHANGED
@@ -8,8 +8,9 @@ const semver = require('semver');
8
8
  const platform = require('./platform');
9
9
 
10
10
  const env = process.env;
11
- const minimumLibvipsVersion = env.npm_package_config_libvips || /* istanbul ignore next */
11
+ const minimumLibvipsVersionLabelled = env.npm_package_config_libvips || /* istanbul ignore next */
12
12
  require('../package.json').config.libvips;
13
+ const minimumLibvipsVersion = semver.coerce(minimumLibvipsVersionLabelled).version;
13
14
 
14
15
  const spawnSyncOptions = {
15
16
  encoding: 'utf8',
@@ -93,11 +94,12 @@ const useGlobalLibvips = function () {
93
94
  };
94
95
 
95
96
  module.exports = {
96
- minimumLibvipsVersion: minimumLibvipsVersion,
97
- cachePath: cachePath,
98
- globalLibvipsVersion: globalLibvipsVersion,
99
- hasVendoredLibvips: hasVendoredLibvips,
100
- pkgConfigPath: pkgConfigPath,
101
- useGlobalLibvips: useGlobalLibvips,
102
- mkdirSync: mkdirSync
97
+ minimumLibvipsVersion,
98
+ minimumLibvipsVersionLabelled,
99
+ cachePath,
100
+ globalLibvipsVersion,
101
+ hasVendoredLibvips,
102
+ pkgConfigPath,
103
+ useGlobalLibvips,
104
+ mkdirSync
103
105
  };
package/lib/output.js CHANGED
@@ -517,7 +517,9 @@ function heif (options) {
517
517
  }
518
518
 
519
519
  /**
520
- * Force output to be raw, uncompressed uint8 pixel data.
520
+ * Force output to be raw, uncompressed, 8-bit unsigned integer (unit8) pixel data.
521
+ * Pixel ordering is left-to-right, top-to-bottom, without padding.
522
+ * Channel ordering will be RGB or RGBA for non-greyscale colourspaces.
521
523
  *
522
524
  * @example
523
525
  * // Extract raw RGB pixel data from JPEG input
@@ -525,6 +527,15 @@ function heif (options) {
525
527
  * .raw()
526
528
  * .toBuffer({ resolveWithObject: true });
527
529
  *
530
+ * @example
531
+ * // Extract alpha channel as raw pixel data from PNG input
532
+ * const data = await sharp('input.png')
533
+ * .ensureAlpha()
534
+ * .extractChannel(3)
535
+ * .colourspace('b-w')
536
+ * .raw()
537
+ * .toBuffer();
538
+ *
528
539
  * @returns {Sharp}
529
540
  */
530
541
  function raw () {
@@ -557,7 +568,7 @@ function raw () {
557
568
  * @param {String} [options.depth] how deep to make the pyramid, possible values are `onepixel`, `onetile` or `one`, default based on layout.
558
569
  * @param {Number} [options.skipBlanks=-1] threshold to skip tile generation, a value 0 - 255 for 8-bit images or 0 - 65535 for 16-bit images
559
570
  * @param {String} [options.container='fs'] tile container, with value `fs` (filesystem) or `zip` (compressed file).
560
- * @param {String} [options.layout='dz'] filesystem layout, possible values are `dz`, `zoomify` or `google`.
571
+ * @param {String} [options.layout='dz'] filesystem layout, possible values are `dz`, `iiif`, `zoomify` or `google`.
561
572
  * @returns {Sharp}
562
573
  * @throws {Error} Invalid parameters
563
574
  */
@@ -592,10 +603,10 @@ function tile (options) {
592
603
  }
593
604
  // Layout
594
605
  if (is.defined(options.layout)) {
595
- if (is.string(options.layout) && is.inArray(options.layout, ['dz', 'google', 'zoomify'])) {
606
+ if (is.string(options.layout) && is.inArray(options.layout, ['dz', 'google', 'iiif', 'zoomify'])) {
596
607
  this.options.tileLayout = options.layout;
597
608
  } else {
598
- throw is.invalidParameterError('layout', 'one of: dz, google, zoomify', options.layout);
609
+ throw is.invalidParameterError('layout', 'one of: dz, google, iiif, zoomify', options.layout);
599
610
  }
600
611
  }
601
612
  // Angle of rotation,
package/lib/resize.js CHANGED
@@ -85,21 +85,30 @@ const mapFitToCanvas = {
85
85
  outside: 'min'
86
86
  };
87
87
 
88
+ /**
89
+ * @private
90
+ */
91
+ function isRotationExpected (options) {
92
+ return (options.angle % 360) !== 0 || options.useExifOrientation === true || options.rotationAngle !== 0;
93
+ }
94
+
88
95
  /**
89
96
  * Resize image to `width`, `height` or `width x height`.
90
97
  *
91
98
  * When both a `width` and `height` are provided, the possible methods by which the image should **fit** these are:
92
- * - `cover`: Crop to cover both provided dimensions (the default).
93
- * - `contain`: Embed within both provided dimensions.
99
+ * - `cover`: (default) Preserving aspect ratio, ensure the image covers both provided dimensions by cropping/clipping to fit.
100
+ * - `contain`: Preserving aspect ratio, contain within both provided dimensions using "letterboxing" where necessary.
94
101
  * - `fill`: Ignore the aspect ratio of the input and stretch to both provided dimensions.
95
102
  * - `inside`: Preserving aspect ratio, resize the image to be as large as possible while ensuring its dimensions are less than or equal to both those specified.
96
103
  * - `outside`: Preserving aspect ratio, resize the image to be as small as possible while ensuring its dimensions are greater than or equal to both those specified.
104
+ *
97
105
  * Some of these values are based on the [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) CSS property.
98
106
  *
99
107
  * When using a `fit` of `cover` or `contain`, the default **position** is `centre`. Other options are:
100
108
  * - `sharp.position`: `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`.
101
109
  * - `sharp.gravity`: `north`, `northeast`, `east`, `southeast`, `south`, `southwest`, `west`, `northwest`, `center` or `centre`.
102
110
  * - `sharp.strategy`: `cover` only, dynamically crop using either the `entropy` or `attention` strategy.
111
+ *
103
112
  * Some of these values are based on the [object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) CSS property.
104
113
  *
105
114
  * The experimental strategy-based approach resizes so one dimension is at its target length
@@ -367,7 +376,7 @@ function extract (options) {
367
376
  }
368
377
  }, this);
369
378
  // Ensure existing rotation occurs before pre-resize extraction
370
- if (suffix === 'Pre' && ((this.options.angle % 360) !== 0 || this.options.useExifOrientation === true || this.options.rotationAngle !== 0)) {
379
+ if (suffix === 'Pre' && isRotationExpected(this.options)) {
371
380
  this.options.rotateBeforePreExtract = true;
372
381
  }
373
382
  return this;
@@ -391,6 +400,9 @@ function trim (threshold) {
391
400
  } else {
392
401
  throw is.invalidParameterError('threshold', 'number greater than zero', threshold);
393
402
  }
403
+ if (this.options.trimThreshold && isRotationExpected(this.options)) {
404
+ this.options.rotateBeforePreExtract = true;
405
+ }
394
406
  return this;
395
407
  }
396
408
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sharp",
3
3
  "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
4
- "version": "0.24.0",
4
+ "version": "0.25.2",
5
5
  "author": "Lovell Fuller <npm@lovell.info>",
6
6
  "homepage": "https://github.com/lovell/sharp",
7
7
  "contributors": [
@@ -65,10 +65,11 @@
65
65
  "Andargor <andargor@yahoo.com>",
66
66
  "Paul Neave <paul.neave@gmail.com>",
67
67
  "Brendan Kennedy <brenwken@gmail.com>",
68
- "Brychan Bennett-Odlum <git@brychan.io>"
68
+ "Brychan Bennett-Odlum <git@brychan.io>",
69
+ "Edward Silverton <e.silverton@gmail.com>"
69
70
  ],
70
71
  "scripts": {
71
- "install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
72
+ "install": "(node install/libvips && node install/dll-copy && prebuild-install --runtime=napi) || (node-gyp rebuild && node install/dll-copy)",
72
73
  "clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
73
74
  "test": "semistandard && cpplint && npm run test-unit && npm run test-licensing && prebuild-ci",
74
75
  "test-unit": "nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js",
@@ -109,40 +110,45 @@
109
110
  "dependencies": {
110
111
  "color": "^3.1.2",
111
112
  "detect-libc": "^1.0.3",
112
- "nan": "^2.14.0",
113
+ "node-addon-api": "^2.0.0",
113
114
  "npmlog": "^4.1.2",
114
115
  "prebuild-install": "^5.3.3",
115
- "semver": "^7.1.1",
116
+ "semver": "^7.1.3",
116
117
  "simple-get": "^3.1.0",
117
- "tar": "^5.0.5",
118
+ "tar": "^6.0.1",
118
119
  "tunnel-agent": "^0.6.0"
119
120
  },
120
121
  "devDependencies": {
121
- "async": "^3.1.0",
122
+ "async": "^3.2.0",
122
123
  "cc": "^2.0.1",
123
124
  "decompress-zip": "^0.3.2",
124
125
  "documentation": "^12.1.4",
125
126
  "exif-reader": "^1.0.3",
126
127
  "icc": "^1.0.0",
127
128
  "license-checker": "^25.0.1",
128
- "mocha": "^7.0.0",
129
- "mock-fs": "^4.10.4",
129
+ "mocha": "^7.1.1",
130
+ "mock-fs": "^4.11.0",
130
131
  "nyc": "^15.0.0",
131
132
  "prebuild": "^10.0.0",
132
133
  "prebuild-ci": "^3.1.0",
133
- "rimraf": "^3.0.0",
134
+ "rimraf": "^3.0.2",
134
135
  "semistandard": "^14.2.0"
135
136
  },
136
137
  "license": "Apache-2.0",
137
138
  "config": {
138
- "libvips": "8.9.0"
139
+ "libvips": "8.9.1"
139
140
  },
140
141
  "engines": {
141
- "node": ">=10.13.0"
142
+ "node": ">=10"
142
143
  },
143
144
  "funding": {
144
145
  "url": "https://opencollective.com/libvips"
145
146
  },
147
+ "binary": {
148
+ "napi_versions": [
149
+ 3
150
+ ]
151
+ },
146
152
  "semistandard": {
147
153
  "env": [
148
154
  "mocha"
package/src/common.cc CHANGED
@@ -19,9 +19,7 @@
19
19
  #include <queue>
20
20
  #include <mutex> // NOLINT(build/c++11)
21
21
 
22
- #include <node.h>
23
- #include <node_buffer.h>
24
- #include <nan.h>
22
+ #include <napi.h>
25
23
  #include <vips/vips8>
26
24
 
27
25
  #include "common.h"
@@ -30,66 +28,77 @@ using vips::VImage;
30
28
 
31
29
  namespace sharp {
32
30
 
33
- // Convenience methods to access the attributes of a v8::Object
34
- bool HasAttr(v8::Local<v8::Object> obj, std::string attr) {
35
- return Nan::Has(obj, Nan::New(attr).ToLocalChecked()).FromJust();
31
+ // Convenience methods to access the attributes of a Napi::Object
32
+ bool HasAttr(Napi::Object obj, std::string attr) {
33
+ return obj.Has(attr);
36
34
  }
37
- std::string AttrAsStr(v8::Local<v8::Object> obj, std::string attr) {
38
- return *Nan::Utf8String(Nan::Get(obj, Nan::New(attr).ToLocalChecked()).ToLocalChecked());
35
+ std::string AttrAsStr(Napi::Object obj, std::string attr) {
36
+ return obj.Get(attr).As<Napi::String>();
39
37
  }
40
- std::vector<double> AttrAsRgba(v8::Local<v8::Object> obj, std::string attr) {
41
- v8::Local<v8::Object> background = AttrAs<v8::Object>(obj, attr);
42
- std::vector<double> rgba(4);
43
- for (unsigned int i = 0; i < 4; i++) {
44
- rgba[i] = AttrTo<double>(background, i);
38
+ uint32_t AttrAsUint32(Napi::Object obj, std::string attr) {
39
+ return obj.Get(attr).As<Napi::Number>().Uint32Value();
40
+ }
41
+ int32_t AttrAsInt32(Napi::Object obj, std::string attr) {
42
+ return obj.Get(attr).As<Napi::Number>().Int32Value();
43
+ }
44
+ double AttrAsDouble(Napi::Object obj, std::string attr) {
45
+ return obj.Get(attr).As<Napi::Number>().DoubleValue();
46
+ }
47
+ double AttrAsDouble(Napi::Object obj, unsigned int const attr) {
48
+ return obj.Get(attr).As<Napi::Number>().DoubleValue();
49
+ }
50
+ bool AttrAsBool(Napi::Object obj, std::string attr) {
51
+ return obj.Get(attr).As<Napi::Boolean>().Value();
52
+ }
53
+ std::vector<double> AttrAsRgba(Napi::Object obj, std::string attr) {
54
+ Napi::Array background = obj.Get(attr).As<Napi::Array>();
55
+ std::vector<double> rgba(background.Length());
56
+ for (unsigned int i = 0; i < background.Length(); i++) {
57
+ rgba[i] = AttrAsDouble(background, i);
45
58
  }
46
59
  return rgba;
47
60
  }
48
61
 
49
- // Create an InputDescriptor instance from a v8::Object describing an input image
50
- InputDescriptor* CreateInputDescriptor(
51
- v8::Local<v8::Object> input, std::vector<v8::Local<v8::Object>> &buffersToPersist
52
- ) {
53
- Nan::HandleScope();
62
+ // Create an InputDescriptor instance from a Napi::Object describing an input image
63
+ InputDescriptor* CreateInputDescriptor(Napi::Object input) {
54
64
  InputDescriptor *descriptor = new InputDescriptor;
55
65
  if (HasAttr(input, "file")) {
56
66
  descriptor->file = AttrAsStr(input, "file");
57
67
  } else if (HasAttr(input, "buffer")) {
58
- v8::Local<v8::Object> buffer = AttrAs<v8::Object>(input, "buffer");
59
- descriptor->bufferLength = node::Buffer::Length(buffer);
60
- descriptor->buffer = node::Buffer::Data(buffer);
68
+ Napi::Buffer<char> buffer = input.Get("buffer").As<Napi::Buffer<char>>();
69
+ descriptor->bufferLength = buffer.Length();
70
+ descriptor->buffer = buffer.Data();
61
71
  descriptor->isBuffer = TRUE;
62
- buffersToPersist.push_back(buffer);
63
72
  }
64
- descriptor->failOnError = AttrTo<bool>(input, "failOnError");
73
+ descriptor->failOnError = AttrAsBool(input, "failOnError");
65
74
  // Density for vector-based input
66
75
  if (HasAttr(input, "density")) {
67
- descriptor->density = AttrTo<double>(input, "density");
76
+ descriptor->density = AttrAsDouble(input, "density");
68
77
  }
69
78
  // Raw pixel input
70
79
  if (HasAttr(input, "rawChannels")) {
71
- descriptor->rawChannels = AttrTo<uint32_t>(input, "rawChannels");
72
- descriptor->rawWidth = AttrTo<uint32_t>(input, "rawWidth");
73
- descriptor->rawHeight = AttrTo<uint32_t>(input, "rawHeight");
80
+ descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
81
+ descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
82
+ descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
74
83
  }
75
84
  // Multi-page input (GIF, TIFF, PDF)
76
85
  if (HasAttr(input, "pages")) {
77
- descriptor->pages = AttrTo<int32_t>(input, "pages");
86
+ descriptor->pages = AttrAsInt32(input, "pages");
78
87
  }
79
88
  if (HasAttr(input, "page")) {
80
- descriptor->page = AttrTo<uint32_t>(input, "page");
89
+ descriptor->page = AttrAsUint32(input, "page");
81
90
  }
82
91
  // Create new image
83
92
  if (HasAttr(input, "createChannels")) {
84
- descriptor->createChannels = AttrTo<uint32_t>(input, "createChannels");
85
- descriptor->createWidth = AttrTo<uint32_t>(input, "createWidth");
86
- descriptor->createHeight = AttrTo<uint32_t>(input, "createHeight");
93
+ descriptor->createChannels = AttrAsUint32(input, "createChannels");
94
+ descriptor->createWidth = AttrAsUint32(input, "createWidth");
95
+ descriptor->createHeight = AttrAsUint32(input, "createHeight");
87
96
  descriptor->createBackground = AttrAsRgba(input, "createBackground");
88
97
  }
89
98
  // Limit input images to a given number of pixels, where pixels = width * height
90
- descriptor->limitInputPixels = AttrTo<uint32_t>(input, "limitInputPixels");
99
+ descriptor->limitInputPixels = AttrAsUint32(input, "limitInputPixels");
91
100
  // Allow switch from random to sequential access
92
- descriptor->access = AttrTo<bool>(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
101
+ descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
93
102
  return descriptor;
94
103
  }
95
104
 
@@ -439,11 +448,9 @@ namespace sharp {
439
448
  /*
440
449
  Called when a Buffer undergoes GC, required to support mixed runtime libraries in Windows
441
450
  */
442
- void FreeCallback(char* data, void* hint) {
443
- if (data != nullptr) {
444
- g_free(data);
445
- }
446
- }
451
+ std::function<void(void*, char*)> FreeCallback = [](void*, char* data) {
452
+ g_free(data);
453
+ };
447
454
 
448
455
  /*
449
456
  Temporary buffer of warnings