sharp 0.35.0-rc.4 → 0.35.0-rc.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.
@@ -125,6 +125,7 @@ const blend = {
125
125
  * @param {boolean} [images[].animated=false] - Set to `true` to read all frames/pages of an animated image.
126
126
  * @param {string} [images[].failOn='warning'] - @see {@link /api-constructor/ constructor parameters}
127
127
  * @param {number|boolean} [images[].limitInputPixels=268402689] - @see {@link /api-constructor/ constructor parameters}
128
+ * @param {number|boolean} [images[].limitInputChannels=5] - @see {@link /api-constructor/ constructor parameters}
128
129
  * @returns {Sharp}
129
130
  * @throws {Error} Invalid parameters
130
131
  */
@@ -125,6 +125,7 @@ const blend = {
125
125
  * @param {boolean} [images[].animated=false] - Set to `true` to read all frames/pages of an animated image.
126
126
  * @param {string} [images[].failOn='warning'] - @see {@link /api-constructor/ constructor parameters}
127
127
  * @param {number|boolean} [images[].limitInputPixels=268402689] - @see {@link /api-constructor/ constructor parameters}
128
+ * @param {number|boolean} [images[].limitInputChannels=5] - @see {@link /api-constructor/ constructor parameters}
128
129
  * @returns {Sharp}
129
130
  * @throws {Error} Invalid parameters
130
131
  */
@@ -48,7 +48,7 @@ const queueListener = (queueLength) => {
48
48
  * // resize to 300 pixels wide,
49
49
  * // emit an 'info' event with calculated dimensions
50
50
  * // and finally write image data to writableStream
51
- * const { body } = fetch('https://...');
51
+ * const { body } = await fetch('https://...');
52
52
  * const readableStream = Readable.fromWeb(body);
53
53
  * const transformer = sharp()
54
54
  * .resize(300)
@@ -58,6 +58,17 @@ const queueListener = (queueLength) => {
58
58
  * readableStream.pipe(transformer).pipe(writableStream);
59
59
  *
60
60
  * @example
61
+ * // Web Streams API, requires Node.js >= 24.15.0
62
+ * const { Duplex } = require('node:stream');
63
+ *
64
+ * const { body } = await fetch('https://...');
65
+ * const transformer = Duplex.toWeb(
66
+ * sharp().resize(300),
67
+ * { readableType: 'bytes' }
68
+ * );
69
+ * body.pipeThrough(transformer).pipeTo(writable);
70
+ *
71
+ * @example
61
72
  * // Create a blank 300x200 PNG image of semi-translucent red pixels
62
73
  * sharp({
63
74
  * create: {
@@ -146,10 +157,12 @@ const queueListener = (queueLength) => {
146
157
  * An array of inputs can be provided, and these will be joined together.
147
158
  * JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
148
159
  * @param {Object} [options] - if present, is an Object with optional attributes.
149
- * @param {string} [options.failOn='warning'] - When to abort processing of invalid pixel data, one of (in order of sensitivity, least to most): 'none', 'truncated', 'error', 'warning'. Higher levels imply lower levels. Invalid metadata will always abort.
160
+ * @param {string} [options.failOn='warning'] - When to abort processing of invalid pixel data, one of (in order of sensitivity, least to most): 'none', 'truncated', 'error', 'warning'. Higher levels imply lower levels. Invalid metadata will always abort. Use the default 'warning' level with untrusted input.
150
161
  * @param {number|boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
151
162
  * (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
152
163
  * An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
164
+ * @param {number|boolean} [options.limitInputChannels=5] - Do not process input images where the number of channels exceeds this limit. Assumes image metadata can be trusted.
165
+ * An integral Number of channels, zero or false to remove limit, true to use default limit of 5.
153
166
  * @param {boolean} [options.unlimited=false] - Set this to `true` to remove safety features that help prevent memory exhaustion (JPEG, PNG, SVG, HEIF).
154
167
  * @param {boolean} [options.autoOrient=false] - Set this to `true` to rotate/flip the image to match EXIF `Orientation`, if any.
155
168
  * @param {boolean} [options.sequentialRead=true] - Set this to `false` to use random access rather than sequential read. Some operations will do this automatically.
@@ -380,7 +393,7 @@ const Sharp = function (input, options) {
380
393
  heifEffort: 4,
381
394
  heifChromaSubsampling: '4:4:4',
382
395
  heifBitdepth: 8,
383
- heifTune: 'ssim',
396
+ heifTune: 'auto',
384
397
  jxlDistance: 1,
385
398
  jxlDecodingTier: 0,
386
399
  jxlEffort: 7,
@@ -422,29 +435,33 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
422
435
  * This allows multiple output Streams and therefore multiple processing pipelines to share a single input Stream.
423
436
  *
424
437
  * @example
425
- * const pipeline = sharp().rotate();
426
- * pipeline.clone().resize(800, 600).pipe(firstWritableStream);
427
- * pipeline.clone().extract({ left: 20, top: 20, width: 100, height: 100 }).pipe(secondWritableStream);
428
- * readableStream.pipe(pipeline);
429
438
  * // firstWritableStream receives auto-rotated, resized readableStream
430
439
  * // secondWritableStream receives auto-rotated, extracted region of readableStream
431
440
  *
441
+ * const pipeline = sharp().rotate();
442
+ * pipeline
443
+ * .clone()
444
+ * .resize(800, 600)
445
+ * .pipe(firstWritableStream);
446
+ * pipeline
447
+ * .clone()
448
+ * .extract({ left: 20, top: 20, width: 100, height: 100 })
449
+ * .pipe(secondWritableStream);
450
+ * readableStream.pipe(pipeline);
451
+ *
432
452
  * @example
433
453
  * // Create a pipeline that will download an image, resize it and format it to different files
434
454
  * // Using Promises to know when the pipeline is complete
435
- * const fs = require("node:fs");
436
- * const got = require("got");
437
- * const sharpStream = sharp({ failOn: 'none' });
438
455
  *
439
- * const promises = [];
456
+ * const sharpStream = sharp();
440
457
  *
458
+ * const promises = [];
441
459
  * promises.push(
442
460
  * sharpStream
443
461
  * .clone()
444
462
  * .jpeg({ quality: 100 })
445
463
  * .toFile("originalFile.jpg")
446
464
  * );
447
- *
448
465
  * promises.push(
449
466
  * sharpStream
450
467
  * .clone()
@@ -452,7 +469,6 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
452
469
  * .jpeg({ quality: 80 })
453
470
  * .toFile("optimized-500.jpg")
454
471
  * );
455
- *
456
472
  * promises.push(
457
473
  * sharpStream
458
474
  * .clone()
@@ -461,19 +477,9 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
461
477
  * .toFile("optimized-500.webp")
462
478
  * );
463
479
  *
464
- * // https://github.com/sindresorhus/got/blob/main/documentation/3-streams.md
465
- * got.stream("https://www.example.com/some-file.jpg").pipe(sharpStream);
466
- *
467
- * Promise.all(promises)
468
- * .then(res => { console.log("Done!", res); })
469
- * .catch(err => {
470
- * console.error("Error processing files, let's clean it up", err);
471
- * try {
472
- * fs.unlinkSync("originalFile.jpg");
473
- * fs.unlinkSync("optimized-500.jpg");
474
- * fs.unlinkSync("optimized-500.webp");
475
- * } catch (e) {}
476
- * });
480
+ * const res = await fetch("https://www.example.com/some-file.jpg")
481
+ * Readable.fromWeb(res.body).pipe(sharpStream);
482
+ * await Promise.all(promises);
477
483
  *
478
484
  * @returns {Sharp}
479
485
  */
@@ -48,7 +48,7 @@ const queueListener = (queueLength) => {
48
48
  * // resize to 300 pixels wide,
49
49
  * // emit an 'info' event with calculated dimensions
50
50
  * // and finally write image data to writableStream
51
- * const { body } = fetch('https://...');
51
+ * const { body } = await fetch('https://...');
52
52
  * const readableStream = Readable.fromWeb(body);
53
53
  * const transformer = sharp()
54
54
  * .resize(300)
@@ -58,6 +58,17 @@ const queueListener = (queueLength) => {
58
58
  * readableStream.pipe(transformer).pipe(writableStream);
59
59
  *
60
60
  * @example
61
+ * // Web Streams API, requires Node.js >= 24.15.0
62
+ * import { Duplex } from 'node:stream';
63
+ *
64
+ * const { body } = await fetch('https://...');
65
+ * const transformer = Duplex.toWeb(
66
+ * sharp().resize(300),
67
+ * { readableType: 'bytes' }
68
+ * );
69
+ * body.pipeThrough(transformer).pipeTo(writable);
70
+ *
71
+ * @example
61
72
  * // Create a blank 300x200 PNG image of semi-translucent red pixels
62
73
  * sharp({
63
74
  * create: {
@@ -146,10 +157,12 @@ const queueListener = (queueLength) => {
146
157
  * An array of inputs can be provided, and these will be joined together.
147
158
  * JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
148
159
  * @param {Object} [options] - if present, is an Object with optional attributes.
149
- * @param {string} [options.failOn='warning'] - When to abort processing of invalid pixel data, one of (in order of sensitivity, least to most): 'none', 'truncated', 'error', 'warning'. Higher levels imply lower levels. Invalid metadata will always abort.
160
+ * @param {string} [options.failOn='warning'] - When to abort processing of invalid pixel data, one of (in order of sensitivity, least to most): 'none', 'truncated', 'error', 'warning'. Higher levels imply lower levels. Invalid metadata will always abort. Use the default 'warning' level with untrusted input.
150
161
  * @param {number|boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
151
162
  * (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
152
163
  * An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
164
+ * @param {number|boolean} [options.limitInputChannels=5] - Do not process input images where the number of channels exceeds this limit. Assumes image metadata can be trusted.
165
+ * An integral Number of channels, zero or false to remove limit, true to use default limit of 5.
153
166
  * @param {boolean} [options.unlimited=false] - Set this to `true` to remove safety features that help prevent memory exhaustion (JPEG, PNG, SVG, HEIF).
154
167
  * @param {boolean} [options.autoOrient=false] - Set this to `true` to rotate/flip the image to match EXIF `Orientation`, if any.
155
168
  * @param {boolean} [options.sequentialRead=true] - Set this to `false` to use random access rather than sequential read. Some operations will do this automatically.
@@ -380,7 +393,7 @@ const Sharp = function (input, options) {
380
393
  heifEffort: 4,
381
394
  heifChromaSubsampling: '4:4:4',
382
395
  heifBitdepth: 8,
383
- heifTune: 'ssim',
396
+ heifTune: 'auto',
384
397
  jxlDistance: 1,
385
398
  jxlDecodingTier: 0,
386
399
  jxlEffort: 7,
@@ -422,29 +435,33 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
422
435
  * This allows multiple output Streams and therefore multiple processing pipelines to share a single input Stream.
423
436
  *
424
437
  * @example
425
- * const pipeline = sharp().rotate();
426
- * pipeline.clone().resize(800, 600).pipe(firstWritableStream);
427
- * pipeline.clone().extract({ left: 20, top: 20, width: 100, height: 100 }).pipe(secondWritableStream);
428
- * readableStream.pipe(pipeline);
429
438
  * // firstWritableStream receives auto-rotated, resized readableStream
430
439
  * // secondWritableStream receives auto-rotated, extracted region of readableStream
431
440
  *
441
+ * const pipeline = sharp().rotate();
442
+ * pipeline
443
+ * .clone()
444
+ * .resize(800, 600)
445
+ * .pipe(firstWritableStream);
446
+ * pipeline
447
+ * .clone()
448
+ * .extract({ left: 20, top: 20, width: 100, height: 100 })
449
+ * .pipe(secondWritableStream);
450
+ * readableStream.pipe(pipeline);
451
+ *
432
452
  * @example
433
453
  * // Create a pipeline that will download an image, resize it and format it to different files
434
454
  * // Using Promises to know when the pipeline is complete
435
- * import fs from "node:fs";
436
- * import got from "got";
437
- * const sharpStream = sharp({ failOn: 'none' });
438
455
  *
439
- * const promises = [];
456
+ * const sharpStream = sharp();
440
457
  *
458
+ * const promises = [];
441
459
  * promises.push(
442
460
  * sharpStream
443
461
  * .clone()
444
462
  * .jpeg({ quality: 100 })
445
463
  * .toFile("originalFile.jpg")
446
464
  * );
447
- *
448
465
  * promises.push(
449
466
  * sharpStream
450
467
  * .clone()
@@ -452,7 +469,6 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
452
469
  * .jpeg({ quality: 80 })
453
470
  * .toFile("optimized-500.jpg")
454
471
  * );
455
- *
456
472
  * promises.push(
457
473
  * sharpStream
458
474
  * .clone()
@@ -461,19 +477,9 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
461
477
  * .toFile("optimized-500.webp")
462
478
  * );
463
479
  *
464
- * // https://github.com/sindresorhus/got/blob/main/documentation/3-streams.md
465
- * got.stream("https://www.example.com/some-file.jpg").pipe(sharpStream);
466
- *
467
- * Promise.all(promises)
468
- * .then(res => { console.log("Done!", res); })
469
- * .catch(err => {
470
- * console.error("Error processing files, let's clean it up", err);
471
- * try {
472
- * fs.unlinkSync("originalFile.jpg");
473
- * fs.unlinkSync("optimized-500.jpg");
474
- * fs.unlinkSync("optimized-500.webp");
475
- * } catch (e) {}
476
- * });
480
+ * const res = await fetch("https://www.example.com/some-file.jpg")
481
+ * Readable.fromWeb(res.body).pipe(sharpStream);
482
+ * await Promise.all(promises);
477
483
  *
478
484
  * @returns {Sharp}
479
485
  */
package/dist/input.cjs CHANGED
@@ -24,7 +24,7 @@ const align = {
24
24
 
25
25
  const inputStreamParameters = [
26
26
  // Limits and error handling
27
- 'failOn', 'limitInputPixels', 'unlimited',
27
+ 'failOn', 'limitInputPixels', 'limitInputChannels', 'unlimited',
28
28
  // Format-generic
29
29
  'animated', 'autoOrient', 'density', 'ignoreIcc', 'page', 'pages', 'sequentialRead',
30
30
  // Format-specific
@@ -55,6 +55,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
55
55
  autoOrient: false,
56
56
  failOn: 'warning',
57
57
  limitInputPixels: 0x3FFF ** 2,
58
+ limitInputChannels: 5,
58
59
  ignoreIcc: false,
59
60
  unlimited: false,
60
61
  sequentialRead: true
@@ -150,6 +151,16 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
150
151
  throw is.invalidParameterError('limitInputPixels', 'positive integer', inputOptions.limitInputPixels);
151
152
  }
152
153
  }
154
+ // limitInputChannels
155
+ if (is.defined(inputOptions.limitInputChannels)) {
156
+ if (is.bool(inputOptions.limitInputChannels)) {
157
+ inputDescriptor.limitInputChannels = inputOptions.limitInputChannels ? 5 : 0;
158
+ } else if (is.integer(inputOptions.limitInputChannels) && is.inRange(inputOptions.limitInputChannels, 0, Number.MAX_SAFE_INTEGER)) {
159
+ inputDescriptor.limitInputChannels = inputOptions.limitInputChannels;
160
+ } else {
161
+ throw is.invalidParameterError('limitInputChannels', 'positive integer', inputOptions.limitInputChannels);
162
+ }
163
+ }
153
164
  // unlimited
154
165
  if (is.defined(inputOptions.unlimited)) {
155
166
  if (is.bool(inputOptions.unlimited)) {
package/dist/input.mjs CHANGED
@@ -24,7 +24,7 @@ const align = {
24
24
 
25
25
  const inputStreamParameters = [
26
26
  // Limits and error handling
27
- 'failOn', 'limitInputPixels', 'unlimited',
27
+ 'failOn', 'limitInputPixels', 'limitInputChannels', 'unlimited',
28
28
  // Format-generic
29
29
  'animated', 'autoOrient', 'density', 'ignoreIcc', 'page', 'pages', 'sequentialRead',
30
30
  // Format-specific
@@ -55,6 +55,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
55
55
  autoOrient: false,
56
56
  failOn: 'warning',
57
57
  limitInputPixels: 0x3FFF ** 2,
58
+ limitInputChannels: 5,
58
59
  ignoreIcc: false,
59
60
  unlimited: false,
60
61
  sequentialRead: true
@@ -150,6 +151,16 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
150
151
  throw is.invalidParameterError('limitInputPixels', 'positive integer', inputOptions.limitInputPixels);
151
152
  }
152
153
  }
154
+ // limitInputChannels
155
+ if (is.defined(inputOptions.limitInputChannels)) {
156
+ if (is.bool(inputOptions.limitInputChannels)) {
157
+ inputDescriptor.limitInputChannels = inputOptions.limitInputChannels ? 5 : 0;
158
+ } else if (is.integer(inputOptions.limitInputChannels) && is.inRange(inputOptions.limitInputChannels, 0, Number.MAX_SAFE_INTEGER)) {
159
+ inputDescriptor.limitInputChannels = inputOptions.limitInputChannels;
160
+ } else {
161
+ throw is.invalidParameterError('limitInputChannels', 'positive integer', inputOptions.limitInputChannels);
162
+ }
163
+ }
153
164
  // unlimited
154
165
  if (is.defined(inputOptions.unlimited)) {
155
166
  if (is.bool(inputOptions.unlimited)) {
package/dist/libvips.cjs CHANGED
@@ -5,15 +5,13 @@
5
5
 
6
6
  const { spawnSync } = require('node:child_process');
7
7
  const { createHash } = require('node:crypto');
8
- const semverCoerce = require('semver/functions/coerce');
9
- const semverGreaterThanOrEqualTo = require('semver/functions/gte');
10
- const semverSatisfies = require('semver/functions/satisfies');
8
+ const semver = require('semver');
11
9
  const detectLibc = require('detect-libc');
12
10
  const pkg = require('../package.json');
13
11
 
14
12
  /* node:coverage ignore next */
15
13
  const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips || pkg.config.libvips;
16
- const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
14
+ const minimumLibvipsVersion = semver.coerce(minimumLibvipsVersionLabelled).version;
17
15
 
18
16
  const prebuiltPlatforms = [
19
17
  'darwin-arm64', 'darwin-x64',
@@ -82,7 +80,7 @@ const buildSharpLibvipsLibDir = () => {
82
80
 
83
81
  const isUnsupportedNodeRuntime = () => {
84
82
  if (process.release?.name === 'node' && process.versions) {
85
- if (!semverSatisfies(process.versions.node, pkg.engines.node)) {
83
+ if (!semver.satisfies(process.versions.node, pkg.engines.node)) {
86
84
  return { found: process.versions.node, expected: pkg.engines.node };
87
85
  }
88
86
  }
@@ -108,7 +106,7 @@ const sha512 = (s) => createHash('sha512').update(s).digest('hex');
108
106
  const yarnLocator = () => {
109
107
  try {
110
108
  const identHash = sha512(`imgsharp-libvips-${buildPlatformArch()}`);
111
- const npmVersion = semverCoerce(pkg.optionalDependencies[`@img/sharp-libvips-${buildPlatformArch()}`], {
109
+ const npmVersion = semver.coerce(pkg.optionalDependencies[`@img/sharp-libvips-${buildPlatformArch()}`], {
112
110
  includePrerelease: true
113
111
  }).version;
114
112
  return sha512(`${identHash}npm:${npmVersion}`).slice(0, 10);
@@ -193,7 +191,7 @@ const useGlobalLibvips = (logger) => {
193
191
  }
194
192
  const globalVipsVersion = globalLibvipsVersion();
195
193
  /* node:coverage ignore next */
196
- return !!globalVipsVersion && semverGreaterThanOrEqualTo(globalVipsVersion, minimumLibvipsVersion);
194
+ return !!globalVipsVersion && semver.gte(globalVipsVersion, minimumLibvipsVersion);
197
195
  };
198
196
 
199
197
  module.exports = {
package/dist/libvips.mjs CHANGED
@@ -5,15 +5,13 @@
5
5
 
6
6
  import { spawnSync } from 'node:child_process';
7
7
  import { createHash } from 'node:crypto';
8
- import semverCoerce from 'semver/functions/coerce';
9
- import semverGreaterThanOrEqualTo from 'semver/functions/gte';
10
- import semverSatisfies from 'semver/functions/satisfies';
8
+ import semver from 'semver';
11
9
  import detectLibc from 'detect-libc';
12
10
  import pkg from '../package.json' with { type: 'json' };
13
11
 
14
12
  /* node:coverage ignore next */
15
13
  const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips || pkg.config.libvips;
16
- const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
14
+ const minimumLibvipsVersion = semver.coerce(minimumLibvipsVersionLabelled).version;
17
15
 
18
16
  const prebuiltPlatforms = [
19
17
  'darwin-arm64', 'darwin-x64',
@@ -82,7 +80,7 @@ const buildSharpLibvipsLibDir = () => {
82
80
 
83
81
  const isUnsupportedNodeRuntime = () => {
84
82
  if (process.release?.name === 'node' && process.versions) {
85
- if (!semverSatisfies(process.versions.node, pkg.engines.node)) {
83
+ if (!semver.satisfies(process.versions.node, pkg.engines.node)) {
86
84
  return { found: process.versions.node, expected: pkg.engines.node };
87
85
  }
88
86
  }
@@ -108,7 +106,7 @@ const sha512 = (s) => createHash('sha512').update(s).digest('hex');
108
106
  const yarnLocator = () => {
109
107
  try {
110
108
  const identHash = sha512(`imgsharp-libvips-${buildPlatformArch()}`);
111
- const npmVersion = semverCoerce(pkg.optionalDependencies[`@img/sharp-libvips-${buildPlatformArch()}`], {
109
+ const npmVersion = semver.coerce(pkg.optionalDependencies[`@img/sharp-libvips-${buildPlatformArch()}`], {
112
110
  includePrerelease: true
113
111
  }).version;
114
112
  return sha512(`${identHash}npm:${npmVersion}`).slice(0, 10);
@@ -193,7 +191,7 @@ const useGlobalLibvips = (logger) => {
193
191
  }
194
192
  const globalVipsVersion = globalLibvipsVersion();
195
193
  /* node:coverage ignore next */
196
- return !!globalVipsVersion && semverGreaterThanOrEqualTo(globalVipsVersion, minimumLibvipsVersion);
194
+ return !!globalVipsVersion && semver.gte(globalVipsVersion, minimumLibvipsVersion);
197
195
  };
198
196
 
199
197
  export default {
package/dist/output.cjs CHANGED
@@ -1228,13 +1228,12 @@ function tiff (options) {
1228
1228
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
1229
1229
  * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
1230
1230
  * @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
1231
- * @param {string} [options.tune='iq'] - tune output for a quality metric, one of 'iq' (default), 'ssim' (default when lossless) or 'psnr'
1231
+ * @param {string} [options.tune='auto'] - tune output for a quality metric, one of 'auto' (default), 'iq', 'psnr' or 'ssim'
1232
1232
  * @returns {Sharp}
1233
1233
  * @throws {Error} Invalid options
1234
1234
  */
1235
1235
  function avif (options) {
1236
- const tune = is.object(options) && is.defined(options.tune) ? options.tune : 'iq';
1237
- return this.heif({ ...options, compression: 'av1', tune });
1236
+ return this.heif({ ...options, compression: 'av1' });
1238
1237
  }
1239
1238
 
1240
1239
  /**
@@ -1257,7 +1256,7 @@ function avif (options) {
1257
1256
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
1258
1257
  * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
1259
1258
  * @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
1260
- * @param {string} [options.tune='ssim'] - tune output for a quality metric, one of 'ssim' (default), 'psnr' or 'iq'
1259
+ * @param {string} [options.tune='auto'] - tune output for a quality metric, one of 'auto' (default), 'iq', 'psnr' or 'ssim'
1261
1260
  * @returns {Sharp}
1262
1261
  * @throws {Error} Invalid options
1263
1262
  */
@@ -1307,14 +1306,14 @@ function heif (options) {
1307
1306
  }
1308
1307
  }
1309
1308
  if (is.defined(options.tune)) {
1310
- if (is.string(options.tune) && is.inArray(options.tune, ['iq', 'ssim', 'psnr'])) {
1309
+ if (is.string(options.tune) && is.inArray(options.tune, ['auto', 'iq', 'psnr', 'ssim'])) {
1311
1310
  if (this.options.heifLossless && options.tune === 'iq') {
1312
1311
  this.options.heifTune = 'ssim';
1313
1312
  } else {
1314
1313
  this.options.heifTune = options.tune;
1315
1314
  }
1316
1315
  } else {
1317
- throw is.invalidParameterError('tune', 'one of: psnr, ssim, iq', options.tune);
1316
+ throw is.invalidParameterError('tune', 'one of: auto, iq, psnr, ssim', options.tune);
1318
1317
  }
1319
1318
  }
1320
1319
  } else {
package/dist/output.mjs CHANGED
@@ -1228,13 +1228,12 @@ function tiff (options) {
1228
1228
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
1229
1229
  * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
1230
1230
  * @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
1231
- * @param {string} [options.tune='iq'] - tune output for a quality metric, one of 'iq' (default), 'ssim' (default when lossless) or 'psnr'
1231
+ * @param {string} [options.tune='auto'] - tune output for a quality metric, one of 'auto' (default), 'iq', 'psnr' or 'ssim'
1232
1232
  * @returns {Sharp}
1233
1233
  * @throws {Error} Invalid options
1234
1234
  */
1235
1235
  function avif (options) {
1236
- const tune = is.object(options) && is.defined(options.tune) ? options.tune : 'iq';
1237
- return this.heif({ ...options, compression: 'av1', tune });
1236
+ return this.heif({ ...options, compression: 'av1' });
1238
1237
  }
1239
1238
 
1240
1239
  /**
@@ -1257,7 +1256,7 @@ function avif (options) {
1257
1256
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
1258
1257
  * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
1259
1258
  * @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
1260
- * @param {string} [options.tune='ssim'] - tune output for a quality metric, one of 'ssim' (default), 'psnr' or 'iq'
1259
+ * @param {string} [options.tune='auto'] - tune output for a quality metric, one of 'auto' (default), 'iq', 'psnr' or 'ssim'
1261
1260
  * @returns {Sharp}
1262
1261
  * @throws {Error} Invalid options
1263
1262
  */
@@ -1307,14 +1306,14 @@ function heif (options) {
1307
1306
  }
1308
1307
  }
1309
1308
  if (is.defined(options.tune)) {
1310
- if (is.string(options.tune) && is.inArray(options.tune, ['iq', 'ssim', 'psnr'])) {
1309
+ if (is.string(options.tune) && is.inArray(options.tune, ['auto', 'iq', 'psnr', 'ssim'])) {
1311
1310
  if (this.options.heifLossless && options.tune === 'iq') {
1312
1311
  this.options.heifTune = 'ssim';
1313
1312
  } else {
1314
1313
  this.options.heifTune = options.tune;
1315
1314
  }
1316
1315
  } else {
1317
- throw is.invalidParameterError('tune', 'one of: psnr, ssim, iq', options.tune);
1316
+ throw is.invalidParameterError('tune', 'one of: auto, iq, psnr, ssim', options.tune);
1318
1317
  }
1319
1318
  }
1320
1319
  } else {
package/dist/resize.cjs CHANGED
@@ -506,6 +506,8 @@ function extract (options) {
506
506
  *
507
507
  * If the result of this operation would trim an image to nothing then no change is made.
508
508
  *
509
+ * Use the `lineArt` and `threshold` options for control over sensitivity.
510
+ *
509
511
  * The `info` response Object will contain `trimOffsetLeft` and `trimOffsetTop` properties.
510
512
  *
511
513
  * @example
package/dist/resize.mjs CHANGED
@@ -506,6 +506,8 @@ function extract (options) {
506
506
  *
507
507
  * If the result of this operation would trim an image to nothing then no change is made.
508
508
  *
509
+ * Use the `lineArt` and `threshold` options for control over sensitivity.
510
+ *
509
511
  * The `info` response Object will contain `trimOffsetLeft` and `trimOffsetTop` properties.
510
512
  *
511
513
  * @example
package/dist/sharp.cjs CHANGED
@@ -5,10 +5,16 @@
5
5
 
6
6
  // Inspects the runtime environment and exports the relevant sharp.node binary
7
7
 
8
+
8
9
  const { familySync, versionSync } = require("detect-libc");
9
10
 
10
- const { version } = require('../package.json');
11
- const { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } = require("./libvips.cjs");
11
+ const libvips = require("./libvips.cjs");
12
+ const pkg = require('../package.json');
13
+
14
+
15
+ const { version } = pkg;
16
+
17
+ const { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } = libvips;
12
18
  const runtimePlatform = runtimePlatformArch();
13
19
 
14
20
  /* node:coverage disable */
@@ -96,7 +102,7 @@ if (!sharp) {
96
102
 
97
103
  const help = [`Could not load the "sharp" module using the ${runtimePlatform} runtime`];
98
104
  errors.forEach((err) => {
99
- if (err.code !== "MODULE_NOT_FOUND") {
105
+ if (!err.code.endsWith("MODULE_NOT_FOUND")) {
100
106
  help.push(`${err.code}: ${err.message}`);
101
107
  }
102
108
  });
package/dist/sharp.mjs CHANGED
@@ -5,10 +5,16 @@
5
5
 
6
6
  // Inspects the runtime environment and exports the relevant sharp.node binary
7
7
 
8
+ import { createRequire } from "node:module"
8
9
  import { familySync, versionSync } from "detect-libc";
9
10
 
10
- import { version } from '../package.json';
11
- import { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } from "./libvips.mjs";
11
+ import libvips from "./libvips.mjs";
12
+ import pkg from '../package.json' with { type: 'json' };
13
+
14
+ const require = createRequire(import.meta.url);
15
+ const { version } = pkg;
16
+
17
+ const { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } = libvips;
12
18
  const runtimePlatform = runtimePlatformArch();
13
19
 
14
20
  /* node:coverage disable */
@@ -16,13 +22,13 @@ const runtimePlatform = runtimePlatformArch();
16
22
  let sharp;
17
23
  const errors = [];
18
24
  try {
19
- sharp = await import(`../src/build/Release/sharp-${runtimePlatform}-${version}.node`);
25
+ sharp = require(`../src/build/Release/sharp-${runtimePlatform}-${version}.node`);
20
26
  } catch (err) {
21
27
  errors.push(err);
22
28
  }
23
29
  if (!sharp) {
24
30
  try {
25
- sharp = await import(`../src/build/Release/sharp-wasm32-${version}.node`);
31
+ sharp = require(`../src/build/Release/sharp-wasm32-${version}.node`);
26
32
  } catch (err) {
27
33
  errors.push(err);
28
34
  }
@@ -31,53 +37,53 @@ if (!sharp) {
31
37
  try {
32
38
  switch (runtimePlatform) {
33
39
  case "darwin-arm64":
34
- sharp = await import("@img/sharp-darwin-arm64/sharp.node");
40
+ sharp = require("@img/sharp-darwin-arm64/sharp.node");
35
41
  break;
36
42
  case "darwin-x64":
37
- sharp = await import("@img/sharp-darwin-x64/sharp.node");
43
+ sharp = require("@img/sharp-darwin-x64/sharp.node");
38
44
  break;
39
45
  case "linux-arm":
40
- sharp = await import("@img/sharp-linux-arm/sharp.node");
46
+ sharp = require("@img/sharp-linux-arm/sharp.node");
41
47
  break;
42
48
  case "linux-arm64":
43
- sharp = await import("@img/sharp-linux-arm64/sharp.node");
49
+ sharp = require("@img/sharp-linux-arm64/sharp.node");
44
50
  break;
45
51
  case "linux-ppc64":
46
- sharp = await import("@img/sharp-linux-ppc64/sharp.node");
52
+ sharp = require("@img/sharp-linux-ppc64/sharp.node");
47
53
  break;
48
54
  case "linux-riscv64":
49
- sharp = await import("@img/sharp-linux-riscv64/sharp.node");
55
+ sharp = require("@img/sharp-linux-riscv64/sharp.node");
50
56
  break;
51
57
  case "linux-s390x":
52
- sharp = await import("@img/sharp-linux-s390x/sharp.node");
58
+ sharp = require("@img/sharp-linux-s390x/sharp.node");
53
59
  break;
54
60
  case "linux-x64":
55
- sharp = await import("@img/sharp-linux-x64/sharp.node");
61
+ sharp = require("@img/sharp-linux-x64/sharp.node");
56
62
  break;
57
63
  case "linuxmusl-arm64":
58
- sharp = await import("@img/sharp-linuxmusl-arm64/sharp.node");
64
+ sharp = require("@img/sharp-linuxmusl-arm64/sharp.node");
59
65
  break;
60
66
  case "linuxmusl-x64":
61
- sharp = await import("@img/sharp-linuxmusl-x64/sharp.node");
67
+ sharp = require("@img/sharp-linuxmusl-x64/sharp.node");
62
68
  break;
63
69
  case "win32-arm64":
64
- sharp = await import("@img/sharp-win32-arm64/sharp.node");
70
+ sharp = require("@img/sharp-win32-arm64/sharp.node");
65
71
  break;
66
72
  case "win32-ia32":
67
- sharp = await import("@img/sharp-win32-ia32/sharp.node");
73
+ sharp = require("@img/sharp-win32-ia32/sharp.node");
68
74
  break;
69
75
  case "win32-x64":
70
- sharp = await import("@img/sharp-win32-x64/sharp.node");
76
+ sharp = require("@img/sharp-win32-x64/sharp.node");
71
77
  break;
72
78
  case "freebsd-arm64":
73
79
  case "freebsd-x64":
74
- sharp = await import("@img/sharp-freebsd-wasm32/sharp.node");
80
+ sharp = require("@img/sharp-freebsd-wasm32/sharp.node");
75
81
  break;
76
82
  case "linux-wasm32":
77
- sharp = await import("@img/sharp-webcontainers-wasm32/sharp.node");
83
+ sharp = require("@img/sharp-webcontainers-wasm32/sharp.node");
78
84
  break;
79
85
  default:
80
- sharp = await import("@img/sharp-wasm32/sharp.node");
86
+ sharp = require("@img/sharp-wasm32/sharp.node");
81
87
  break;
82
88
  }
83
89
  if (["linux-x64", "linuxmusl-x64"].includes(runtimePlatform) && !sharp._isUsingX64V2()) {
@@ -96,7 +102,7 @@ if (!sharp) {
96
102
 
97
103
  const help = [`Could not load the "sharp" module using the ${runtimePlatform} runtime`];
98
104
  errors.forEach((err) => {
99
- if (err.code !== "MODULE_NOT_FOUND") {
105
+ if (!err.code.endsWith("MODULE_NOT_FOUND")) {
100
106
  help.push(`${err.code}: ${err.message}`);
101
107
  }
102
108
  });
@@ -127,7 +133,7 @@ if (!sharp) {
127
133
  }
128
134
  if (isLinux && /(symbol not found|CXXABI_)/i.test(messages)) {
129
135
  try {
130
- const { config } = await import(`@img/sharp-libvips-${runtimePlatform}/package`);
136
+ const { config } = require(`@img/sharp-libvips-${runtimePlatform}/package`);
131
137
  const libcFound = `${familySync()} ${versionSync()}`;
132
138
  const libcRequires = `${config.musl ? "musl" : "glibc"} ${config.musl || config.glibc}`;
133
139
  help.push("- Update your OS:", ` Found ${libcFound}`, ` Requires ${libcRequires}`);
package/dist/utility.cjs CHANGED
@@ -4,14 +4,17 @@
4
4
  */
5
5
 
6
6
  const events = require('node:events');
7
+
8
+ const { availableParallelism } = require("node:os");
7
9
  const detectLibc = require('detect-libc');
8
10
 
9
11
  const is = require('./is.cjs');
10
- const { runtimePlatformArch } = require('./libvips.cjs');
12
+ const libvips = require('./libvips.cjs');
11
13
  const sharp = require('./sharp.cjs');
12
14
  const pkg = require("../package.json");
13
15
 
14
- const runtimePlatform = runtimePlatformArch();
16
+
17
+ const runtimePlatform = libvips.runtimePlatformArch();
15
18
  const libvipsVersion = sharp.libvipsVersion();
16
19
 
17
20
  /**
@@ -157,7 +160,6 @@ if (detectLibc.familySync() === detectLibc.GLIBC && !sharp._isUsingJemalloc()) {
157
160
  sharp.concurrency(1);
158
161
  } else if (detectLibc.familySync() === detectLibc.MUSL && sharp.concurrency() === 1024) {
159
162
  // Reduce default concurrency when musl thread over-subscription detected
160
- const { availableParallelism } = require('node:os')
161
163
  sharp.concurrency(availableParallelism());
162
164
  }
163
165
 
package/dist/utility.mjs CHANGED
@@ -4,14 +4,17 @@
4
4
  */
5
5
 
6
6
  import events from 'node:events';
7
+ import { createRequire } from "node:module";
8
+ import { availableParallelism } from "node:os";
7
9
  import detectLibc from 'detect-libc';
8
10
 
9
11
  import is from './is.mjs';
10
- import { runtimePlatformArch } from './libvips.mjs';
12
+ import libvips from './libvips.mjs';
11
13
  import sharp from './sharp.mjs';
12
14
  import pkg from "../package.json" with { type: "json" };
13
15
 
14
- const runtimePlatform = runtimePlatformArch();
16
+ const require = createRequire(import.meta.url);
17
+ const runtimePlatform = libvips.runtimePlatformArch();
15
18
  const libvipsVersion = sharp.libvipsVersion();
16
19
 
17
20
  /**
@@ -62,15 +65,15 @@ let versions = {
62
65
  if (!libvipsVersion.isGlobal) {
63
66
  if (!libvipsVersion.isWasm) {
64
67
  try {
65
- versions = await import(`@img/sharp-${runtimePlatform}/versions`);
68
+ versions = require(`@img/sharp-${runtimePlatform}/versions`);
66
69
  } catch (_) {
67
70
  try {
68
- versions = await import(`@img/sharp-libvips-${runtimePlatform}/versions`);
71
+ versions = require(`@img/sharp-libvips-${runtimePlatform}/versions`);
69
72
  } catch (_) {}
70
73
  }
71
74
  } else {
72
75
  try {
73
- versions = await import('@img/sharp-wasm32/versions');
76
+ versions = require('@img/sharp-wasm32/versions');
74
77
  } catch (_) {}
75
78
  }
76
79
  }
@@ -157,7 +160,6 @@ if (detectLibc.familySync() === detectLibc.GLIBC && !sharp._isUsingJemalloc()) {
157
160
  sharp.concurrency(1);
158
161
  } else if (detectLibc.familySync() === detectLibc.MUSL && sharp.concurrency() === 1024) {
159
162
  // Reduce default concurrency when musl thread over-subscription detected
160
- const { availableParallelism } = await import('node:os')
161
163
  sharp.concurrency(availableParallelism());
162
164
  }
163
165
 
package/lib/index.d.ts CHANGED
@@ -989,7 +989,8 @@ declare namespace sharp {
989
989
  autoOrient?: boolean | undefined;
990
990
  /**
991
991
  * When to abort processing of invalid pixel data, one of (in order of sensitivity):
992
- * 'none' (least), 'truncated', 'error' or 'warning' (most), highers level imply lower levels, invalid metadata will always abort. (optional, default 'warning')
992
+ * 'none' (least), 'truncated', 'error' or 'warning' (most), highers level imply lower levels, invalid metadata will always abort.
993
+ * Use the default 'warning' level with untrusted input. (optional, default 'warning')
993
994
  */
994
995
  failOn?: FailOnOptions | undefined;
995
996
  /**
@@ -998,6 +999,12 @@ declare namespace sharp {
998
999
  * An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF). (optional, default 268402689)
999
1000
  */
1000
1001
  limitInputPixels?: number | boolean | undefined;
1002
+ /**
1003
+ * Do not process input images where the number of channels exceeds this limit.
1004
+ * Assumes image metadata can be trusted.
1005
+ * An integral Number of channels, zero or false to remove limit, true to use default limit of 5. (optional, default 5)
1006
+ */
1007
+ limitInputChannels?: number | boolean | undefined;
1001
1008
  /** Set this to true to remove safety features that help prevent memory exhaustion (SVG, PNG). (optional, default false) */
1002
1009
  unlimited?: boolean | undefined;
1003
1010
  /** Set this to false to use random access rather than sequential read. Some operations will do this automatically. */
@@ -1176,7 +1183,7 @@ declare namespace sharp {
1176
1183
 
1177
1184
  type HeifCompression = 'av1' | 'hevc';
1178
1185
 
1179
- type HeifTune = 'iq' | 'ssim' | 'psnr';
1186
+ type HeifTune = 'auto' | 'iq' | 'psnr' | 'ssim';
1180
1187
 
1181
1188
  type Unit = 'inch' | 'cm';
1182
1189
 
@@ -1425,7 +1432,7 @@ declare namespace sharp {
1425
1432
  chromaSubsampling?: string | undefined;
1426
1433
  /** Set bitdepth to 8, 10 or 12 bit (optional, default 8) */
1427
1434
  bitdepth?: 8 | 10 | 12 | undefined;
1428
- /** Tune output for a quality metric, one of 'iq', 'ssim' or 'psnr' (optional, default 'iq') */
1435
+ /** Tune output for a quality metric, one of 'auto', 'iq', 'psnr' or 'ssim' (optional, default 'auto') */
1429
1436
  tune?: HeifTune | undefined;
1430
1437
  }
1431
1438
 
@@ -1442,7 +1449,7 @@ declare namespace sharp {
1442
1449
  chromaSubsampling?: string | undefined;
1443
1450
  /** Set bitdepth to 8, 10 or 12 bit (optional, default 8) */
1444
1451
  bitdepth?: 8 | 10 | 12 | undefined;
1445
- /** Tune output for a quality metric, one of 'ssim', 'psnr' or 'iq' (optional, default 'ssim') */
1452
+ /** Tune output for a quality metric, one of 'auto', 'iq', 'psnr' or 'ssim' (optional, default 'auto') */
1446
1453
  tune?: HeifTune | undefined;
1447
1454
  }
1448
1455
 
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.35.0-rc.4",
4
+ "version": "0.35.0-rc.6",
5
5
  "author": "Lovell Fuller <npm@lovell.info>",
6
6
  "homepage": "https://sharp.pixelplumbing.com",
7
7
  "contributors": [
@@ -152,51 +152,51 @@
152
152
  "dependencies": {
153
153
  "@img/colour": "^1.1.0",
154
154
  "detect-libc": "^2.1.2",
155
- "semver": "^7.7.4"
155
+ "semver": "^7.8.2"
156
156
  },
157
157
  "optionalDependencies": {
158
- "@img/sharp-darwin-arm64": "0.35.0-rc.4",
159
- "@img/sharp-darwin-x64": "0.35.0-rc.4",
160
- "@img/sharp-freebsd-wasm32": "0.35.0-rc.4",
161
- "@img/sharp-libvips-darwin-arm64": "1.3.0-rc.5",
162
- "@img/sharp-libvips-darwin-x64": "1.3.0-rc.5",
163
- "@img/sharp-libvips-linux-arm": "1.3.0-rc.5",
164
- "@img/sharp-libvips-linux-arm64": "1.3.0-rc.5",
165
- "@img/sharp-libvips-linux-ppc64": "1.3.0-rc.5",
166
- "@img/sharp-libvips-linux-riscv64": "1.3.0-rc.5",
167
- "@img/sharp-libvips-linux-s390x": "1.3.0-rc.5",
168
- "@img/sharp-libvips-linux-x64": "1.3.0-rc.5",
169
- "@img/sharp-libvips-linuxmusl-arm64": "1.3.0-rc.5",
170
- "@img/sharp-libvips-linuxmusl-x64": "1.3.0-rc.5",
171
- "@img/sharp-linux-arm": "0.35.0-rc.4",
172
- "@img/sharp-linux-arm64": "0.35.0-rc.4",
173
- "@img/sharp-linux-ppc64": "0.35.0-rc.4",
174
- "@img/sharp-linux-riscv64": "0.35.0-rc.4",
175
- "@img/sharp-linux-s390x": "0.35.0-rc.4",
176
- "@img/sharp-linux-x64": "0.35.0-rc.4",
177
- "@img/sharp-linuxmusl-arm64": "0.35.0-rc.4",
178
- "@img/sharp-linuxmusl-x64": "0.35.0-rc.4",
179
- "@img/sharp-webcontainers-wasm32": "0.35.0-rc.4",
180
- "@img/sharp-win32-arm64": "0.35.0-rc.4",
181
- "@img/sharp-win32-ia32": "0.35.0-rc.4",
182
- "@img/sharp-win32-x64": "0.35.0-rc.4"
158
+ "@img/sharp-darwin-arm64": "0.35.0-rc.6",
159
+ "@img/sharp-darwin-x64": "0.35.0-rc.6",
160
+ "@img/sharp-freebsd-wasm32": "0.35.0-rc.6",
161
+ "@img/sharp-libvips-darwin-arm64": "1.3.0-rc.8",
162
+ "@img/sharp-libvips-darwin-x64": "1.3.0-rc.8",
163
+ "@img/sharp-libvips-linux-arm": "1.3.0-rc.8",
164
+ "@img/sharp-libvips-linux-arm64": "1.3.0-rc.8",
165
+ "@img/sharp-libvips-linux-ppc64": "1.3.0-rc.8",
166
+ "@img/sharp-libvips-linux-riscv64": "1.3.0-rc.8",
167
+ "@img/sharp-libvips-linux-s390x": "1.3.0-rc.8",
168
+ "@img/sharp-libvips-linux-x64": "1.3.0-rc.8",
169
+ "@img/sharp-libvips-linuxmusl-arm64": "1.3.0-rc.8",
170
+ "@img/sharp-libvips-linuxmusl-x64": "1.3.0-rc.8",
171
+ "@img/sharp-linux-arm": "0.35.0-rc.6",
172
+ "@img/sharp-linux-arm64": "0.35.0-rc.6",
173
+ "@img/sharp-linux-ppc64": "0.35.0-rc.6",
174
+ "@img/sharp-linux-riscv64": "0.35.0-rc.6",
175
+ "@img/sharp-linux-s390x": "0.35.0-rc.6",
176
+ "@img/sharp-linux-x64": "0.35.0-rc.6",
177
+ "@img/sharp-linuxmusl-arm64": "0.35.0-rc.6",
178
+ "@img/sharp-linuxmusl-x64": "0.35.0-rc.6",
179
+ "@img/sharp-webcontainers-wasm32": "0.35.0-rc.6",
180
+ "@img/sharp-win32-arm64": "0.35.0-rc.6",
181
+ "@img/sharp-win32-ia32": "0.35.0-rc.6",
182
+ "@img/sharp-win32-x64": "0.35.0-rc.6"
183
183
  },
184
184
  "devDependencies": {
185
- "@biomejs/biome": "^2.4.12",
185
+ "@biomejs/biome": "^2.4.16",
186
186
  "@cpplint/cli": "^0.1.0",
187
187
  "@emnapi/runtime": "^1.10.0",
188
- "@img/sharp-libvips-dev": "1.3.0-rc.5",
189
- "@img/sharp-libvips-dev-wasm32": "1.3.0-rc.5",
190
- "@img/sharp-libvips-win32-arm64": "1.3.0-rc.5",
191
- "@img/sharp-libvips-win32-ia32": "1.3.0-rc.5",
192
- "@img/sharp-libvips-win32-x64": "1.3.0-rc.5",
188
+ "@img/sharp-libvips-dev": "1.3.0-rc.8",
189
+ "@img/sharp-libvips-dev-wasm32": "1.3.0-rc.8",
190
+ "@img/sharp-libvips-win32-arm64": "1.3.0-rc.8",
191
+ "@img/sharp-libvips-win32-ia32": "1.3.0-rc.8",
192
+ "@img/sharp-libvips-win32-x64": "1.3.0-rc.8",
193
193
  "@types/node": "*",
194
194
  "emnapi": "^1.10.0",
195
195
  "exif-reader": "^2.0.3",
196
196
  "extract-zip": "^2.0.1",
197
- "icc": "^3.0.0",
198
- "node-addon-api": "^8.7.0",
199
- "node-gyp": "^12.2.0",
197
+ "icc": "^4.0.0",
198
+ "node-addon-api": "^8.8.0",
199
+ "node-gyp": "^12.4.0",
200
200
  "tar-fs": "^3.1.2",
201
201
  "tsd": "^0.33.0"
202
202
  },
@@ -205,7 +205,7 @@
205
205
  "node": ">=20.9.0"
206
206
  },
207
207
  "config": {
208
- "libvips": ">=8.18.2"
208
+ "libvips": ">=8.18.3"
209
209
  },
210
210
  "funding": {
211
211
  "url": "https://opencollective.com/libvips"
package/src/common.cc CHANGED
@@ -196,8 +196,8 @@ namespace sharp {
196
196
  if (HasAttr(input, "joinValign")) {
197
197
  descriptor->joinValign = AttrAsEnum<VipsAlign>(input, "joinValign", VIPS_TYPE_ALIGN);
198
198
  }
199
- // Limit input images to a given number of pixels, where pixels = width * height
200
199
  descriptor->limitInputPixels = static_cast<uint64_t>(AttrAsInt64(input, "limitInputPixels"));
200
+ descriptor->limitInputChannels = static_cast<uint64_t>(AttrAsInt64(input, "limitInputChannels"));
201
201
  if (HasAttr(input, "access")) {
202
202
  descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
203
203
  }
@@ -614,6 +614,9 @@ namespace sharp {
614
614
  static_cast<uint64_t>(image.width()) * image.height() > descriptor->limitInputPixels) {
615
615
  throw std::runtime_error("Input image exceeds pixel limit");
616
616
  }
617
+ if (descriptor->limitInputChannels > 0 && static_cast<uint64_t>(image.bands()) > descriptor->limitInputChannels) {
618
+ throw std::runtime_error("Input image exceeds channel limit");
619
+ }
617
620
  return std::make_tuple(image, imageType);
618
621
  }
619
622
 
package/src/common.h CHANGED
@@ -19,8 +19,8 @@
19
19
 
20
20
  #if (VIPS_MAJOR_VERSION < 8) || \
21
21
  (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 18) || \
22
- (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 18 && VIPS_MICRO_VERSION < 2)
23
- #error "libvips version 8.18.2+ is required - please see https://sharp.pixelplumbing.com/install"
22
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 18 && VIPS_MICRO_VERSION < 3)
23
+ #error "libvips version 8.18.3+ is required - please see https://sharp.pixelplumbing.com/install"
24
24
  #endif
25
25
 
26
26
  #if defined(__has_include)
@@ -46,6 +46,7 @@ namespace sharp {
46
46
  char *buffer;
47
47
  VipsFailOn failOn;
48
48
  uint64_t limitInputPixels;
49
+ uint64_t limitInputChannels;
49
50
  bool unlimited;
50
51
  VipsAccess access;
51
52
  size_t bufferLength;
@@ -98,6 +99,7 @@ namespace sharp {
98
99
  buffer(nullptr),
99
100
  failOn(VIPS_FAIL_ON_WARNING),
100
101
  limitInputPixels(0x3FFF * 0x3FFF),
102
+ limitInputChannels(5),
101
103
  unlimited(false),
102
104
  access(VIPS_ACCESS_SEQUENTIAL),
103
105
  bufferLength(0),
package/src/pipeline.h CHANGED
@@ -380,7 +380,7 @@ struct PipelineBaton {
380
380
  heifChromaSubsampling("4:4:4"),
381
381
  heifLossless(false),
382
382
  heifBitdepth(8),
383
- heifTune("ssim"),
383
+ heifTune("auto"),
384
384
  jxlDistance(1.0),
385
385
  jxlDecodingTier(0),
386
386
  jxlEffort(7),