sharp 0.32.6 → 0.33.0-alpha.4

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 >= 14.15.0
19
+ Most modern macOS, Windows and Linux systems running Node.js >= 18.17.0
20
20
  do not require any additional install or runtime dependencies.
21
21
 
22
22
  ## Documentation
package/binding.gyp CHANGED
@@ -1,8 +1,13 @@
1
+ # Copyright 2013 Lovell Fuller and others.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
1
4
  {
2
5
  'variables': {
3
6
  'vips_version': '<!(node -p "require(\'./lib/libvips\').minimumLibvipsVersion")',
4
- 'platform_and_arch': '<!(node -p "require(\'./lib/platform\')()")',
5
- 'sharp_vendor_dir': './vendor/<(vips_version)/<(platform_and_arch)'
7
+ 'platform_and_arch': '<!(node -p "require(\'./lib/libvips\').buildPlatformArch()")',
8
+ 'sharp_libvips_include_dir': '<!(node -p "require(\'./lib/libvips\').buildSharpLibvipsIncludeDir()")',
9
+ 'sharp_libvips_cplusplus_dir': '<!(node -p "require(\'./lib/libvips\').buildSharpLibvipsCPlusPlusDir()")',
10
+ 'sharp_libvips_lib_dir': '<!(node -p "require(\'./lib/libvips\').buildSharpLibvipsLibDir()")'
6
11
  },
7
12
  'targets': [{
8
13
  'target_name': 'libvips-cpp',
@@ -15,19 +20,19 @@
15
20
  '_ALLOW_KEYWORD_MACROS'
16
21
  ],
17
22
  'sources': [
18
- 'src/libvips/cplusplus/VConnection.cpp',
19
- 'src/libvips/cplusplus/VError.cpp',
20
- 'src/libvips/cplusplus/VImage.cpp',
21
- 'src/libvips/cplusplus/VInterpolate.cpp',
22
- 'src/libvips/cplusplus/VRegion.cpp'
23
+ '<(sharp_libvips_cplusplus_dir)/VConnection.cpp',
24
+ '<(sharp_libvips_cplusplus_dir)/VError.cpp',
25
+ '<(sharp_libvips_cplusplus_dir)/VImage.cpp',
26
+ '<(sharp_libvips_cplusplus_dir)/VInterpolate.cpp',
27
+ '<(sharp_libvips_cplusplus_dir)/VRegion.cpp'
23
28
  ],
24
29
  'include_dirs': [
25
- '<(sharp_vendor_dir)/include',
26
- '<(sharp_vendor_dir)/include/glib-2.0',
27
- '<(sharp_vendor_dir)/lib/glib-2.0/include'
30
+ '<(sharp_libvips_include_dir)',
31
+ '<(sharp_libvips_include_dir)/glib-2.0',
32
+ '<(sharp_libvips_lib_dir)/glib-2.0/include'
28
33
  ],
29
34
  'link_settings': {
30
- 'library_dirs': ['<(sharp_vendor_dir)/lib'],
35
+ 'library_dirs': ['<(sharp_libvips_lib_dir)'],
31
36
  'libraries': [
32
37
  'libvips.lib',
33
38
  'libglib-2.0.lib',
@@ -70,7 +75,7 @@
70
75
  }, {
71
76
  'target_name': 'sharp-<(platform_and_arch)',
72
77
  'defines': [
73
- 'NAPI_VERSION=7',
78
+ 'NAPI_VERSION=9',
74
79
  'NODE_ADDON_API_DISABLE_DEPRECATED',
75
80
  'NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS'
76
81
  ],
@@ -79,7 +84,6 @@
79
84
  'libvips-cpp'
80
85
  ],
81
86
  'variables': {
82
- 'runtime_link%': 'shared',
83
87
  'conditions': [
84
88
  ['OS != "win"', {
85
89
  'pkg_config_path': '<!(node -p "require(\'./lib/libvips\').pkgConfigPath()")',
@@ -106,12 +110,8 @@
106
110
  ['use_global_libvips == "true"', {
107
111
  # Use pkg-config for include and lib
108
112
  'include_dirs': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --cflags-only-I vips-cpp vips glib-2.0 | sed s\/-I//g)'],
113
+ 'libraries': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --libs vips-cpp)'],
109
114
  'conditions': [
110
- ['runtime_link == "static"', {
111
- 'libraries': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --libs --static vips-cpp)']
112
- }, {
113
- 'libraries': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --libs vips-cpp)']
114
- }],
115
115
  ['OS == "linux"', {
116
116
  'defines': [
117
117
  # Inspect libvips-cpp.so to determine which C++11 ABI version was used and set _GLIBCXX_USE_CXX11_ABI accordingly. This is quite horrible.
@@ -122,9 +122,9 @@
122
122
  }, {
123
123
  # Use pre-built libvips stored locally within node_modules
124
124
  'include_dirs': [
125
- '<(sharp_vendor_dir)/include',
126
- '<(sharp_vendor_dir)/include/glib-2.0',
127
- '<(sharp_vendor_dir)/lib/glib-2.0/include'
125
+ '<(sharp_libvips_include_dir)',
126
+ '<(sharp_libvips_include_dir)/glib-2.0',
127
+ '<(sharp_libvips_lib_dir)/glib-2.0/include'
128
128
  ],
129
129
  'conditions': [
130
130
  ['OS == "win"', {
@@ -133,7 +133,7 @@
133
133
  '_FILE_OFFSET_BITS=64'
134
134
  ],
135
135
  'link_settings': {
136
- 'library_dirs': ['<(sharp_vendor_dir)/lib'],
136
+ 'library_dirs': ['<(sharp_libvips_lib_dir)'],
137
137
  'libraries': [
138
138
  'libvips.lib',
139
139
  'libglib-2.0.lib',
@@ -143,7 +143,9 @@
143
143
  }],
144
144
  ['OS == "mac"', {
145
145
  'link_settings': {
146
- 'library_dirs': ['../<(sharp_vendor_dir)/lib'],
146
+ 'library_dirs': [
147
+ '<(sharp_libvips_lib_dir)'
148
+ ],
147
149
  'libraries': [
148
150
  'libvips-cpp.42.dylib'
149
151
  ]
@@ -151,7 +153,9 @@
151
153
  'xcode_settings': {
152
154
  'OTHER_LDFLAGS': [
153
155
  # Ensure runtime linking is relative to sharp.node
154
- '-Wl,-rpath,\'@loader_path/../../<(sharp_vendor_dir)/lib\''
156
+ '-Wl,-rpath,\'@loader_path/../../sharp-libvips-<(platform_and_arch)/lib\'',
157
+ '-Wl,-rpath,\'@loader_path/../../node_modules/@sharpen/sharp-libvips-<(platform_and_arch)/lib\'',
158
+ '-Wl,-rpath,\'@loader_path/../../../node_modules/@sharpen/sharp-libvips-<(platform_and_arch)/lib\''
155
159
  ]
156
160
  }
157
161
  }],
@@ -160,13 +164,19 @@
160
164
  '_GLIBCXX_USE_CXX11_ABI=1'
161
165
  ],
162
166
  'link_settings': {
163
- 'library_dirs': ['../<(sharp_vendor_dir)/lib'],
167
+ 'library_dirs': [
168
+ '<(sharp_libvips_lib_dir)'
169
+ ],
164
170
  'libraries': [
165
171
  '-l:libvips-cpp.so.42'
166
172
  ],
167
173
  'ldflags': [
168
174
  # Ensure runtime linking is relative to sharp.node
169
- '-Wl,-s -Wl,--disable-new-dtags -Wl,-rpath=\'$$ORIGIN/../../<(sharp_vendor_dir)/lib\''
175
+ '-Wl,-s',
176
+ '-Wl,--disable-new-dtags',
177
+ '-Wl,-rpath=\'$$ORIGIN/../../sharp-libvips-<(platform_and_arch)/lib\'',
178
+ '-Wl,-rpath=\'$$ORIGIN/../../node_modules/@sharpen/sharp-libvips-<(platform_and_arch)/lib\'',
179
+ '-Wl,-rpath=\'$$ORIGIN/../../../node_modules/@sharpen/sharp-libvips-<(platform_and_arch)/lib\''
170
180
  ]
171
181
  }
172
182
  }]
@@ -232,5 +242,23 @@
232
242
  ]
233
243
  }
234
244
  },
245
+ }, {
246
+ 'target_name': 'copy-dll',
247
+ 'type': 'none',
248
+ 'dependencies': [
249
+ 'sharp-<(platform_and_arch)'
250
+ ],
251
+ 'conditions': [
252
+ ['OS == "win"', {
253
+ 'copies': [{
254
+ 'destination': 'build/Release',
255
+ 'files': [
256
+ '<(sharp_libvips_lib_dir)/libvips-42.dll',
257
+ '<(sharp_libvips_lib_dir)/libglib-2.0-0.dll',
258
+ '<(sharp_libvips_lib_dir)/libgobject-2.0-0.dll'
259
+ ]
260
+ }]
261
+ }]
262
+ ]
235
263
  }]
236
264
  }
@@ -0,0 +1,27 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ 'use strict';
5
+
6
+ const { useGlobalLibvips, globalLibvipsVersion, log, gypRebuild } = require('../lib/libvips');
7
+
8
+ const buildFromSource = (msg) => {
9
+ log(msg);
10
+ log('Attempting to build from source via node-gyp');
11
+ try {
12
+ require('node-gyp');
13
+ } catch (err) {
14
+ log('You might need to install node-gyp');
15
+ }
16
+ log('See https://sharp.pixelplumbing.com/install#building-from-source');
17
+ const status = gypRebuild();
18
+ if (status !== 0) {
19
+ process.exit(status);
20
+ }
21
+ };
22
+
23
+ if (useGlobalLibvips()) {
24
+ buildFromSource(`Detected globally-installed libvips v${globalLibvipsVersion()}`);
25
+ } else if (process.env.npm_config_build_from_source) {
26
+ buildFromSource('Detected --build-from-source flag');
27
+ }
@@ -3,11 +3,10 @@
3
3
 
4
4
  'use strict';
5
5
 
6
- const util = require('util');
7
- const stream = require('stream');
6
+ const util = require('node:util');
7
+ const stream = require('node:stream');
8
8
  const is = require('./is');
9
9
 
10
- require('./libvips').hasVendoredLibvips();
11
10
  require('./sharp');
12
11
 
13
12
  // Use NODE_DEBUG=sharp to enable libvips warnings
package/lib/index.d.ts CHANGED
@@ -91,12 +91,6 @@ declare namespace sharp {
91
91
  zlib?: string | undefined;
92
92
  };
93
93
 
94
- /** An Object containing the platform and architecture of the current and installed vendored binaries. */
95
- const vendor: {
96
- current: string;
97
- installed: string[];
98
- };
99
-
100
94
  /** An Object containing the available interpolators and their proper values */
101
95
  const interpolators: Interpolators;
102
96
 
@@ -705,7 +699,6 @@ declare namespace sharp {
705
699
 
706
700
  /**
707
701
  * Use these AVIF options for output image.
708
- * Whilst it is possible to create AVIF images smaller than 16x16 pixels, most web browsers do not display these properly.
709
702
  * @param options Output options.
710
703
  * @throws {Error} Invalid options
711
704
  * @returns A sharp instance that can be used to chain operations
package/lib/is.js CHANGED
@@ -138,18 +138,18 @@ const invalidParameterError = function (name, expected, actual) {
138
138
  };
139
139
 
140
140
  module.exports = {
141
- defined: defined,
142
- object: object,
143
- plainObject: plainObject,
144
- fn: fn,
145
- bool: bool,
146
- buffer: buffer,
147
- typedArray: typedArray,
148
- arrayBuffer: arrayBuffer,
149
- string: string,
150
- number: number,
151
- integer: integer,
152
- inRange: inRange,
153
- inArray: inArray,
154
- invalidParameterError: invalidParameterError
141
+ defined,
142
+ object,
143
+ plainObject,
144
+ fn,
145
+ bool,
146
+ buffer,
147
+ typedArray,
148
+ arrayBuffer,
149
+ string,
150
+ number,
151
+ integer,
152
+ inRange,
153
+ inArray,
154
+ invalidParameterError
155
155
  };
package/lib/libvips.js CHANGED
@@ -3,61 +3,74 @@
3
3
 
4
4
  'use strict';
5
5
 
6
- const fs = require('fs');
7
- const os = require('os');
8
- const path = require('path');
9
- const spawnSync = require('child_process').spawnSync;
6
+ const { spawnSync } = require('node:child_process');
10
7
  const semverCoerce = require('semver/functions/coerce');
11
8
  const semverGreaterThanOrEqualTo = require('semver/functions/gte');
9
+ const detectLibc = require('detect-libc');
12
10
 
13
- const platform = require('./platform');
14
- const { config } = require('../package.json');
11
+ const { engines } = require('../package.json');
15
12
 
16
- const env = process.env;
17
- const minimumLibvipsVersionLabelled = env.npm_package_config_libvips || /* istanbul ignore next */
18
- config.libvips;
13
+ const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips || /* istanbul ignore next */
14
+ engines.libvips;
19
15
  const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
20
16
 
17
+ const prebuiltPlatforms = [
18
+ 'darwin-arm64', 'darwin-x64',
19
+ 'linux-arm', 'linux-arm64', 'linux-x64',
20
+ 'linuxmusl-arm64', 'linuxmusl-x64',
21
+ 'win32-ia32', 'win32-x64'
22
+ ];
23
+
21
24
  const spawnSyncOptions = {
22
25
  encoding: 'utf8',
23
26
  shell: true
24
27
  };
25
28
 
26
- const vendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platform());
27
-
28
- const mkdirSync = function (dirPath) {
29
- try {
30
- fs.mkdirSync(dirPath, { recursive: true });
31
- } catch (err) {
32
- /* istanbul ignore next */
33
- if (err.code !== 'EEXIST') {
34
- throw err;
35
- }
29
+ const log = (item) => {
30
+ if (item instanceof Error) {
31
+ console.error(`sharp: Installation error: ${item.message}`);
32
+ } else {
33
+ console.log(`sharp: ${item}`);
36
34
  }
37
35
  };
38
36
 
39
- const cachePath = function () {
40
- const npmCachePath = env.npm_config_cache || /* istanbul ignore next */
41
- (env.APPDATA ? path.join(env.APPDATA, 'npm-cache') : path.join(os.homedir(), '.npm'));
42
- mkdirSync(npmCachePath);
43
- const libvipsCachePath = path.join(npmCachePath, '_libvips');
44
- mkdirSync(libvipsCachePath);
45
- return libvipsCachePath;
37
+ /* istanbul ignore next */
38
+ const runtimeLibc = () => detectLibc.isNonGlibcLinuxSync() ? detectLibc.familySync() : '';
39
+
40
+ const runtimePlatformArch = () => `${process.platform}${runtimeLibc()}-${process.arch}`;
41
+
42
+ /* istanbul ignore next */
43
+ const buildPlatformArch = () => {
44
+ /* eslint camelcase: ["error", { allow: ["^npm_config_"] }] */
45
+ const { npm_config_arch, npm_config_platform, npm_config_libc } = process.env;
46
+ return `${npm_config_platform || process.platform}${npm_config_libc || runtimeLibc()}-${npm_config_arch || process.arch}`;
46
47
  };
47
48
 
48
- const integrity = function (platformAndArch) {
49
- return env[`npm_package_config_integrity_${platformAndArch.replace('-', '_')}`] || config.integrity[platformAndArch];
49
+ const buildSharpLibvipsIncludeDir = () => {
50
+ try {
51
+ return require('@sharpen/sharp-libvips-dev/include');
52
+ } catch {}
53
+ /* istanbul ignore next */
54
+ return '';
50
55
  };
51
56
 
52
- const log = function (item) {
53
- if (item instanceof Error) {
54
- console.error(`sharp: Installation error: ${item.message}`);
55
- } else {
56
- console.log(`sharp: ${item}`);
57
- }
57
+ const buildSharpLibvipsCPlusPlusDir = () => {
58
+ try {
59
+ return require('@sharpen/sharp-libvips-dev/cplusplus');
60
+ } catch {}
61
+ /* istanbul ignore next */
62
+ return '';
63
+ };
64
+
65
+ const buildSharpLibvipsLibDir = () => {
66
+ try {
67
+ return require(`@sharpen/sharp-libvips-${buildPlatformArch()}/lib`);
68
+ } catch {}
69
+ /* istanbul ignore next */
70
+ return '';
58
71
  };
59
72
 
60
- const isRosetta = function () {
73
+ const isRosetta = () => {
61
74
  /* istanbul ignore next */
62
75
  if (process.platform === 'darwin' && process.arch === 'x64') {
63
76
  const translated = spawnSync('sysctl sysctl.proc_translated', spawnSyncOptions).stdout;
@@ -66,12 +79,19 @@ const isRosetta = function () {
66
79
  return false;
67
80
  };
68
81
 
69
- const globalLibvipsVersion = function () {
82
+ /* istanbul ignore next */
83
+ const gypRebuild = () =>
84
+ spawnSync('node-gyp rebuild', {
85
+ ...spawnSyncOptions,
86
+ stdio: 'inherit'
87
+ }).status;
88
+
89
+ const globalLibvipsVersion = () => {
70
90
  if (process.platform !== 'win32') {
71
91
  const globalLibvipsVersion = spawnSync('pkg-config --modversion vips-cpp', {
72
92
  ...spawnSyncOptions,
73
93
  env: {
74
- ...env,
94
+ ...process.env,
75
95
  PKG_CONFIG_PATH: pkgConfigPath()
76
96
  }
77
97
  }).stdout;
@@ -82,17 +102,8 @@ const globalLibvipsVersion = function () {
82
102
  }
83
103
  };
84
104
 
85
- const hasVendoredLibvips = function () {
86
- return fs.existsSync(vendorPath);
87
- };
88
-
89
- /* istanbul ignore next */
90
- const removeVendoredLibvips = function () {
91
- fs.rmSync(vendorPath, { recursive: true, maxRetries: 3, force: true });
92
- };
93
-
94
105
  /* istanbul ignore next */
95
- const pkgConfigPath = function () {
106
+ const pkgConfigPath = () => {
96
107
  if (process.platform !== 'win32') {
97
108
  const brewPkgConfigPath = spawnSync(
98
109
  'which brew >/dev/null 2>&1 && brew environment --plain | grep PKG_CONFIG_LIBDIR | cut -d" " -f2',
@@ -100,7 +111,7 @@ const pkgConfigPath = function () {
100
111
  ).stdout || '';
101
112
  return [
102
113
  brewPkgConfigPath.trim(),
103
- env.PKG_CONFIG_PATH,
114
+ process.env.PKG_CONFIG_PATH,
104
115
  '/usr/local/lib/pkgconfig',
105
116
  '/usr/lib/pkgconfig',
106
117
  '/usr/local/libdata/pkgconfig',
@@ -111,8 +122,9 @@ const pkgConfigPath = function () {
111
122
  }
112
123
  };
113
124
 
114
- const useGlobalLibvips = function () {
115
- if (Boolean(env.SHARP_IGNORE_GLOBAL_LIBVIPS) === true) {
125
+ const useGlobalLibvips = () => {
126
+ if (Boolean(process.env.SHARP_IGNORE_GLOBAL_LIBVIPS) === true) {
127
+ log('Detected SHARP_IGNORE_GLOBAL_LIBVIPS, skipping search for globally-installed libvips');
116
128
  return false;
117
129
  }
118
130
  /* istanbul ignore next */
@@ -127,14 +139,15 @@ const useGlobalLibvips = function () {
127
139
 
128
140
  module.exports = {
129
141
  minimumLibvipsVersion,
130
- minimumLibvipsVersionLabelled,
131
- cachePath,
132
- integrity,
142
+ prebuiltPlatforms,
143
+ buildPlatformArch,
144
+ buildSharpLibvipsIncludeDir,
145
+ buildSharpLibvipsCPlusPlusDir,
146
+ buildSharpLibvipsLibDir,
147
+ runtimePlatformArch,
133
148
  log,
149
+ gypRebuild,
134
150
  globalLibvipsVersion,
135
- hasVendoredLibvips,
136
- removeVendoredLibvips,
137
151
  pkgConfigPath,
138
- useGlobalLibvips,
139
- mkdirSync
152
+ useGlobalLibvips
140
153
  };
package/lib/output.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  'use strict';
5
5
 
6
- const path = require('path');
6
+ const path = require('node:path');
7
7
  const is = require('./is');
8
8
  const sharp = require('./sharp');
9
9
 
@@ -867,9 +867,6 @@ function tiff (options) {
867
867
  /**
868
868
  * Use these AVIF options for output image.
869
869
  *
870
- * Whilst it is possible to create AVIF images smaller than 16x16 pixels,
871
- * most web browsers do not display these properly.
872
- *
873
870
  * AVIF image sequences are not supported.
874
871
  *
875
872
  * @example
@@ -909,9 +906,9 @@ function avif (options) {
909
906
  *
910
907
  * @since 0.23.0
911
908
  *
912
- * @param {Object} [options] - output options
909
+ * @param {Object} options - output options
910
+ * @param {string} options.compression - compression format: av1, hevc
913
911
  * @param {number} [options.quality=50] - quality, integer 1-100
914
- * @param {string} [options.compression='av1'] - compression format: av1, hevc
915
912
  * @param {boolean} [options.lossless=false] - use lossless compression
916
913
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
917
914
  * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
@@ -920,6 +917,11 @@ function avif (options) {
920
917
  */
921
918
  function heif (options) {
922
919
  if (is.object(options)) {
920
+ if (is.string(options.compression) && is.inArray(options.compression, ['av1', 'hevc'])) {
921
+ this.options.heifCompression = options.compression;
922
+ } else {
923
+ throw is.invalidParameterError('compression', 'one of: av1, hevc', options.compression);
924
+ }
923
925
  if (is.defined(options.quality)) {
924
926
  if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
925
927
  this.options.heifQuality = options.quality;
@@ -934,13 +936,6 @@ function heif (options) {
934
936
  throw is.invalidParameterError('lossless', 'boolean', options.lossless);
935
937
  }
936
938
  }
937
- if (is.defined(options.compression)) {
938
- if (is.string(options.compression) && is.inArray(options.compression, ['av1', 'hevc'])) {
939
- this.options.heifCompression = options.compression;
940
- } else {
941
- throw is.invalidParameterError('compression', 'one of: av1, hevc', options.compression);
942
- }
943
- }
944
939
  if (is.defined(options.effort)) {
945
940
  if (is.integer(options.effort) && is.inRange(options.effort, 0, 9)) {
946
941
  this.options.heifEffort = options.effort;
@@ -955,6 +950,8 @@ function heif (options) {
955
950
  throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling);
956
951
  }
957
952
  }
953
+ } else {
954
+ throw is.invalidParameterError('options', 'Object', options);
958
955
  }
959
956
  return this._updateFormatOut('heif', options);
960
957
  }
@@ -1370,7 +1367,7 @@ function _pipeline (callback) {
1370
1367
  reject(err);
1371
1368
  } else {
1372
1369
  if (this.options.resolveWithObject) {
1373
- resolve({ data: data, info: info });
1370
+ resolve({ data, info });
1374
1371
  } else {
1375
1372
  resolve(data);
1376
1373
  }
package/lib/resize.js CHANGED
@@ -250,6 +250,9 @@ function resize (widthOrOptions, height, options) {
250
250
  if (isResizeExpected(this.options)) {
251
251
  this.options.debuglog('ignoring previous resize options');
252
252
  }
253
+ if (this.options.widthPost !== -1) {
254
+ this.options.debuglog('operation order will be: extract, resize, extract');
255
+ }
253
256
  if (is.defined(widthOrOptions)) {
254
257
  if (is.object(widthOrOptions) && !is.defined(options)) {
255
258
  options = widthOrOptions;
@@ -437,7 +440,7 @@ function extend (extend) {
437
440
  *
438
441
  * - Use `extract` before `resize` for pre-resize extraction.
439
442
  * - Use `extract` after `resize` for post-resize extraction.
440
- * - Use `extract` before and after for both.
443
+ * - Use `extract` twice and `resize` once for extract-then-resize-then-extract in a fixed operation order.
441
444
  *
442
445
  * @example
443
446
  * sharp(input)
package/lib/sharp.js CHANGED
@@ -3,36 +3,58 @@
3
3
 
4
4
  'use strict';
5
5
 
6
- const platformAndArch = require('./platform')();
6
+ // Inspects the runtime environment and exports the relevant sharp.node binary
7
+
8
+ const { familySync, versionSync } = require('detect-libc');
9
+
10
+ const { runtimePlatformArch, prebuiltPlatforms, minimumLibvipsVersion } = require('./libvips');
11
+ const runtimePlatform = runtimePlatformArch();
7
12
 
8
13
  /* istanbul ignore next */
9
14
  try {
10
- module.exports = require(`../build/Release/sharp-${platformAndArch}.node`);
11
- } catch (err) {
12
- // Bail early if bindings aren't available
13
- const help = ['', 'Something went wrong installing the "sharp" module', '', err.message, '', 'Possible solutions:'];
14
- if (/dylib/.test(err.message) && /Incompatible library version/.test(err.message)) {
15
- help.push('- Update Homebrew: "brew update && brew upgrade vips"');
16
- } else {
17
- const [platform, arch] = platformAndArch.split('-');
18
- if (platform === 'linux' && /Module did not self-register/.test(err.message)) {
19
- help.push('- Using worker threads? See https://sharp.pixelplumbing.com/install#worker-threads');
15
+ // Check for local build
16
+ module.exports = require(`../build/Release/sharp-${runtimePlatform}.node`);
17
+ } catch (errLocal) {
18
+ try {
19
+ // Check for runtime package
20
+ module.exports = require(`@sharpen/sharp-${runtimePlatform}/sharp.node`);
21
+ } catch (errPackage) {
22
+ const help = ['Could not load the "sharp" module at runtime'];
23
+ if (errLocal.code !== 'MODULE_NOT_FOUND') {
24
+ help.push(`${errLocal.code}: ${errLocal.message}`);
20
25
  }
21
- help.push(
22
- '- Install with verbose logging and look for errors: "npm install --ignore-scripts=false --foreground-scripts --verbose sharp"',
23
- `- Install for the current ${platformAndArch} runtime: "npm install --platform=${platform} --arch=${arch} sharp"`
24
- );
25
- }
26
- help.push(
27
- '- Consult the installation documentation: https://sharp.pixelplumbing.com/install'
28
- );
29
- // Check loaded
30
- if (process.platform === 'win32' || /symbol/.test(err.message)) {
31
- const loadedModule = Object.keys(require.cache).find((i) => /[\\/]build[\\/]Release[\\/]sharp(.*)\.node$/.test(i));
32
- if (loadedModule) {
33
- const [, loadedPackage] = loadedModule.match(/node_modules[\\/]([^\\/]+)[\\/]/);
34
- help.push(`- Ensure the version of sharp aligns with the ${loadedPackage} package: "npm ls sharp"`);
26
+ if (errPackage.code !== 'MODULE_NOT_FOUND') {
27
+ help.push(`${errPackage.code}: ${errPackage.message}`);
28
+ }
29
+ help.push('Possible solutions:');
30
+ // Common error messages
31
+ if (prebuiltPlatforms.includes(runtimePlatform)) {
32
+ help.push(`- Add an explicit dependency for the runtime platform: "npm install --force @sharpen/sharp-${runtimePlatform}"`);
33
+ } else {
34
+ help.push(`- The ${runtimePlatform} platform requires manual installation of libvips >= ${minimumLibvipsVersion}`);
35
+ }
36
+ if (runtimePlatform.startsWith('linux') && /symbol not found/i.test(errPackage)) {
37
+ try {
38
+ const { engines } = require(`@sharpen/sharp-libvips-${runtimePlatform}/package`);
39
+ const libcFound = `${familySync()} ${versionSync()}`;
40
+ const libcRequires = `${engines.musl ? 'musl' : 'glibc'} ${engines.musl || engines.glibc}`;
41
+ help.push(`- Update your OS: found ${libcFound}, requires ${libcRequires}`);
42
+ } catch (errEngines) {}
43
+ }
44
+ if (runtimePlatform.startsWith('darwin') && /Incompatible library version/.test(errLocal.message)) {
45
+ help.push('- Update Homebrew: "brew update && brew upgrade vips"');
46
+ }
47
+ if (errPackage.code === 'ERR_DLOPEN_DISABLED') {
48
+ help.push('- Run Node.js without using the --no-addons flag');
49
+ }
50
+ // Link to installation docs
51
+ if (runtimePlatform.startsWith('linux') && /Module did not self-register/.test(errLocal.message + errPackage.message)) {
52
+ help.push('- Using worker threads on Linux? See https://sharp.pixelplumbing.com/install#worker-threads');
53
+ } else if (runtimePlatform.startsWith('win32') && /The specified procedure could not be found/.test(errPackage.message)) {
54
+ help.push('- Using the canvas package on Windows? See https://sharp.pixelplumbing.com/install#canvas-and-windows');
55
+ } else {
56
+ help.push('- Consult the installation documentation: https://sharp.pixelplumbing.com/install');
35
57
  }
58
+ throw new Error(help.join('\n'));
36
59
  }
37
- throw new Error(help.join('\n'));
38
60
  }