sharp 0.30.3 → 0.30.6

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.
@@ -35,6 +35,7 @@ const hasSharpPrebuild = [
35
35
  ];
36
36
 
37
37
  const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
38
+ const localLibvipsDir = process.env.npm_config_sharp_libvips_local_prebuilds || '';
38
39
  const distHost = process.env.npm_config_sharp_libvips_binary_host || 'https://github.com/lovell/sharp-libvips/releases/download';
39
40
  const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `${distHost}/v${minimumLibvipsVersionLabelled}/`;
40
41
  const installationForced = !!(process.env.npm_config_sharp_install_force || process.env.SHARP_INSTALL_FORCE);
@@ -42,7 +43,9 @@ const installationForced = !!(process.env.npm_config_sharp_install_force || proc
42
43
  const fail = function (err) {
43
44
  libvips.log(err);
44
45
  if (err.code === 'EACCES') {
45
- libvips.log('Are you trying to install as a root or sudo user? Try again with the --unsafe-perm flag');
46
+ libvips.log('Are you trying to install as a root or sudo user?');
47
+ libvips.log('- For npm <= v6, try again with the "--unsafe-perm" flag');
48
+ libvips.log('- For npm >= v8, the user must own the directory "npm install" is run in');
46
49
  }
47
50
  libvips.log('Please see https://sharp.pixelplumbing.com/install for required dependencies');
48
51
  process.exit(1);
@@ -156,6 +159,11 @@ try {
156
159
  if (fs.existsSync(tarPathCache)) {
157
160
  libvips.log(`Using cached ${tarPathCache}`);
158
161
  extractTarball(tarPathCache, platformAndArch);
162
+ } else if (localLibvipsDir) {
163
+ // If localLibvipsDir is given try to use binaries from local directory
164
+ const tarPathLocal = path.join(path.resolve(localLibvipsDir), `v${minimumLibvipsVersionLabelled}`, tarFilename);
165
+ libvips.log(`Using local libvips from ${tarPathLocal}`);
166
+ extractTarball(tarPathLocal, platformAndArch);
159
167
  } else {
160
168
  const url = distBaseUrl + tarFilename;
161
169
  libvips.log(`Downloading ${url}`);
package/lib/composite.js CHANGED
@@ -50,7 +50,7 @@ const blend = {
50
50
  * `hard-light`, `soft-light`, `difference`, `exclusion`.
51
51
  *
52
52
  * More information about blend modes can be found at
53
- * https://libvips.github.io/libvips/API/current/libvips-conversion.html#VipsBlendMode
53
+ * https://www.libvips.org/API/current/libvips-conversion.html#VipsBlendMode
54
54
  * and https://www.cairographics.org/operators/
55
55
  *
56
56
  * @since 0.22.0
@@ -105,7 +105,7 @@ const blend = {
105
105
  * @param {Number} [images[].raw.height]
106
106
  * @param {Number} [images[].raw.channels]
107
107
  * @param {boolean} [images[].animated=false] - Set to `true` to read all frames/pages of an animated image.
108
- * @param {boolean} [images[].failOnError=true] - @see {@link /api-constructor#parameters|constructor parameters}
108
+ * @param {string} [images[].failOn='warning'] - @see {@link /api-constructor#parameters|constructor parameters}
109
109
  * @param {number|boolean} [images[].limitInputPixels=268402689] - @see {@link /api-constructor#parameters|constructor parameters}
110
110
  * @returns {Sharp}
111
111
  * @throws {Error} Invalid parameters
@@ -98,8 +98,7 @@ const debuglog = util.debuglog('sharp');
98
98
  * a String containing the filesystem path to an JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image file.
99
99
  * JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
100
100
  * @param {Object} [options] - if present, is an Object with optional attributes.
101
- * @param {boolean} [options.failOnError=true] - by default halt processing and raise an error when loading invalid images.
102
- * Set this flag to `false` if you'd rather apply a "best effort" to decode images, even if the data is corrupt or invalid.
101
+ * @param {string} [options.failOn='warning'] - level of sensitivity to invalid images, one of (in order of sensitivity): 'none' (least), 'truncated', 'error' or 'warning' (most), highers level imply lower levels.
103
102
  * @param {number|boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
104
103
  * (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
105
104
  * An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
@@ -320,9 +319,7 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
320
319
  * // Using Promises to know when the pipeline is complete
321
320
  * const fs = require("fs");
322
321
  * const got = require("got");
323
- * const sharpStream = sharp({
324
- * failOnError: false
325
- * });
322
+ * const sharpStream = sharp({ failOn: 'none' });
326
323
  *
327
324
  * const promises = [];
328
325
  *
package/lib/input.js CHANGED
@@ -9,9 +9,9 @@ const sharp = require('./sharp');
9
9
  * @private
10
10
  */
11
11
  function _inputOptionsFromObject (obj) {
12
- const { raw, density, limitInputPixels, unlimited, sequentialRead, failOnError, animated, page, pages, subifd } = obj;
13
- return [raw, density, limitInputPixels, unlimited, sequentialRead, failOnError, animated, page, pages, subifd].some(is.defined)
14
- ? { raw, density, limitInputPixels, unlimited, sequentialRead, failOnError, animated, page, pages, subifd }
12
+ const { raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd } = obj;
13
+ return [raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd].some(is.defined)
14
+ ? { raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd }
15
15
  : undefined;
16
16
  }
17
17
 
@@ -21,7 +21,7 @@ function _inputOptionsFromObject (obj) {
21
21
  */
22
22
  function _createInputDescriptor (input, inputOptions, containerOptions) {
23
23
  const inputDescriptor = {
24
- failOnError: true,
24
+ failOn: 'warning',
25
25
  limitInputPixels: Math.pow(0x3FFF, 2),
26
26
  unlimited: false,
27
27
  sequentialRead: false
@@ -39,7 +39,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
39
39
  if (input.length === 0) {
40
40
  throw Error('Input Bit Array is empty');
41
41
  }
42
- inputDescriptor.buffer = Buffer.from(input.buffer);
42
+ inputDescriptor.buffer = Buffer.from(input.buffer, input.byteOffset, input.byteLength);
43
43
  } else if (is.plainObject(input) && !is.defined(inputOptions)) {
44
44
  // Plain Object descriptor, e.g. create
45
45
  inputOptions = input;
@@ -56,14 +56,22 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
56
56
  }`);
57
57
  }
58
58
  if (is.object(inputOptions)) {
59
- // Fail on error
59
+ // Deprecated: failOnError
60
60
  if (is.defined(inputOptions.failOnError)) {
61
61
  if (is.bool(inputOptions.failOnError)) {
62
- inputDescriptor.failOnError = inputOptions.failOnError;
62
+ inputDescriptor.failOn = inputOptions.failOnError ? 'warning' : 'none';
63
63
  } else {
64
64
  throw is.invalidParameterError('failOnError', 'boolean', inputOptions.failOnError);
65
65
  }
66
66
  }
67
+ // failOn
68
+ if (is.defined(inputOptions.failOn)) {
69
+ if (is.string(inputOptions.failOn) && is.inArray(inputOptions.failOn, ['none', 'truncated', 'error', 'warning'])) {
70
+ inputDescriptor.failOn = inputOptions.failOn;
71
+ } else {
72
+ throw is.invalidParameterError('failOn', 'one of: none, truncated, error, warning', inputOptions.failOn);
73
+ }
74
+ }
67
75
  // Density
68
76
  if (is.defined(inputOptions.density)) {
69
77
  if (is.inRange(inputOptions.density, 1, 100000)) {
@@ -78,10 +86,10 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
78
86
  inputDescriptor.limitInputPixels = inputOptions.limitInputPixels
79
87
  ? Math.pow(0x3FFF, 2)
80
88
  : 0;
81
- } else if (is.integer(inputOptions.limitInputPixels) && inputOptions.limitInputPixels >= 0) {
89
+ } else if (is.integer(inputOptions.limitInputPixels) && is.inRange(inputOptions.limitInputPixels, 0, Number.MAX_SAFE_INTEGER)) {
82
90
  inputDescriptor.limitInputPixels = inputOptions.limitInputPixels;
83
91
  } else {
84
- throw is.invalidParameterError('limitInputPixels', 'integer >= 0', inputOptions.limitInputPixels);
92
+ throw is.invalidParameterError('limitInputPixels', 'positive integer', inputOptions.limitInputPixels);
85
93
  }
86
94
  }
87
95
  // unlimited
@@ -301,9 +309,9 @@ function _isStreamInput () {
301
309
  * - `size`: Total size of image in bytes, for Stream and Buffer input only
302
310
  * - `width`: Number of pixels wide (EXIF orientation is not taken into consideration, see example below)
303
311
  * - `height`: Number of pixels high (EXIF orientation is not taken into consideration, see example below)
304
- * - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsInterpretation)
312
+ * - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://www.libvips.org/API/current/VipsImage.html#VipsInterpretation)
305
313
  * - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
306
- * - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsBandFormat)
314
+ * - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://www.libvips.org/API/current/VipsImage.html#VipsBandFormat)
307
315
  * - `density`: Number of pixels per inch (DPI), if present
308
316
  * - `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
309
317
  * - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
package/lib/libvips.js CHANGED
@@ -65,7 +65,13 @@ const isRosetta = function () {
65
65
 
66
66
  const globalLibvipsVersion = function () {
67
67
  if (process.platform !== 'win32') {
68
- const globalLibvipsVersion = spawnSync(`PKG_CONFIG_PATH="${pkgConfigPath()}" pkg-config --modversion vips-cpp`, spawnSyncOptions).stdout;
68
+ const globalLibvipsVersion = spawnSync('pkg-config --modversion vips-cpp', {
69
+ ...spawnSyncOptions,
70
+ env: {
71
+ ...env,
72
+ PKG_CONFIG_PATH: pkgConfigPath()
73
+ }
74
+ }).stdout;
69
75
  /* istanbul ignore next */
70
76
  return (globalLibvipsVersion || '').trim();
71
77
  } else {
@@ -85,7 +91,10 @@ const removeVendoredLibvips = function () {
85
91
 
86
92
  const pkgConfigPath = function () {
87
93
  if (process.platform !== 'win32') {
88
- const brewPkgConfigPath = spawnSync('which brew >/dev/null 2>&1 && eval $(brew --env) && echo $PKG_CONFIG_LIBDIR', spawnSyncOptions).stdout || '';
94
+ const brewPkgConfigPath = spawnSync(
95
+ 'which brew >/dev/null 2>&1 && brew environment --plain | grep PKG_CONFIG_LIBDIR | cut -d" " -f2',
96
+ spawnSyncOptions
97
+ ).stdout || '';
89
98
  return [
90
99
  brewPkgConfigPath.trim(),
91
100
  env.PKG_CONFIG_PATH,
package/lib/operation.js CHANGED
@@ -420,6 +420,17 @@ function gamma (gamma, gammaOut) {
420
420
 
421
421
  /**
422
422
  * Produce the "negative" of the image.
423
+ *
424
+ * @example
425
+ * const output = await sharp(input)
426
+ * .negate()
427
+ * .toBuffer();
428
+ *
429
+ * @example
430
+ * const output = await sharp(input)
431
+ * .negate({ alpha: false })
432
+ * .toBuffer();
433
+ *
423
434
  * @param {Object} [options]
424
435
  * @param {Boolean} [options.alpha=true] Whether or not to negate any alpha channel
425
436
  * @returns {Sharp}
package/lib/output.js CHANGED
@@ -82,6 +82,8 @@ function toFile (fileOut, callback) {
82
82
  * Write output to a Buffer.
83
83
  * JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
84
84
  *
85
+ * Use {@link toFormat} or one of the format-specific functions such as {@link jpeg}, {@link png} etc. to set the output format.
86
+ *
85
87
  * If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.
86
88
  *
87
89
  * By default all metadata will be removed, which includes EXIF-based orientation.
@@ -108,6 +110,7 @@ function toFile (fileOut, callback) {
108
110
  *
109
111
  * @example
110
112
  * sharp(input)
113
+ * .png()
111
114
  * .toBuffer({ resolveWithObject: true })
112
115
  * .then(({ data, info }) => { ... })
113
116
  * .catch(err => { ... });
@@ -151,6 +154,8 @@ function toBuffer (options, callback) {
151
154
  * The default behaviour, when `withMetadata` is not used, is to convert to the device-independent
152
155
  * sRGB colour space and strip all metadata, including the removal of any ICC profile.
153
156
  *
157
+ * EXIF metadata is unsupported for TIFF output.
158
+ *
154
159
  * @example
155
160
  * sharp('input.jpg')
156
161
  * .withMetadata()
@@ -514,7 +519,7 @@ function webp (options) {
514
519
  * // Convert PNG to GIF
515
520
  * await sharp(pngBuffer)
516
521
  * .gif()
517
- * .toBuffer());
522
+ * .toBuffer();
518
523
  *
519
524
  * @example
520
525
  * // Convert animated WebP to animated GIF
package/lib/platform.js CHANGED
@@ -7,10 +7,12 @@ const env = process.env;
7
7
  module.exports = function () {
8
8
  const arch = env.npm_config_arch || process.arch;
9
9
  const platform = env.npm_config_platform || process.platform;
10
- /* istanbul ignore next */
11
- const libc = (platform === 'linux' && detectLibc.isNonGlibcLinuxSync()) ? detectLibc.familySync() : '';
10
+ const libc = process.env.npm_config_libc ||
11
+ /* istanbul ignore next */
12
+ (detectLibc.isNonGlibcLinuxSync() ? detectLibc.familySync() : '');
13
+ const libcId = platform !== 'linux' || libc === detectLibc.GLIBC ? '' : libc;
12
14
 
13
- const platformId = [`${platform}${libc}`];
15
+ const platformId = [`${platform}${libcId}`];
14
16
 
15
17
  if (arch === 'arm') {
16
18
  const fallback = process.versions.electron ? '7' : '6';
package/lib/sharp.js CHANGED
@@ -13,7 +13,7 @@ try {
13
13
  } else {
14
14
  const [platform, arch] = platformAndArch.split('-');
15
15
  help.push(
16
- '- Install with the --verbose flag and look for errors: "npm install --ignore-scripts=false --verbose sharp"',
16
+ '- Install with verbose logging and look for errors: "npm install --ignore-scripts=false --foreground-scripts --verbose sharp"',
17
17
  `- Install for the current ${platformAndArch} runtime: "npm install --platform=${platform} --arch=${arch} sharp"`
18
18
  );
19
19
  }
package/lib/utility.js CHANGED
@@ -103,7 +103,11 @@ cache(true);
103
103
 
104
104
  /**
105
105
  * Gets or, when a concurrency is provided, sets
106
- * the number of threads _libvips'_ should create to process each image.
106
+ * the maximum number of threads _libvips_ should use to process _each image_.
107
+ * These are from a thread pool managed by glib,
108
+ * which helps avoid the overhead of creating new threads.
109
+ *
110
+ * This method always returns the current concurrency.
107
111
  *
108
112
  * The default value is the number of CPU cores,
109
113
  * except when using glibc-based Linux without jemalloc,
@@ -111,10 +115,19 @@ cache(true);
111
115
  *
112
116
  * A value of `0` will reset this to the number of CPU cores.
113
117
  *
114
- * The maximum number of images that can be processed in parallel
115
- * is limited by libuv's `UV_THREADPOOL_SIZE` environment variable.
118
+ * Some image format libraries spawn additional threads,
119
+ * e.g. libaom manages its own 4 threads when encoding AVIF images,
120
+ * and these are independent of the value set here.
116
121
  *
117
- * This method always returns the current concurrency.
122
+ * The maximum number of images that sharp can process in parallel
123
+ * is controlled by libuv's `UV_THREADPOOL_SIZE` environment variable,
124
+ * which defaults to 4.
125
+ *
126
+ * https://nodejs.org/api/cli.html#uv_threadpool_sizesize
127
+ *
128
+ * For example, by default, a machine with 8 CPU cores will process
129
+ * 4 images in parallel and use up to 8 threads per image,
130
+ * so there will be up to 32 concurrent threads.
118
131
  *
119
132
  * @example
120
133
  * const threads = sharp.concurrency(); // 4
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, GIF, AVIF and TIFF images",
4
- "version": "0.30.3",
4
+ "version": "0.30.6",
5
5
  "author": "Lovell Fuller <npm@lovell.info>",
6
6
  "homepage": "https://github.com/lovell/sharp",
7
7
  "contributors": [
@@ -81,7 +81,9 @@
81
81
  "Taneli Vatanen <taneli.vatanen@gmail.com>",
82
82
  "Joris Dugué <zaruike10@gmail.com>",
83
83
  "Chris Banks <christopher.bradley.banks@gmail.com>",
84
- "Ompal Singh <ompal.hitm09@gmail.com>"
84
+ "Ompal Singh <ompal.hitm09@gmail.com>",
85
+ "Brodan <christopher.hranj@gmail.com",
86
+ "Ankur Parihar <ankur.github@gmail.com>"
85
87
  ],
86
88
  "scripts": {
87
89
  "install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild && node install/dll-copy)",
@@ -126,11 +128,11 @@
126
128
  "vips"
127
129
  ],
128
130
  "dependencies": {
129
- "color": "^4.2.1",
131
+ "color": "^4.2.3",
130
132
  "detect-libc": "^2.0.1",
131
- "node-addon-api": "^4.3.0",
132
- "prebuild-install": "^7.0.1",
133
- "semver": "^7.3.5",
133
+ "node-addon-api": "^5.0.0",
134
+ "prebuild-install": "^7.1.0",
135
+ "semver": "^7.3.7",
134
136
  "simple-get": "^4.0.1",
135
137
  "tar-fs": "^2.1.1",
136
138
  "tunnel-agent": "^0.6.0"
@@ -143,7 +145,7 @@
143
145
  "exif-reader": "^1.0.3",
144
146
  "icc": "^2.0.0",
145
147
  "license-checker": "^25.0.1",
146
- "mocha": "^9.2.2",
148
+ "mocha": "^10.0.0",
147
149
  "mock-fs": "^5.1.2",
148
150
  "nyc": "^15.1.0",
149
151
  "prebuild": "^11.0.3",
package/src/common.cc CHANGED
@@ -48,6 +48,9 @@ namespace sharp {
48
48
  int32_t AttrAsInt32(Napi::Object obj, unsigned int const attr) {
49
49
  return obj.Get(attr).As<Napi::Number>().Int32Value();
50
50
  }
51
+ int64_t AttrAsInt64(Napi::Object obj, std::string attr) {
52
+ return obj.Get(attr).As<Napi::Number>().Int64Value();
53
+ }
51
54
  double AttrAsDouble(Napi::Object obj, std::string attr) {
52
55
  return obj.Get(attr).As<Napi::Number>().DoubleValue();
53
56
  }
@@ -85,7 +88,9 @@ namespace sharp {
85
88
  descriptor->buffer = buffer.Data();
86
89
  descriptor->isBuffer = TRUE;
87
90
  }
88
- descriptor->failOnError = AttrAsBool(input, "failOnError");
91
+ descriptor->failOn = static_cast<VipsFailOn>(
92
+ vips_enum_from_nick(nullptr, VIPS_TYPE_FAIL_ON,
93
+ AttrAsStr(input, "failOn").data()));
89
94
  // Density for vector-based input
90
95
  if (HasAttr(input, "density")) {
91
96
  descriptor->density = AttrAsDouble(input, "density");
@@ -129,7 +134,7 @@ namespace sharp {
129
134
  }
130
135
  }
131
136
  // Limit input images to a given number of pixels, where pixels = width * height
132
- descriptor->limitInputPixels = AttrAsUint32(input, "limitInputPixels");
137
+ descriptor->limitInputPixels = static_cast<uint64_t>(AttrAsInt64(input, "limitInputPixels"));
133
138
  // Allow switch from random to sequential access
134
139
  descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
135
140
  // Remove safety features and allow unlimited SVG/PNG input
@@ -329,7 +334,7 @@ namespace sharp {
329
334
  try {
330
335
  vips::VOption *option = VImage::option()
331
336
  ->set("access", descriptor->access)
332
- ->set("fail", descriptor->failOnError);
337
+ ->set("fail_on", descriptor->failOn);
333
338
  if (descriptor->unlimited && (imageType == ImageType::SVG || imageType == ImageType::PNG)) {
334
339
  option->set("unlimited", TRUE);
335
340
  }
@@ -375,12 +380,6 @@ namespace sharp {
375
380
  VImage::option()->set("mean", descriptor->createNoiseMean)->set("sigma", descriptor->createNoiseSigma)));
376
381
  }
377
382
  image = image.bandjoin(bands);
378
- image = image.cast(VipsBandFormat::VIPS_FORMAT_UCHAR);
379
- if (channels < 3) {
380
- image = image.colourspace(VIPS_INTERPRETATION_B_W);
381
- } else {
382
- image = image.colourspace(VIPS_INTERPRETATION_sRGB);
383
- }
384
383
  } else {
385
384
  std::vector<double> background = {
386
385
  descriptor->createBackground[0],
@@ -392,7 +391,8 @@ namespace sharp {
392
391
  }
393
392
  image = VImage::new_matrix(descriptor->createWidth, descriptor->createHeight).new_from_image(background);
394
393
  }
395
- image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
394
+ image.get_image()->Type = image.guess_interpretation();
395
+ image = image.cast(VIPS_FORMAT_UCHAR);
396
396
  imageType = ImageType::RAW;
397
397
  } else {
398
398
  // From filesystem
@@ -402,13 +402,13 @@ namespace sharp {
402
402
  throw vips::VError("Input file is missing, did you mean "
403
403
  "sharp(Buffer.from('" + descriptor->file.substr(0, 8) + "...')?");
404
404
  }
405
- throw vips::VError("Input file is missing");
405
+ throw vips::VError("Input file is missing: " + descriptor->file);
406
406
  }
407
407
  if (imageType != ImageType::UNKNOWN) {
408
408
  try {
409
409
  vips::VOption *option = VImage::option()
410
410
  ->set("access", descriptor->access)
411
- ->set("fail", descriptor->failOnError);
411
+ ->set("fail_on", descriptor->failOn);
412
412
  if (descriptor->unlimited && (imageType == ImageType::SVG || imageType == ImageType::PNG)) {
413
413
  option->set("unlimited", TRUE);
414
414
  }
@@ -442,7 +442,7 @@ namespace sharp {
442
442
  }
443
443
  // Limit input images to a given number of pixels, where pixels = width * height
444
444
  if (descriptor->limitInputPixels > 0 &&
445
- static_cast<uint64_t>(image.width() * image.height()) > static_cast<uint64_t>(descriptor->limitInputPixels)) {
445
+ static_cast<uint64_t>(image.width() * image.height()) > descriptor->limitInputPixels) {
446
446
  throw vips::VError("Input image exceeds pixel limit");
447
447
  }
448
448
  return std::make_tuple(image, imageType);
package/src/common.h CHANGED
@@ -48,8 +48,8 @@ namespace sharp {
48
48
  std::string name;
49
49
  std::string file;
50
50
  char *buffer;
51
- bool failOnError;
52
- int limitInputPixels;
51
+ VipsFailOn failOn;
52
+ uint64_t limitInputPixels;
53
53
  bool unlimited;
54
54
  VipsAccess access;
55
55
  size_t bufferLength;
@@ -74,7 +74,7 @@ namespace sharp {
74
74
 
75
75
  InputDescriptor():
76
76
  buffer(nullptr),
77
- failOnError(TRUE),
77
+ failOn(VIPS_FAIL_ON_WARNING),
78
78
  limitInputPixels(0x3FFF * 0x3FFF),
79
79
  unlimited(FALSE),
80
80
  access(VIPS_ACCESS_RANDOM),
package/src/pipeline.cc CHANGED
@@ -95,16 +95,18 @@ class PipelineWorker : public Napi::AsyncWorker {
95
95
  if (baton->rotateBeforePreExtract) {
96
96
  if (rotation != VIPS_ANGLE_D0) {
97
97
  image = image.rot(rotation);
98
- if (flip) {
99
- image = image.flip(VIPS_DIRECTION_VERTICAL);
100
- flip = FALSE;
101
- }
102
- if (flop) {
103
- image = image.flip(VIPS_DIRECTION_HORIZONTAL);
104
- flop = FALSE;
105
- }
98
+ }
99
+ if (flip) {
100
+ image = image.flip(VIPS_DIRECTION_VERTICAL);
101
+ }
102
+ if (flop) {
103
+ image = image.flip(VIPS_DIRECTION_HORIZONTAL);
104
+ }
105
+ if (rotation != VIPS_ANGLE_D0 || flip || flop) {
106
106
  image = sharp::RemoveExifOrientation(image);
107
107
  }
108
+ flop = FALSE;
109
+ flip = FALSE;
108
110
  if (baton->rotationAngle != 0.0) {
109
111
  MultiPageUnsupported(nPages, "Rotate");
110
112
  std::vector<double> background;
@@ -200,7 +202,7 @@ class PipelineWorker : public Napi::AsyncWorker {
200
202
  vips::VOption *option = VImage::option()
201
203
  ->set("access", baton->input->access)
202
204
  ->set("shrink", jpegShrinkOnLoad)
203
- ->set("fail", baton->input->failOnError);
205
+ ->set("fail_on", baton->input->failOn);
204
206
  if (baton->input->buffer != nullptr) {
205
207
  // Reload JPEG buffer
206
208
  VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength);
@@ -214,7 +216,7 @@ class PipelineWorker : public Napi::AsyncWorker {
214
216
  vips::VOption *option = VImage::option()
215
217
  ->set("access", baton->input->access)
216
218
  ->set("scale", scale)
217
- ->set("fail", baton->input->failOnError);
219
+ ->set("fail_on", baton->input->failOn);
218
220
  if (inputImageType == sharp::ImageType::WEBP) {
219
221
  option->set("n", baton->input->pages);
220
222
  option->set("page", baton->input->page);
@@ -241,8 +243,10 @@ class PipelineWorker : public Napi::AsyncWorker {
241
243
  // Reload SVG file
242
244
  image = VImage::svgload(const_cast<char*>(baton->input->file.data()), option);
243
245
  }
244
-
245
246
  sharp::SetDensity(image, baton->input->density);
247
+ if (image.width() > 32767 || image.height() > 32767) {
248
+ throw vips::VError("Input SVG image will exceed 32767x32767 pixel limit when scaled");
249
+ }
246
250
  } else if (inputImageType == sharp::ImageType::PDF) {
247
251
  option->set("n", baton->input->pages);
248
252
  option->set("page", baton->input->page);
@@ -260,6 +264,10 @@ class PipelineWorker : public Napi::AsyncWorker {
260
264
 
261
265
  sharp::SetDensity(image, baton->input->density);
262
266
  }
267
+ } else {
268
+ if (inputImageType == sharp::ImageType::SVG && (image.width() > 32767 || image.height() > 32767)) {
269
+ throw vips::VError("Input SVG image exceeds 32767x32767 pixel limit");
270
+ }
263
271
  }
264
272
 
265
273
  // Any pre-shrinking may already have been done