sharp 0.35.2 → 0.35.3-rc.1

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/dist/colour.cjs CHANGED
@@ -146,12 +146,16 @@ function _getBackgroundColourOption (value) {
146
146
  (is.string(value) && value.length >= 3 && value.length <= 200)
147
147
  ) {
148
148
  const colour = color(value);
149
- return [
150
- colour.red(),
151
- colour.green(),
152
- colour.blue(),
153
- Math.round(colour.alpha() * 255)
154
- ];
149
+ const red = colour.red();
150
+ const green = colour.green();
151
+ const blue = colour.blue();
152
+ const alpha = Math.round(colour.alpha() * 255);
153
+ for (const [channel, component] of [['red', red], ['green', green], ['blue', blue], ['alpha', alpha]]) {
154
+ if (!is.number(component)) {
155
+ throw is.invalidParameterError(`background.${channel}`, 'number', component);
156
+ }
157
+ }
158
+ return [red, green, blue, alpha];
155
159
  } else {
156
160
  throw is.invalidParameterError('background', 'object or string', value);
157
161
  }
package/dist/colour.mjs CHANGED
@@ -146,12 +146,16 @@ function _getBackgroundColourOption (value) {
146
146
  (is.string(value) && value.length >= 3 && value.length <= 200)
147
147
  ) {
148
148
  const colour = color(value);
149
- return [
150
- colour.red(),
151
- colour.green(),
152
- colour.blue(),
153
- Math.round(colour.alpha() * 255)
154
- ];
149
+ const red = colour.red();
150
+ const green = colour.green();
151
+ const blue = colour.blue();
152
+ const alpha = Math.round(colour.alpha() * 255);
153
+ for (const [channel, component] of [['red', red], ['green', green], ['blue', blue], ['alpha', alpha]]) {
154
+ if (!is.number(component)) {
155
+ throw is.invalidParameterError(`background.${channel}`, 'number', component);
156
+ }
157
+ }
158
+ return [red, green, blue, alpha];
155
159
  } else {
156
160
  throw is.invalidParameterError('background', 'object or string', value);
157
161
  }
package/dist/index.d.cts CHANGED
@@ -1508,11 +1508,11 @@ declare namespace sharp {
1508
1508
  tile?: boolean | undefined;
1509
1509
  /** Horizontal tile size (optional, default 256) */
1510
1510
  tileWidth?: number | undefined;
1511
- /** Vertical tile size (optional, default 256) */
1511
+ /** Vertical tile size, valid values are integers in the range 1-32768 (optional, default 256) */
1512
1512
  tileHeight?: number | undefined;
1513
- /** Horizontal resolution in pixels/mm (optional, default 1.0) */
1513
+ /** Horizontal resolution in pixels/mm, valid values are numbers in the range 0.001-1000000 (optional, default 1.0) */
1514
1514
  xres?: number | undefined;
1515
- /** Vertical resolution in pixels/mm (optional, default 1.0) */
1515
+ /** Vertical resolution in pixels/mm, valid values are numbers in the range 0.001-1000000 (optional, default 1.0) */
1516
1516
  yres?: number | undefined;
1517
1517
  /** Reduce bitdepth to 1, 2 or 4 bit (optional) */
1518
1518
  bitdepth?: 1 | 2 | 4 | undefined;
@@ -1598,13 +1598,13 @@ declare namespace sharp {
1598
1598
  }
1599
1599
 
1600
1600
  interface Region {
1601
- /** zero-indexed offset from left edge */
1601
+ /** zero-indexed offset from left edge, an integer between 0 and 100000000 */
1602
1602
  left: number;
1603
- /** zero-indexed offset from top edge */
1603
+ /** zero-indexed offset from top edge, an integer between 0 and 100000000 */
1604
1604
  top: number;
1605
- /** dimension of extracted image */
1605
+ /** dimension of extracted image, an integer between 0 and 100000000 */
1606
1606
  width: number;
1607
- /** dimension of extracted image */
1607
+ /** dimension of extracted image, an integer between 0 and 100000000 */
1608
1608
  height: number;
1609
1609
  }
1610
1610
 
@@ -1620,13 +1620,13 @@ declare namespace sharp {
1620
1620
  type ExtendWith = 'background' | 'copy' | 'repeat' | 'mirror';
1621
1621
 
1622
1622
  interface ExtendOptions {
1623
- /** single pixel count to top edge (optional, default 0) */
1623
+ /** single pixel count to top edge, valid values are integers in the range 0-10000 (optional, default 0) */
1624
1624
  top?: number | undefined;
1625
- /** single pixel count to left edge (optional, default 0) */
1625
+ /** single pixel count to left edge, valid values are integers in the range 0-10000 (optional, default 0) */
1626
1626
  left?: number | undefined;
1627
- /** single pixel count to bottom edge (optional, default 0) */
1627
+ /** single pixel count to bottom edge, valid values are integers in the range 0-10000 (optional, default 0) */
1628
1628
  bottom?: number | undefined;
1629
- /** single pixel count to right edge (optional, default 0) */
1629
+ /** single pixel count to right edge, valid values are integers in the range 0-10000 (optional, default 0) */
1630
1630
  right?: number | undefined;
1631
1631
  /** background colour, parsed by the color module, defaults to black without transparency. (optional, default {r:0,g:0,b:0,alpha:1}) */
1632
1632
  background?: ColorLike | undefined;
@@ -1641,7 +1641,7 @@ declare namespace sharp {
1641
1641
  threshold?: number | undefined;
1642
1642
  /** Does the input more closely resemble line art (e.g. vector) rather than being photographic? (optional, default false) */
1643
1643
  lineArt?: boolean | undefined;
1644
- /** Leave a margin around trimmed content, value is in pixels. (optional, default 0) */
1644
+ /** Leave a margin around trimmed content, integral number of pixels between 0 and 10000000. (optional, default 0) */
1645
1645
  margin?: number | undefined;
1646
1646
  }
1647
1647
 
@@ -1669,11 +1669,11 @@ declare namespace sharp {
1669
1669
  }
1670
1670
 
1671
1671
  interface ClaheOptions {
1672
- /** width of the region */
1672
+ /** width of the region. Valid values are integers in the range 1-65536. */
1673
1673
  width: number;
1674
- /** height of the region */
1674
+ /** height of the region. Valid values are integers in the range 1-65536. */
1675
1675
  height: number;
1676
- /** max slope of the cumulative contrast. A value of 0 disables contrast limiting. Valid values are integers in the range 0-100 (inclusive) (optional, default 3) */
1676
+ /** max slope of the cumulative contrast. A value of 0 disables contrast limiting. Valid values are integers in the range 0-100. (optional, default 3) */
1677
1677
  maxSlope?: number | undefined;
1678
1678
  }
1679
1679
 
@@ -1783,6 +1783,8 @@ declare namespace sharp {
1783
1783
  channels: Channels;
1784
1784
  /** indicating if premultiplication was used */
1785
1785
  premultiplied: boolean;
1786
+ /** Indicates if the output image has an alpha channel */
1787
+ hasAlpha: boolean;
1786
1788
  /** Only defined when using a crop strategy */
1787
1789
  cropOffsetLeft?: number | undefined;
1788
1790
  /** Only defined when using a crop strategy */
package/dist/index.d.mts CHANGED
@@ -1502,11 +1502,11 @@ export interface TiffOptions extends OutputOptions {
1502
1502
  tile?: boolean | undefined;
1503
1503
  /** Horizontal tile size (optional, default 256) */
1504
1504
  tileWidth?: number | undefined;
1505
- /** Vertical tile size (optional, default 256) */
1505
+ /** Vertical tile size, valid values are integers in the range 1-32768 (optional, default 256) */
1506
1506
  tileHeight?: number | undefined;
1507
- /** Horizontal resolution in pixels/mm (optional, default 1.0) */
1507
+ /** Horizontal resolution in pixels/mm, valid values are numbers in the range 0.001-1000000 (optional, default 1.0) */
1508
1508
  xres?: number | undefined;
1509
- /** Vertical resolution in pixels/mm (optional, default 1.0) */
1509
+ /** Vertical resolution in pixels/mm, valid values are numbers in the range 0.001-1000000 (optional, default 1.0) */
1510
1510
  yres?: number | undefined;
1511
1511
  /** Reduce bitdepth to 1, 2 or 4 bit (optional) */
1512
1512
  bitdepth?: 1 | 2 | 4 | undefined;
@@ -1592,13 +1592,13 @@ export interface ResizeOptions {
1592
1592
  }
1593
1593
 
1594
1594
  export interface Region {
1595
- /** zero-indexed offset from left edge */
1595
+ /** zero-indexed offset from left edge, an integer between 0 and 100000000 */
1596
1596
  left: number;
1597
- /** zero-indexed offset from top edge */
1597
+ /** zero-indexed offset from top edge, an integer between 0 and 100000000 */
1598
1598
  top: number;
1599
- /** dimension of extracted image */
1599
+ /** dimension of extracted image, an integer between 0 and 100000000 */
1600
1600
  width: number;
1601
- /** dimension of extracted image */
1601
+ /** dimension of extracted image, an integer between 0 and 100000000 */
1602
1602
  height: number;
1603
1603
  }
1604
1604
 
@@ -1614,13 +1614,13 @@ export interface Noise {
1614
1614
  export type ExtendWith = 'background' | 'copy' | 'repeat' | 'mirror';
1615
1615
 
1616
1616
  export interface ExtendOptions {
1617
- /** single pixel count to top edge (optional, default 0) */
1617
+ /** single pixel count to top edge, valid values are integers in the range 0-10000 (optional, default 0) */
1618
1618
  top?: number | undefined;
1619
- /** single pixel count to left edge (optional, default 0) */
1619
+ /** single pixel count to left edge, valid values are integers in the range 0-10000 (optional, default 0) */
1620
1620
  left?: number | undefined;
1621
- /** single pixel count to bottom edge (optional, default 0) */
1621
+ /** single pixel count to bottom edge, valid values are integers in the range 0-10000 (optional, default 0) */
1622
1622
  bottom?: number | undefined;
1623
- /** single pixel count to right edge (optional, default 0) */
1623
+ /** single pixel count to right edge, valid values are integers in the range 0-10000 (optional, default 0) */
1624
1624
  right?: number | undefined;
1625
1625
  /** background colour, parsed by the color module, defaults to black without transparency. (optional, default {r:0,g:0,b:0,alpha:1}) */
1626
1626
  background?: ColorLike | undefined;
@@ -1635,7 +1635,7 @@ export interface TrimOptions {
1635
1635
  threshold?: number | undefined;
1636
1636
  /** Does the input more closely resemble line art (e.g. vector) rather than being photographic? (optional, default false) */
1637
1637
  lineArt?: boolean | undefined;
1638
- /** Leave a margin around trimmed content, value is in pixels. (optional, default 0) */
1638
+ /** Leave a margin around trimmed content, integral number of pixels between 0 and 10000000. (optional, default 0) */
1639
1639
  margin?: number | undefined;
1640
1640
  }
1641
1641
 
@@ -1663,11 +1663,11 @@ export interface Kernel {
1663
1663
  }
1664
1664
 
1665
1665
  export interface ClaheOptions {
1666
- /** width of the region */
1666
+ /** width of the region. Valid values are integers in the range 1-65536. */
1667
1667
  width: number;
1668
- /** height of the region */
1668
+ /** height of the region. Valid values are integers in the range 1-65536. */
1669
1669
  height: number;
1670
- /** max slope of the cumulative contrast. A value of 0 disables contrast limiting. Valid values are integers in the range 0-100 (inclusive) (optional, default 3) */
1670
+ /** max slope of the cumulative contrast. A value of 0 disables contrast limiting. Valid values are integers in the range 0-100. (optional, default 3) */
1671
1671
  maxSlope?: number | undefined;
1672
1672
  }
1673
1673
 
@@ -1777,6 +1777,8 @@ export interface OutputInfo {
1777
1777
  channels: Channels;
1778
1778
  /** indicating if premultiplication was used */
1779
1779
  premultiplied: boolean;
1780
+ /** Indicates if the output image has an alpha channel */
1781
+ hasAlpha: boolean;
1780
1782
  /** Only defined when using a crop strategy */
1781
1783
  cropOffsetLeft?: number | undefined;
1782
1784
  /** Only defined when using a crop strategy */
package/dist/input.cjs CHANGED
@@ -181,8 +181,8 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
181
181
  if (is.defined(inputOptions.raw)) {
182
182
  if (
183
183
  is.object(inputOptions.raw) &&
184
- is.integer(inputOptions.raw.width) && inputOptions.raw.width > 0 &&
185
- is.integer(inputOptions.raw.height) && inputOptions.raw.height > 0 &&
184
+ is.integer(inputOptions.raw.width) && is.inRange(inputOptions.raw.width, 1, 100000000) &&
185
+ is.integer(inputOptions.raw.height) && is.inRange(inputOptions.raw.height, 1, 100000000) &&
186
186
  is.integer(inputOptions.raw.channels) && is.inRange(inputOptions.raw.channels, 1, 4)
187
187
  ) {
188
188
  inputDescriptor.rawWidth = inputOptions.raw.width;
@@ -329,8 +329,8 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
329
329
  if (is.defined(inputOptions.create)) {
330
330
  if (
331
331
  is.object(inputOptions.create) &&
332
- is.integer(inputOptions.create.width) && inputOptions.create.width > 0 &&
333
- is.integer(inputOptions.create.height) && inputOptions.create.height > 0 &&
332
+ is.integer(inputOptions.create.width) && is.inRange(inputOptions.create.width, 1, 100000000) &&
333
+ is.integer(inputOptions.create.height) && is.inRange(inputOptions.create.height, 1, 100000000) &&
334
334
  is.integer(inputOptions.create.channels)
335
335
  ) {
336
336
  inputDescriptor.createWidth = inputOptions.create.width;
@@ -410,17 +410,17 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
410
410
  }
411
411
  }
412
412
  if (is.defined(inputOptions.text.width)) {
413
- if (is.integer(inputOptions.text.width) && inputOptions.text.width > 0) {
413
+ if (is.integer(inputOptions.text.width) && is.inRange(inputOptions.text.width, 1, 1000000)) {
414
414
  inputDescriptor.textWidth = inputOptions.text.width;
415
415
  } else {
416
- throw is.invalidParameterError('text.width', 'positive integer', inputOptions.text.width);
416
+ throw is.invalidParameterError('text.width', 'integer between 1 and 1000000', inputOptions.text.width);
417
417
  }
418
418
  }
419
419
  if (is.defined(inputOptions.text.height)) {
420
- if (is.integer(inputOptions.text.height) && inputOptions.text.height > 0) {
420
+ if (is.integer(inputOptions.text.height) && is.inRange(inputOptions.text.height, 1, 1000000)) {
421
421
  inputDescriptor.textHeight = inputOptions.text.height;
422
422
  } else {
423
- throw is.invalidParameterError('text.height', 'positive integer', inputOptions.text.height);
423
+ throw is.invalidParameterError('text.height', 'integer between 1 and 1000000', inputOptions.text.height);
424
424
  }
425
425
  }
426
426
  if (is.defined(inputOptions.text.align)) {
package/dist/input.mjs CHANGED
@@ -181,8 +181,8 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
181
181
  if (is.defined(inputOptions.raw)) {
182
182
  if (
183
183
  is.object(inputOptions.raw) &&
184
- is.integer(inputOptions.raw.width) && inputOptions.raw.width > 0 &&
185
- is.integer(inputOptions.raw.height) && inputOptions.raw.height > 0 &&
184
+ is.integer(inputOptions.raw.width) && is.inRange(inputOptions.raw.width, 1, 100000000) &&
185
+ is.integer(inputOptions.raw.height) && is.inRange(inputOptions.raw.height, 1, 100000000) &&
186
186
  is.integer(inputOptions.raw.channels) && is.inRange(inputOptions.raw.channels, 1, 4)
187
187
  ) {
188
188
  inputDescriptor.rawWidth = inputOptions.raw.width;
@@ -329,8 +329,8 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
329
329
  if (is.defined(inputOptions.create)) {
330
330
  if (
331
331
  is.object(inputOptions.create) &&
332
- is.integer(inputOptions.create.width) && inputOptions.create.width > 0 &&
333
- is.integer(inputOptions.create.height) && inputOptions.create.height > 0 &&
332
+ is.integer(inputOptions.create.width) && is.inRange(inputOptions.create.width, 1, 100000000) &&
333
+ is.integer(inputOptions.create.height) && is.inRange(inputOptions.create.height, 1, 100000000) &&
334
334
  is.integer(inputOptions.create.channels)
335
335
  ) {
336
336
  inputDescriptor.createWidth = inputOptions.create.width;
@@ -410,17 +410,17 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
410
410
  }
411
411
  }
412
412
  if (is.defined(inputOptions.text.width)) {
413
- if (is.integer(inputOptions.text.width) && inputOptions.text.width > 0) {
413
+ if (is.integer(inputOptions.text.width) && is.inRange(inputOptions.text.width, 1, 1000000)) {
414
414
  inputDescriptor.textWidth = inputOptions.text.width;
415
415
  } else {
416
- throw is.invalidParameterError('text.width', 'positive integer', inputOptions.text.width);
416
+ throw is.invalidParameterError('text.width', 'integer between 1 and 1000000', inputOptions.text.width);
417
417
  }
418
418
  }
419
419
  if (is.defined(inputOptions.text.height)) {
420
- if (is.integer(inputOptions.text.height) && inputOptions.text.height > 0) {
420
+ if (is.integer(inputOptions.text.height) && is.inRange(inputOptions.text.height, 1, 1000000)) {
421
421
  inputDescriptor.textHeight = inputOptions.text.height;
422
422
  } else {
423
- throw is.invalidParameterError('text.height', 'positive integer', inputOptions.text.height);
423
+ throw is.invalidParameterError('text.height', 'integer between 1 and 1000000', inputOptions.text.height);
424
424
  }
425
425
  }
426
426
  if (is.defined(inputOptions.text.align)) {
package/dist/is.cjs CHANGED
@@ -78,7 +78,7 @@ const string = (val) => typeof val === 'string' && val.length > 0;
78
78
  * Is this value a real number?
79
79
  * @private
80
80
  */
81
- const number = (val) => typeof val === 'number' && !Number.isNaN(val);
81
+ const number = (val) => typeof val === 'number' && Number.isFinite(val);
82
82
 
83
83
  /**
84
84
  * Is this value an integer?
package/dist/is.mjs CHANGED
@@ -78,7 +78,7 @@ const string = (val) => typeof val === 'string' && val.length > 0;
78
78
  * Is this value a real number?
79
79
  * @private
80
80
  */
81
- const number = (val) => typeof val === 'number' && !Number.isNaN(val);
81
+ const number = (val) => typeof val === 'number' && Number.isFinite(val);
82
82
 
83
83
  /**
84
84
  * Is this value an integer?
@@ -178,7 +178,13 @@ function flop (flop) {
178
178
  * @throws {Error} Invalid parameters
179
179
  */
180
180
  function affine (matrix, options) {
181
- const flatMatrix = Array.isArray(matrix) ? [].concat(...matrix) : [];
181
+ const isValidShape = Array.isArray(matrix) && (
182
+ // 1x4 array of numbers
183
+ (matrix.length === 4 && matrix.every(is.number)) ||
184
+ // 2x2 array of arrays of numbers
185
+ (matrix.length === 2 && matrix.every((row) => Array.isArray(row) && row.length === 2))
186
+ );
187
+ const flatMatrix = isValidShape ? matrix.flat() : [];
182
188
  if (flatMatrix.length === 4 && flatMatrix.every(is.number)) {
183
189
  this.options.affineMatrix = flatMatrix;
184
190
  } else {
@@ -646,23 +652,23 @@ function normalize (options) {
646
652
  * .toBuffer();
647
653
  *
648
654
  * @param {Object} options
649
- * @param {number} options.width - Integral width of the search window, in pixels.
650
- * @param {number} options.height - Integral height of the search window, in pixels.
655
+ * @param {number} options.width - Integral width of the search window, in pixels, between 1 and 65536.
656
+ * @param {number} options.height - Integral height of the search window, in pixels, between 1 and 65536.
651
657
  * @param {number} [options.maxSlope=3] - Integral level of brightening, between 0 and 100, where 0 disables contrast limiting.
652
658
  * @returns {Sharp}
653
659
  * @throws {Error} Invalid parameters
654
660
  */
655
661
  function clahe (options) {
656
662
  if (is.plainObject(options)) {
657
- if (is.integer(options.width) && options.width > 0) {
663
+ if (is.integer(options.width) && is.inRange(options.width, 1, 65536)) {
658
664
  this.options.claheWidth = options.width;
659
665
  } else {
660
- throw is.invalidParameterError('width', 'integer greater than zero', options.width);
666
+ throw is.invalidParameterError('width', 'integer between 1 and 65536', options.width);
661
667
  }
662
- if (is.integer(options.height) && options.height > 0) {
668
+ if (is.integer(options.height) && is.inRange(options.height, 1, 65536)) {
663
669
  this.options.claheHeight = options.height;
664
670
  } else {
665
- throw is.invalidParameterError('height', 'integer greater than zero', options.height);
671
+ throw is.invalidParameterError('height', 'integer between 1 and 65536', options.height);
666
672
  }
667
673
  if (is.defined(options.maxSlope)) {
668
674
  if (is.integer(options.maxSlope) && is.inRange(options.maxSlope, 0, 100)) {
@@ -860,13 +866,14 @@ function recomb (inputMatrix) {
860
866
  if (!Array.isArray(inputMatrix)) {
861
867
  throw is.invalidParameterError('inputMatrix', 'array', inputMatrix);
862
868
  }
863
- if (inputMatrix.length !== 3 && inputMatrix.length !== 4) {
864
- throw is.invalidParameterError('inputMatrix', '3x3 or 4x4 array', inputMatrix.length);
869
+ const dimensions = inputMatrix.length;
870
+ if (dimensions !== 3 && dimensions !== 4) {
871
+ throw is.invalidParameterError('inputMatrix', '3x3 or 4x4 array', dimensions);
865
872
  }
866
- const recombMatrix = inputMatrix.flat();
867
- if (recombMatrix.length !== 9 && recombMatrix.length !== 16) {
868
- throw is.invalidParameterError('inputMatrix', 'cardinality of 9 or 16', recombMatrix.length);
873
+ if (!inputMatrix.every((row) => Array.isArray(row) && row.length === dimensions)) {
874
+ throw is.invalidParameterError('inputMatrix', `array of ${dimensions} arrays of length ${dimensions}`, inputMatrix);
869
875
  }
876
+ const recombMatrix = inputMatrix.flat();
870
877
  if (!recombMatrix.every(is.number)) {
871
878
  throw is.invalidParameterError('inputMatrix', 'array of numbers', recombMatrix);
872
879
  }
@@ -178,7 +178,13 @@ function flop (flop) {
178
178
  * @throws {Error} Invalid parameters
179
179
  */
180
180
  function affine (matrix, options) {
181
- const flatMatrix = Array.isArray(matrix) ? [].concat(...matrix) : [];
181
+ const isValidShape = Array.isArray(matrix) && (
182
+ // 1x4 array of numbers
183
+ (matrix.length === 4 && matrix.every(is.number)) ||
184
+ // 2x2 array of arrays of numbers
185
+ (matrix.length === 2 && matrix.every((row) => Array.isArray(row) && row.length === 2))
186
+ );
187
+ const flatMatrix = isValidShape ? matrix.flat() : [];
182
188
  if (flatMatrix.length === 4 && flatMatrix.every(is.number)) {
183
189
  this.options.affineMatrix = flatMatrix;
184
190
  } else {
@@ -646,23 +652,23 @@ function normalize (options) {
646
652
  * .toBuffer();
647
653
  *
648
654
  * @param {Object} options
649
- * @param {number} options.width - Integral width of the search window, in pixels.
650
- * @param {number} options.height - Integral height of the search window, in pixels.
655
+ * @param {number} options.width - Integral width of the search window, in pixels, between 1 and 65536.
656
+ * @param {number} options.height - Integral height of the search window, in pixels, between 1 and 65536.
651
657
  * @param {number} [options.maxSlope=3] - Integral level of brightening, between 0 and 100, where 0 disables contrast limiting.
652
658
  * @returns {Sharp}
653
659
  * @throws {Error} Invalid parameters
654
660
  */
655
661
  function clahe (options) {
656
662
  if (is.plainObject(options)) {
657
- if (is.integer(options.width) && options.width > 0) {
663
+ if (is.integer(options.width) && is.inRange(options.width, 1, 65536)) {
658
664
  this.options.claheWidth = options.width;
659
665
  } else {
660
- throw is.invalidParameterError('width', 'integer greater than zero', options.width);
666
+ throw is.invalidParameterError('width', 'integer between 1 and 65536', options.width);
661
667
  }
662
- if (is.integer(options.height) && options.height > 0) {
668
+ if (is.integer(options.height) && is.inRange(options.height, 1, 65536)) {
663
669
  this.options.claheHeight = options.height;
664
670
  } else {
665
- throw is.invalidParameterError('height', 'integer greater than zero', options.height);
671
+ throw is.invalidParameterError('height', 'integer between 1 and 65536', options.height);
666
672
  }
667
673
  if (is.defined(options.maxSlope)) {
668
674
  if (is.integer(options.maxSlope) && is.inRange(options.maxSlope, 0, 100)) {
@@ -860,13 +866,14 @@ function recomb (inputMatrix) {
860
866
  if (!Array.isArray(inputMatrix)) {
861
867
  throw is.invalidParameterError('inputMatrix', 'array', inputMatrix);
862
868
  }
863
- if (inputMatrix.length !== 3 && inputMatrix.length !== 4) {
864
- throw is.invalidParameterError('inputMatrix', '3x3 or 4x4 array', inputMatrix.length);
869
+ const dimensions = inputMatrix.length;
870
+ if (dimensions !== 3 && dimensions !== 4) {
871
+ throw is.invalidParameterError('inputMatrix', '3x3 or 4x4 array', dimensions);
865
872
  }
866
- const recombMatrix = inputMatrix.flat();
867
- if (recombMatrix.length !== 9 && recombMatrix.length !== 16) {
868
- throw is.invalidParameterError('inputMatrix', 'cardinality of 9 or 16', recombMatrix.length);
873
+ if (!inputMatrix.every((row) => Array.isArray(row) && row.length === dimensions)) {
874
+ throw is.invalidParameterError('inputMatrix', `array of ${dimensions} arrays of length ${dimensions}`, inputMatrix);
869
875
  }
876
+ const recombMatrix = inputMatrix.flat();
870
877
  if (!recombMatrix.every(is.number)) {
871
878
  throw is.invalidParameterError('inputMatrix', 'array of numbers', recombMatrix);
872
879
  }
package/dist/output.cjs CHANGED
@@ -1103,10 +1103,10 @@ function trySetAnimationOptions (source, target) {
1103
1103
  * @param {string} [options.predictor='horizontal'] - compression predictor options: none, horizontal, float
1104
1104
  * @param {boolean} [options.pyramid=false] - write an image pyramid
1105
1105
  * @param {boolean} [options.tile=false] - write a tiled tiff
1106
- * @param {number} [options.tileWidth=256] - horizontal tile size
1107
- * @param {number} [options.tileHeight=256] - vertical tile size
1108
- * @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm
1109
- * @param {number} [options.yres=1.0] - vertical resolution in pixels/mm
1106
+ * @param {number} [options.tileWidth=256] - horizontal tile size, valid values are integers in the range 1-32768
1107
+ * @param {number} [options.tileHeight=256] - vertical tile size, valid values are integers in the range 1-32768
1108
+ * @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm, valid values are numbers in the range 0.001-1000000
1109
+ * @param {number} [options.yres=1.0] - vertical resolution in pixels/mm, valid values are numbers in the range 0.001-1000000
1110
1110
  * @param {string} [options.resolutionUnit='inch'] - resolution unit options: inch, cm
1111
1111
  * @param {number} [options.bitdepth=0] - reduce bitdepth to 1, 2 or 4 bit
1112
1112
  * @param {boolean} [options.miniswhite=false] - write 1-bit images as miniswhite
@@ -1134,17 +1134,17 @@ function tiff (options) {
1134
1134
  this._setBooleanOption('tiffTile', options.tile);
1135
1135
  }
1136
1136
  if (is.defined(options.tileWidth)) {
1137
- if (is.integer(options.tileWidth) && options.tileWidth > 0) {
1137
+ if (is.integer(options.tileWidth) && is.inRange(options.tileWidth, 1, 32768)) {
1138
1138
  this.options.tiffTileWidth = options.tileWidth;
1139
1139
  } else {
1140
- throw is.invalidParameterError('tileWidth', 'integer greater than zero', options.tileWidth);
1140
+ throw is.invalidParameterError('tileWidth', 'integer between 1 and 32768', options.tileWidth);
1141
1141
  }
1142
1142
  }
1143
1143
  if (is.defined(options.tileHeight)) {
1144
- if (is.integer(options.tileHeight) && options.tileHeight > 0) {
1144
+ if (is.integer(options.tileHeight) && is.inRange(options.tileHeight, 1, 32768)) {
1145
1145
  this.options.tiffTileHeight = options.tileHeight;
1146
1146
  } else {
1147
- throw is.invalidParameterError('tileHeight', 'integer greater than zero', options.tileHeight);
1147
+ throw is.invalidParameterError('tileHeight', 'integer between 1 and 32768', options.tileHeight);
1148
1148
  }
1149
1149
  }
1150
1150
  // miniswhite
@@ -1157,17 +1157,17 @@ function tiff (options) {
1157
1157
  }
1158
1158
  // resolution
1159
1159
  if (is.defined(options.xres)) {
1160
- if (is.number(options.xres) && options.xres > 0) {
1160
+ if (is.number(options.xres) && is.inRange(options.xres, 0.001, 1000000)) {
1161
1161
  this.options.tiffXres = options.xres;
1162
1162
  } else {
1163
- throw is.invalidParameterError('xres', 'number greater than zero', options.xres);
1163
+ throw is.invalidParameterError('xres', 'number between 0.001 and 1000000', options.xres);
1164
1164
  }
1165
1165
  }
1166
1166
  if (is.defined(options.yres)) {
1167
- if (is.number(options.yres) && options.yres > 0) {
1167
+ if (is.number(options.yres) && is.inRange(options.yres, 0.001, 1000000)) {
1168
1168
  this.options.tiffYres = options.yres;
1169
1169
  } else {
1170
- throw is.invalidParameterError('yres', 'number greater than zero', options.yres);
1170
+ throw is.invalidParameterError('yres', 'number between 0.001 and 1000000', options.yres);
1171
1171
  }
1172
1172
  }
1173
1173
  // compression
package/dist/output.mjs CHANGED
@@ -1103,10 +1103,10 @@ function trySetAnimationOptions (source, target) {
1103
1103
  * @param {string} [options.predictor='horizontal'] - compression predictor options: none, horizontal, float
1104
1104
  * @param {boolean} [options.pyramid=false] - write an image pyramid
1105
1105
  * @param {boolean} [options.tile=false] - write a tiled tiff
1106
- * @param {number} [options.tileWidth=256] - horizontal tile size
1107
- * @param {number} [options.tileHeight=256] - vertical tile size
1108
- * @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm
1109
- * @param {number} [options.yres=1.0] - vertical resolution in pixels/mm
1106
+ * @param {number} [options.tileWidth=256] - horizontal tile size, valid values are integers in the range 1-32768
1107
+ * @param {number} [options.tileHeight=256] - vertical tile size, valid values are integers in the range 1-32768
1108
+ * @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm, valid values are numbers in the range 0.001-1000000
1109
+ * @param {number} [options.yres=1.0] - vertical resolution in pixels/mm, valid values are numbers in the range 0.001-1000000
1110
1110
  * @param {string} [options.resolutionUnit='inch'] - resolution unit options: inch, cm
1111
1111
  * @param {number} [options.bitdepth=0] - reduce bitdepth to 1, 2 or 4 bit
1112
1112
  * @param {boolean} [options.miniswhite=false] - write 1-bit images as miniswhite
@@ -1134,17 +1134,17 @@ function tiff (options) {
1134
1134
  this._setBooleanOption('tiffTile', options.tile);
1135
1135
  }
1136
1136
  if (is.defined(options.tileWidth)) {
1137
- if (is.integer(options.tileWidth) && options.tileWidth > 0) {
1137
+ if (is.integer(options.tileWidth) && is.inRange(options.tileWidth, 1, 32768)) {
1138
1138
  this.options.tiffTileWidth = options.tileWidth;
1139
1139
  } else {
1140
- throw is.invalidParameterError('tileWidth', 'integer greater than zero', options.tileWidth);
1140
+ throw is.invalidParameterError('tileWidth', 'integer between 1 and 32768', options.tileWidth);
1141
1141
  }
1142
1142
  }
1143
1143
  if (is.defined(options.tileHeight)) {
1144
- if (is.integer(options.tileHeight) && options.tileHeight > 0) {
1144
+ if (is.integer(options.tileHeight) && is.inRange(options.tileHeight, 1, 32768)) {
1145
1145
  this.options.tiffTileHeight = options.tileHeight;
1146
1146
  } else {
1147
- throw is.invalidParameterError('tileHeight', 'integer greater than zero', options.tileHeight);
1147
+ throw is.invalidParameterError('tileHeight', 'integer between 1 and 32768', options.tileHeight);
1148
1148
  }
1149
1149
  }
1150
1150
  // miniswhite
@@ -1157,17 +1157,17 @@ function tiff (options) {
1157
1157
  }
1158
1158
  // resolution
1159
1159
  if (is.defined(options.xres)) {
1160
- if (is.number(options.xres) && options.xres > 0) {
1160
+ if (is.number(options.xres) && is.inRange(options.xres, 0.001, 1000000)) {
1161
1161
  this.options.tiffXres = options.xres;
1162
1162
  } else {
1163
- throw is.invalidParameterError('xres', 'number greater than zero', options.xres);
1163
+ throw is.invalidParameterError('xres', 'number between 0.001 and 1000000', options.xres);
1164
1164
  }
1165
1165
  }
1166
1166
  if (is.defined(options.yres)) {
1167
- if (is.number(options.yres) && options.yres > 0) {
1167
+ if (is.number(options.yres) && is.inRange(options.yres, 0.001, 1000000)) {
1168
1168
  this.options.tiffYres = options.yres;
1169
1169
  } else {
1170
- throw is.invalidParameterError('yres', 'number greater than zero', options.yres);
1170
+ throw is.invalidParameterError('yres', 'number between 0.001 and 1000000', options.yres);
1171
1171
  }
1172
1172
  }
1173
1173
  // compression
package/dist/resize.cjs CHANGED
@@ -386,48 +386,52 @@ function resize (widthOrOptions, height, options) {
386
386
  * ...
387
387
  *
388
388
  * @param {(number|Object)} extend - single pixel count to add to all edges or an Object with per-edge counts
389
- * @param {number} [extend.top=0]
390
- * @param {number} [extend.left=0]
391
- * @param {number} [extend.bottom=0]
392
- * @param {number} [extend.right=0]
389
+ * @param {number} [extend.top=0] - number of pixels to add to the top edge, valid values are integers in the range 0-10000
390
+ * @param {number} [extend.left=0] - number of pixels to add to the left edge, valid values are integers in the range 0-10000
391
+ * @param {number} [extend.bottom=0] - number of pixels to add to the bottom edge, valid values are integers in the range 0-10000
392
+ * @param {number} [extend.right=0] - number of pixels to add to the right edge, valid values are integers in the range 0-10000
393
393
  * @param {String} [extend.extendWith='background'] - populate new pixels using this method, one of: background, copy, repeat, mirror.
394
394
  * @param {String|Object} [extend.background={r: 0, g: 0, b: 0, alpha: 1}] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black without transparency.
395
395
  * @returns {Sharp}
396
396
  * @throws {Error} Invalid parameters
397
397
  */
398
398
  function extend (extend) {
399
- if (is.integer(extend) && extend > 0) {
400
- this.options.extendTop = extend;
401
- this.options.extendBottom = extend;
402
- this.options.extendLeft = extend;
403
- this.options.extendRight = extend;
399
+ if (is.integer(extend)) {
400
+ if (is.inRange(extend, 1, 10000)) {
401
+ this.options.extendTop = extend;
402
+ this.options.extendBottom = extend;
403
+ this.options.extendLeft = extend;
404
+ this.options.extendRight = extend;
405
+ } else {
406
+ throw is.invalidParameterError('extend', 'integer between 1 and 10000', extend);
407
+ }
404
408
  } else if (is.object(extend)) {
405
409
  if (is.defined(extend.top)) {
406
- if (is.integer(extend.top) && extend.top >= 0) {
410
+ if (is.integer(extend.top) && is.inRange(extend.top, 0, 10000)) {
407
411
  this.options.extendTop = extend.top;
408
412
  } else {
409
- throw is.invalidParameterError('top', 'positive integer', extend.top);
413
+ throw is.invalidParameterError('top', 'integer between 0 and 10000', extend.top);
410
414
  }
411
415
  }
412
416
  if (is.defined(extend.bottom)) {
413
- if (is.integer(extend.bottom) && extend.bottom >= 0) {
417
+ if (is.integer(extend.bottom) && is.inRange(extend.bottom, 0, 10000)) {
414
418
  this.options.extendBottom = extend.bottom;
415
419
  } else {
416
- throw is.invalidParameterError('bottom', 'positive integer', extend.bottom);
420
+ throw is.invalidParameterError('bottom', 'integer between 0 and 10000', extend.bottom);
417
421
  }
418
422
  }
419
423
  if (is.defined(extend.left)) {
420
- if (is.integer(extend.left) && extend.left >= 0) {
424
+ if (is.integer(extend.left) && is.inRange(extend.left, 0, 10000)) {
421
425
  this.options.extendLeft = extend.left;
422
426
  } else {
423
- throw is.invalidParameterError('left', 'positive integer', extend.left);
427
+ throw is.invalidParameterError('left', 'integer between 0 and 10000', extend.left);
424
428
  }
425
429
  }
426
430
  if (is.defined(extend.right)) {
427
- if (is.integer(extend.right) && extend.right >= 0) {
431
+ if (is.integer(extend.right) && is.inRange(extend.right, 0, 10000)) {
428
432
  this.options.extendRight = extend.right;
429
433
  } else {
430
- throw is.invalidParameterError('right', 'positive integer', extend.right);
434
+ throw is.invalidParameterError('right', 'integer between 0 and 10000', extend.right);
431
435
  }
432
436
  }
433
437
  this._setBackgroundColourOption('extendBackground', extend.background);
@@ -467,10 +471,10 @@ function extend (extend) {
467
471
  * });
468
472
  *
469
473
  * @param {Object} options - describes the region to extract using integral pixel values
470
- * @param {number} options.left - zero-indexed offset from left edge
471
- * @param {number} options.top - zero-indexed offset from top edge
472
- * @param {number} options.width - width of region to extract
473
- * @param {number} options.height - height of region to extract
474
+ * @param {number} options.left - zero-indexed offset from left edge, an integer between 0 and 100000000
475
+ * @param {number} options.top - zero-indexed offset from top edge, an integer between 0 and 100000000
476
+ * @param {number} options.width - width of region to extract, an integer between 0 and 100000000
477
+ * @param {number} options.height - height of region to extract, an integer between 0 and 100000000
474
478
  * @returns {Sharp}
475
479
  * @throws {Error} Invalid parameters
476
480
  */
@@ -481,10 +485,10 @@ function extract (options) {
481
485
  }
482
486
  ['left', 'top', 'width', 'height'].forEach(function (name) {
483
487
  const value = options[name];
484
- if (is.integer(value) && value >= 0) {
488
+ if (is.integer(value) && is.inRange(value, 0, 100000000)) {
485
489
  this.options[name + (name === 'left' || name === 'top' ? 'Offset' : '') + suffix] = value;
486
490
  } else {
487
- throw is.invalidParameterError(name, 'integer', value);
491
+ throw is.invalidParameterError(name, 'integer between 0 and 100000000', value);
488
492
  }
489
493
  }, this);
490
494
  // Ensure existing rotation occurs before pre-resize extraction
@@ -554,7 +558,7 @@ function extract (options) {
554
558
  * @param {string|Object} [options.background='top-left pixel'] - Background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to that of the top-left pixel.
555
559
  * @param {number} [options.threshold=10] - Allowed difference from the above colour, a positive number.
556
560
  * @param {boolean} [options.lineArt=false] - Does the input more closely resemble line art (e.g. vector) rather than being photographic?
557
- * @param {number} [options.margin=0] - Leave a margin around trimmed content, value is in pixels.
561
+ * @param {number} [options.margin=0] - Leave a margin around trimmed content, integral number of pixels between 0 and 10000000.
558
562
  * @returns {Sharp}
559
563
  * @throws {Error} Invalid parameters
560
564
  */
@@ -576,10 +580,10 @@ function trim (options) {
576
580
  this._setBooleanOption('trimLineArt', options.lineArt);
577
581
  }
578
582
  if (is.defined(options.margin)) {
579
- if (is.integer(options.margin) && options.margin >= 0) {
583
+ if (is.integer(options.margin) && is.inRange(options.margin, 0, 10000000)) {
580
584
  this.options.trimMargin = options.margin;
581
585
  } else {
582
- throw is.invalidParameterError('margin', 'positive integer', options.margin);
586
+ throw is.invalidParameterError('margin', 'integer between 0 and 10000000', options.margin);
583
587
  }
584
588
  }
585
589
  } else {
package/dist/resize.mjs CHANGED
@@ -386,48 +386,52 @@ function resize (widthOrOptions, height, options) {
386
386
  * ...
387
387
  *
388
388
  * @param {(number|Object)} extend - single pixel count to add to all edges or an Object with per-edge counts
389
- * @param {number} [extend.top=0]
390
- * @param {number} [extend.left=0]
391
- * @param {number} [extend.bottom=0]
392
- * @param {number} [extend.right=0]
389
+ * @param {number} [extend.top=0] - number of pixels to add to the top edge, valid values are integers in the range 0-10000
390
+ * @param {number} [extend.left=0] - number of pixels to add to the left edge, valid values are integers in the range 0-10000
391
+ * @param {number} [extend.bottom=0] - number of pixels to add to the bottom edge, valid values are integers in the range 0-10000
392
+ * @param {number} [extend.right=0] - number of pixels to add to the right edge, valid values are integers in the range 0-10000
393
393
  * @param {String} [extend.extendWith='background'] - populate new pixels using this method, one of: background, copy, repeat, mirror.
394
394
  * @param {String|Object} [extend.background={r: 0, g: 0, b: 0, alpha: 1}] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black without transparency.
395
395
  * @returns {Sharp}
396
396
  * @throws {Error} Invalid parameters
397
397
  */
398
398
  function extend (extend) {
399
- if (is.integer(extend) && extend > 0) {
400
- this.options.extendTop = extend;
401
- this.options.extendBottom = extend;
402
- this.options.extendLeft = extend;
403
- this.options.extendRight = extend;
399
+ if (is.integer(extend)) {
400
+ if (is.inRange(extend, 1, 10000)) {
401
+ this.options.extendTop = extend;
402
+ this.options.extendBottom = extend;
403
+ this.options.extendLeft = extend;
404
+ this.options.extendRight = extend;
405
+ } else {
406
+ throw is.invalidParameterError('extend', 'integer between 1 and 10000', extend);
407
+ }
404
408
  } else if (is.object(extend)) {
405
409
  if (is.defined(extend.top)) {
406
- if (is.integer(extend.top) && extend.top >= 0) {
410
+ if (is.integer(extend.top) && is.inRange(extend.top, 0, 10000)) {
407
411
  this.options.extendTop = extend.top;
408
412
  } else {
409
- throw is.invalidParameterError('top', 'positive integer', extend.top);
413
+ throw is.invalidParameterError('top', 'integer between 0 and 10000', extend.top);
410
414
  }
411
415
  }
412
416
  if (is.defined(extend.bottom)) {
413
- if (is.integer(extend.bottom) && extend.bottom >= 0) {
417
+ if (is.integer(extend.bottom) && is.inRange(extend.bottom, 0, 10000)) {
414
418
  this.options.extendBottom = extend.bottom;
415
419
  } else {
416
- throw is.invalidParameterError('bottom', 'positive integer', extend.bottom);
420
+ throw is.invalidParameterError('bottom', 'integer between 0 and 10000', extend.bottom);
417
421
  }
418
422
  }
419
423
  if (is.defined(extend.left)) {
420
- if (is.integer(extend.left) && extend.left >= 0) {
424
+ if (is.integer(extend.left) && is.inRange(extend.left, 0, 10000)) {
421
425
  this.options.extendLeft = extend.left;
422
426
  } else {
423
- throw is.invalidParameterError('left', 'positive integer', extend.left);
427
+ throw is.invalidParameterError('left', 'integer between 0 and 10000', extend.left);
424
428
  }
425
429
  }
426
430
  if (is.defined(extend.right)) {
427
- if (is.integer(extend.right) && extend.right >= 0) {
431
+ if (is.integer(extend.right) && is.inRange(extend.right, 0, 10000)) {
428
432
  this.options.extendRight = extend.right;
429
433
  } else {
430
- throw is.invalidParameterError('right', 'positive integer', extend.right);
434
+ throw is.invalidParameterError('right', 'integer between 0 and 10000', extend.right);
431
435
  }
432
436
  }
433
437
  this._setBackgroundColourOption('extendBackground', extend.background);
@@ -467,10 +471,10 @@ function extend (extend) {
467
471
  * });
468
472
  *
469
473
  * @param {Object} options - describes the region to extract using integral pixel values
470
- * @param {number} options.left - zero-indexed offset from left edge
471
- * @param {number} options.top - zero-indexed offset from top edge
472
- * @param {number} options.width - width of region to extract
473
- * @param {number} options.height - height of region to extract
474
+ * @param {number} options.left - zero-indexed offset from left edge, an integer between 0 and 100000000
475
+ * @param {number} options.top - zero-indexed offset from top edge, an integer between 0 and 100000000
476
+ * @param {number} options.width - width of region to extract, an integer between 0 and 100000000
477
+ * @param {number} options.height - height of region to extract, an integer between 0 and 100000000
474
478
  * @returns {Sharp}
475
479
  * @throws {Error} Invalid parameters
476
480
  */
@@ -481,10 +485,10 @@ function extract (options) {
481
485
  }
482
486
  ['left', 'top', 'width', 'height'].forEach(function (name) {
483
487
  const value = options[name];
484
- if (is.integer(value) && value >= 0) {
488
+ if (is.integer(value) && is.inRange(value, 0, 100000000)) {
485
489
  this.options[name + (name === 'left' || name === 'top' ? 'Offset' : '') + suffix] = value;
486
490
  } else {
487
- throw is.invalidParameterError(name, 'integer', value);
491
+ throw is.invalidParameterError(name, 'integer between 0 and 100000000', value);
488
492
  }
489
493
  }, this);
490
494
  // Ensure existing rotation occurs before pre-resize extraction
@@ -554,7 +558,7 @@ function extract (options) {
554
558
  * @param {string|Object} [options.background='top-left pixel'] - Background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to that of the top-left pixel.
555
559
  * @param {number} [options.threshold=10] - Allowed difference from the above colour, a positive number.
556
560
  * @param {boolean} [options.lineArt=false] - Does the input more closely resemble line art (e.g. vector) rather than being photographic?
557
- * @param {number} [options.margin=0] - Leave a margin around trimmed content, value is in pixels.
561
+ * @param {number} [options.margin=0] - Leave a margin around trimmed content, integral number of pixels between 0 and 10000000.
558
562
  * @returns {Sharp}
559
563
  * @throws {Error} Invalid parameters
560
564
  */
@@ -576,10 +580,10 @@ function trim (options) {
576
580
  this._setBooleanOption('trimLineArt', options.lineArt);
577
581
  }
578
582
  if (is.defined(options.margin)) {
579
- if (is.integer(options.margin) && options.margin >= 0) {
583
+ if (is.integer(options.margin) && is.inRange(options.margin, 0, 10000000)) {
580
584
  this.options.trimMargin = options.margin;
581
585
  } else {
582
- throw is.invalidParameterError('margin', 'positive integer', options.margin);
586
+ throw is.invalidParameterError('margin', 'integer between 0 and 10000000', options.margin);
583
587
  }
584
588
  }
585
589
  } else {
package/dist/sharp.cjs CHANGED
@@ -89,6 +89,12 @@ if (!sharp) {
89
89
  errors.push(err);
90
90
  sharp = null;
91
91
  }
92
+ if (sharp && process.versions.electron && runtimePlatform.startsWith("linux")) {
93
+ process.emitWarning(
94
+ "Binaries provided by Electron for use on Linux may be incompatible with sharp - see https://sharp.pixelplumbing.com/install#electron-and-linux",
95
+ { code: "SharpElectronLinux" }
96
+ );
97
+ }
92
98
  } catch (err) {
93
99
  errors.push(err);
94
100
  }
package/dist/sharp.mjs CHANGED
@@ -89,6 +89,12 @@ if (!sharp) {
89
89
  errors.push(err);
90
90
  sharp = null;
91
91
  }
92
+ if (sharp && process.versions.electron && runtimePlatform.startsWith("linux")) {
93
+ process.emitWarning(
94
+ "Binaries provided by Electron for use on Linux may be incompatible with sharp - see https://sharp.pixelplumbing.com/install#electron-and-linux",
95
+ { code: "SharpElectronLinux" }
96
+ );
97
+ }
92
98
  } catch (err) {
93
99
  errors.push(err);
94
100
  }
package/dist/utility.cjs CHANGED
@@ -114,6 +114,12 @@ function cache (options) {
114
114
  return sharp.cache(0, 0, 0);
115
115
  }
116
116
  } else if (is.object(options)) {
117
+ for (const property of ['memory', 'files', 'items']) {
118
+ const value = options[property];
119
+ if (is.defined(value) && !(is.integer(value) && value >= 0)) {
120
+ throw is.invalidParameterError(property, 'a positive integer', value);
121
+ }
122
+ }
117
123
  return sharp.cache(options.memory, options.files, options.items);
118
124
  } else {
119
125
  return sharp.cache();
@@ -155,7 +161,7 @@ function concurrency (concurrency) {
155
161
  return sharp.concurrency(is.integer(concurrency) ? concurrency : null);
156
162
  }
157
163
  /* node:coverage ignore next 7 */
158
- if (detectLibc.familySync() === detectLibc.GLIBC && !sharp._isUsingJemalloc()) {
164
+ if (!process.env.MALLOC_ARENA_MAX && detectLibc.familySync() === detectLibc.GLIBC && !sharp._isUsingJemalloc()) {
159
165
  // Reduce default concurrency to 1 when using glibc memory allocator
160
166
  sharp.concurrency(1);
161
167
  } else if (detectLibc.familySync() === detectLibc.MUSL && sharp.concurrency() === 1024) {
package/dist/utility.mjs CHANGED
@@ -114,6 +114,12 @@ function cache (options) {
114
114
  return sharp.cache(0, 0, 0);
115
115
  }
116
116
  } else if (is.object(options)) {
117
+ for (const property of ['memory', 'files', 'items']) {
118
+ const value = options[property];
119
+ if (is.defined(value) && !(is.integer(value) && value >= 0)) {
120
+ throw is.invalidParameterError(property, 'a positive integer', value);
121
+ }
122
+ }
117
123
  return sharp.cache(options.memory, options.files, options.items);
118
124
  } else {
119
125
  return sharp.cache();
@@ -155,7 +161,7 @@ function concurrency (concurrency) {
155
161
  return sharp.concurrency(is.integer(concurrency) ? concurrency : null);
156
162
  }
157
163
  /* node:coverage ignore next 7 */
158
- if (detectLibc.familySync() === detectLibc.GLIBC && !sharp._isUsingJemalloc()) {
164
+ if (!process.env.MALLOC_ARENA_MAX && detectLibc.familySync() === detectLibc.GLIBC && !sharp._isUsingJemalloc()) {
159
165
  // Reduce default concurrency to 1 when using glibc memory allocator
160
166
  sharp.concurrency(1);
161
167
  } else if (detectLibc.familySync() === detectLibc.MUSL && sharp.concurrency() === 1024) {
package/lib/index.d.ts CHANGED
@@ -1508,11 +1508,11 @@ declare namespace sharp {
1508
1508
  tile?: boolean | undefined;
1509
1509
  /** Horizontal tile size (optional, default 256) */
1510
1510
  tileWidth?: number | undefined;
1511
- /** Vertical tile size (optional, default 256) */
1511
+ /** Vertical tile size, valid values are integers in the range 1-32768 (optional, default 256) */
1512
1512
  tileHeight?: number | undefined;
1513
- /** Horizontal resolution in pixels/mm (optional, default 1.0) */
1513
+ /** Horizontal resolution in pixels/mm, valid values are numbers in the range 0.001-1000000 (optional, default 1.0) */
1514
1514
  xres?: number | undefined;
1515
- /** Vertical resolution in pixels/mm (optional, default 1.0) */
1515
+ /** Vertical resolution in pixels/mm, valid values are numbers in the range 0.001-1000000 (optional, default 1.0) */
1516
1516
  yres?: number | undefined;
1517
1517
  /** Reduce bitdepth to 1, 2 or 4 bit (optional) */
1518
1518
  bitdepth?: 1 | 2 | 4 | undefined;
@@ -1598,13 +1598,13 @@ declare namespace sharp {
1598
1598
  }
1599
1599
 
1600
1600
  interface Region {
1601
- /** zero-indexed offset from left edge */
1601
+ /** zero-indexed offset from left edge, an integer between 0 and 100000000 */
1602
1602
  left: number;
1603
- /** zero-indexed offset from top edge */
1603
+ /** zero-indexed offset from top edge, an integer between 0 and 100000000 */
1604
1604
  top: number;
1605
- /** dimension of extracted image */
1605
+ /** dimension of extracted image, an integer between 0 and 100000000 */
1606
1606
  width: number;
1607
- /** dimension of extracted image */
1607
+ /** dimension of extracted image, an integer between 0 and 100000000 */
1608
1608
  height: number;
1609
1609
  }
1610
1610
 
@@ -1620,13 +1620,13 @@ declare namespace sharp {
1620
1620
  type ExtendWith = 'background' | 'copy' | 'repeat' | 'mirror';
1621
1621
 
1622
1622
  interface ExtendOptions {
1623
- /** single pixel count to top edge (optional, default 0) */
1623
+ /** single pixel count to top edge, valid values are integers in the range 0-10000 (optional, default 0) */
1624
1624
  top?: number | undefined;
1625
- /** single pixel count to left edge (optional, default 0) */
1625
+ /** single pixel count to left edge, valid values are integers in the range 0-10000 (optional, default 0) */
1626
1626
  left?: number | undefined;
1627
- /** single pixel count to bottom edge (optional, default 0) */
1627
+ /** single pixel count to bottom edge, valid values are integers in the range 0-10000 (optional, default 0) */
1628
1628
  bottom?: number | undefined;
1629
- /** single pixel count to right edge (optional, default 0) */
1629
+ /** single pixel count to right edge, valid values are integers in the range 0-10000 (optional, default 0) */
1630
1630
  right?: number | undefined;
1631
1631
  /** background colour, parsed by the color module, defaults to black without transparency. (optional, default {r:0,g:0,b:0,alpha:1}) */
1632
1632
  background?: ColorLike | undefined;
@@ -1641,7 +1641,7 @@ declare namespace sharp {
1641
1641
  threshold?: number | undefined;
1642
1642
  /** Does the input more closely resemble line art (e.g. vector) rather than being photographic? (optional, default false) */
1643
1643
  lineArt?: boolean | undefined;
1644
- /** Leave a margin around trimmed content, value is in pixels. (optional, default 0) */
1644
+ /** Leave a margin around trimmed content, integral number of pixels between 0 and 10000000. (optional, default 0) */
1645
1645
  margin?: number | undefined;
1646
1646
  }
1647
1647
 
@@ -1669,11 +1669,11 @@ declare namespace sharp {
1669
1669
  }
1670
1670
 
1671
1671
  interface ClaheOptions {
1672
- /** width of the region */
1672
+ /** width of the region. Valid values are integers in the range 1-65536. */
1673
1673
  width: number;
1674
- /** height of the region */
1674
+ /** height of the region. Valid values are integers in the range 1-65536. */
1675
1675
  height: number;
1676
- /** max slope of the cumulative contrast. A value of 0 disables contrast limiting. Valid values are integers in the range 0-100 (inclusive) (optional, default 3) */
1676
+ /** max slope of the cumulative contrast. A value of 0 disables contrast limiting. Valid values are integers in the range 0-100. (optional, default 3) */
1677
1677
  maxSlope?: number | undefined;
1678
1678
  }
1679
1679
 
@@ -1783,6 +1783,8 @@ declare namespace sharp {
1783
1783
  channels: Channels;
1784
1784
  /** indicating if premultiplication was used */
1785
1785
  premultiplied: boolean;
1786
+ /** Indicates if the output image has an alpha channel */
1787
+ hasAlpha: boolean;
1786
1788
  /** Only defined when using a crop strategy */
1787
1789
  cropOffsetLeft?: number | undefined;
1788
1790
  /** Only defined when using a crop strategy */
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.2",
4
+ "version": "0.35.3-rc.1",
5
5
  "author": "Lovell Fuller <npm@lovell.info>",
6
6
  "homepage": "https://sharp.pixelplumbing.com",
7
7
  "contributors": [
@@ -160,44 +160,44 @@
160
160
  "dependencies": {
161
161
  "@img/colour": "^1.1.0",
162
162
  "detect-libc": "^2.1.2",
163
- "semver": "^7.8.4"
163
+ "semver": "^7.8.5"
164
164
  },
165
165
  "optionalDependencies": {
166
- "@img/sharp-darwin-arm64": "0.35.2",
167
- "@img/sharp-darwin-x64": "0.35.2",
168
- "@img/sharp-freebsd-wasm32": "0.35.2",
169
- "@img/sharp-libvips-darwin-arm64": "1.3.1",
170
- "@img/sharp-libvips-darwin-x64": "1.3.1",
171
- "@img/sharp-libvips-linux-arm": "1.3.1",
172
- "@img/sharp-libvips-linux-arm64": "1.3.1",
173
- "@img/sharp-libvips-linux-ppc64": "1.3.1",
174
- "@img/sharp-libvips-linux-riscv64": "1.3.1",
175
- "@img/sharp-libvips-linux-s390x": "1.3.1",
176
- "@img/sharp-libvips-linux-x64": "1.3.1",
177
- "@img/sharp-libvips-linuxmusl-arm64": "1.3.1",
178
- "@img/sharp-libvips-linuxmusl-x64": "1.3.1",
179
- "@img/sharp-linux-arm": "0.35.2",
180
- "@img/sharp-linux-arm64": "0.35.2",
181
- "@img/sharp-linux-ppc64": "0.35.2",
182
- "@img/sharp-linux-riscv64": "0.35.2",
183
- "@img/sharp-linux-s390x": "0.35.2",
184
- "@img/sharp-linux-x64": "0.35.2",
185
- "@img/sharp-linuxmusl-arm64": "0.35.2",
186
- "@img/sharp-linuxmusl-x64": "0.35.2",
187
- "@img/sharp-webcontainers-wasm32": "0.35.2",
188
- "@img/sharp-win32-arm64": "0.35.2",
189
- "@img/sharp-win32-ia32": "0.35.2",
190
- "@img/sharp-win32-x64": "0.35.2"
166
+ "@img/sharp-darwin-arm64": "0.35.3-rc.1",
167
+ "@img/sharp-darwin-x64": "0.35.3-rc.1",
168
+ "@img/sharp-freebsd-wasm32": "0.35.3-rc.1",
169
+ "@img/sharp-libvips-darwin-arm64": "1.3.2-rc.0",
170
+ "@img/sharp-libvips-darwin-x64": "1.3.2-rc.0",
171
+ "@img/sharp-libvips-linux-arm": "1.3.2-rc.0",
172
+ "@img/sharp-libvips-linux-arm64": "1.3.2-rc.0",
173
+ "@img/sharp-libvips-linux-ppc64": "1.3.2-rc.0",
174
+ "@img/sharp-libvips-linux-riscv64": "1.3.2-rc.0",
175
+ "@img/sharp-libvips-linux-s390x": "1.3.2-rc.0",
176
+ "@img/sharp-libvips-linux-x64": "1.3.2-rc.0",
177
+ "@img/sharp-libvips-linuxmusl-arm64": "1.3.2-rc.0",
178
+ "@img/sharp-libvips-linuxmusl-x64": "1.3.2-rc.0",
179
+ "@img/sharp-linux-arm": "0.35.3-rc.1",
180
+ "@img/sharp-linux-arm64": "0.35.3-rc.1",
181
+ "@img/sharp-linux-ppc64": "0.35.3-rc.1",
182
+ "@img/sharp-linux-riscv64": "0.35.3-rc.1",
183
+ "@img/sharp-linux-s390x": "0.35.3-rc.1",
184
+ "@img/sharp-linux-x64": "0.35.3-rc.1",
185
+ "@img/sharp-linuxmusl-arm64": "0.35.3-rc.1",
186
+ "@img/sharp-linuxmusl-x64": "0.35.3-rc.1",
187
+ "@img/sharp-webcontainers-wasm32": "0.35.3-rc.1",
188
+ "@img/sharp-win32-arm64": "0.35.3-rc.1",
189
+ "@img/sharp-win32-ia32": "0.35.3-rc.1",
190
+ "@img/sharp-win32-x64": "0.35.3-rc.1"
191
191
  },
192
192
  "devDependencies": {
193
- "@biomejs/biome": "^2.5.0",
193
+ "@biomejs/biome": "^2.5.1",
194
194
  "@cpplint/cli": "^0.1.0",
195
195
  "@emnapi/runtime": "^1.11.1",
196
- "@img/sharp-libvips-dev": "1.3.1",
197
- "@img/sharp-libvips-dev-wasm32": "1.3.1",
198
- "@img/sharp-libvips-win32-arm64": "1.3.1",
199
- "@img/sharp-libvips-win32-ia32": "1.3.1",
200
- "@img/sharp-libvips-win32-x64": "1.3.1",
196
+ "@img/sharp-libvips-dev": "1.3.2-rc.0",
197
+ "@img/sharp-libvips-dev-wasm32": "1.3.2-rc.0",
198
+ "@img/sharp-libvips-win32-arm64": "1.3.2-rc.0",
199
+ "@img/sharp-libvips-win32-ia32": "1.3.2-rc.0",
200
+ "@img/sharp-libvips-win32-x64": "1.3.2-rc.0",
201
201
  "@types/node": "*",
202
202
  "emnapi": "^1.11.1",
203
203
  "exif-reader": "^2.0.3",
package/src/pipeline.cc CHANGED
@@ -608,38 +608,25 @@ class PipelineWorker : public Napi::AsyncWorker {
608
608
  baton->width = image.width() + baton->extendLeft + baton->extendRight;
609
609
  baton->height = (nPages > 1 ? targetPageHeight : image.height()) + baton->extendTop + baton->extendBottom;
610
610
 
611
+ std::vector<double> background;
611
612
  if (baton->extendWith == VIPS_EXTEND_BACKGROUND) {
612
- std::vector<double> background;
613
613
  std::tie(image, background) = sharp::ApplyAlpha(image, baton->extendBackground, shouldPremultiplyAlpha);
614
-
615
- image = sharp::StaySequential(image, nPages > 1);
616
- image = nPages > 1
617
- ? sharp::EmbedMultiPage(image,
618
- baton->extendLeft, baton->extendTop, baton->width, baton->height,
619
- baton->extendWith, background, nPages, &targetPageHeight)
620
- : image.embed(baton->extendLeft, baton->extendTop, baton->width, baton->height,
621
- VImage::option()->set("extend", baton->extendWith)->set("background", background));
622
- if (baton->keepGainMap) {
623
- gainMap = gainMap.embed(baton->extendLeft / gainMapScaleFactor, baton->extendTop / gainMapScaleFactor,
624
- baton->width / gainMapScaleFactor, baton->height / gainMapScaleFactor, VImage::option()
625
- ->set("extend", baton->extendWith)
626
- ->set("background", 0));
627
- }
628
- } else {
629
- std::vector<double> ignoredBackground(1);
630
- image = sharp::StaySequential(image);
631
- image = nPages > 1
632
- ? sharp::EmbedMultiPage(image,
633
- baton->extendLeft, baton->extendTop, baton->width, baton->height,
634
- baton->extendWith, ignoredBackground, nPages, &targetPageHeight)
635
- : image.embed(baton->extendLeft, baton->extendTop, baton->width, baton->height,
636
- VImage::option()->set("extend", baton->extendWith));
637
- if (baton->keepGainMap) {
638
- gainMap = gainMap.embed(baton->extendLeft / gainMapScaleFactor, baton->extendTop / gainMapScaleFactor,
639
- baton->width / gainMapScaleFactor, baton->height / gainMapScaleFactor, VImage::option()
640
- ->set("extend", baton->extendWith)
641
- ->set("background", 0));
642
- }
614
+ }
615
+ image = sharp::StaySequential(image, nPages > 1 || baton->extendWith != VIPS_EXTEND_BACKGROUND);
616
+ auto options = VImage::option()->set("extend", baton->extendWith);
617
+ if (baton->extendWith == VIPS_EXTEND_BACKGROUND) {
618
+ options->set("background", background);
619
+ }
620
+ image = nPages > 1
621
+ ? sharp::EmbedMultiPage(image,
622
+ baton->extendLeft, baton->extendTop, baton->width, baton->height,
623
+ baton->extendWith, background, nPages, &targetPageHeight)
624
+ : image.embed(baton->extendLeft, baton->extendTop, baton->width, baton->height, options);
625
+ if (baton->keepGainMap) {
626
+ gainMap = gainMap.embed(baton->extendLeft / gainMapScaleFactor, baton->extendTop / gainMapScaleFactor,
627
+ baton->width / gainMapScaleFactor, baton->height / gainMapScaleFactor, VImage::option()
628
+ ->set("extend", baton->extendWith)
629
+ ->set("background", 0));
643
630
  }
644
631
  }
645
632
  // Median - must happen before blurring, due to the utility of blurring after thresholding
@@ -957,6 +944,7 @@ class PipelineWorker : public Napi::AsyncWorker {
957
944
  baton->pageHeightOut = image.get_int(VIPS_META_PAGE_HEIGHT);
958
945
  baton->pagesOut = image.get_int(VIPS_META_N_PAGES);
959
946
  }
947
+ baton->hasAlphaOut = image.has_alpha();
960
948
 
961
949
  // Output
962
950
  sharp::SetTimeout(image, baton->timeoutSeconds);
@@ -996,6 +984,7 @@ class PipelineWorker : public Napi::AsyncWorker {
996
984
  } else {
997
985
  baton->channels = std::min(baton->channels, 3);
998
986
  }
987
+ baton->hasAlphaOut = false;
999
988
  } else if (baton->formatOut == "jp2" || (baton->formatOut == "input"
1000
989
  && inputImageType == sharp::ImageType::JP2)) {
1001
990
  // Write JP2 to Buffer
@@ -1078,6 +1067,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1078
1067
  if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) {
1079
1068
  sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
1080
1069
  baton->channels = std::min(baton->channels, 3);
1070
+ baton->hasAlphaOut = false;
1081
1071
  }
1082
1072
  // Cast pixel values to float, if required
1083
1073
  if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) {
@@ -1137,6 +1127,9 @@ class PipelineWorker : public Napi::AsyncWorker {
1137
1127
  area->free_fn = nullptr;
1138
1128
  vips_area_unref(area);
1139
1129
  baton->formatOut = "dz";
1130
+ if (baton->tileFormat == "jpeg") {
1131
+ baton->hasAlphaOut = false;
1132
+ }
1140
1133
  } else if (baton->formatOut == "jxl" ||
1141
1134
  (baton->formatOut == "input" && inputImageType == sharp::ImageType::JXL)) {
1142
1135
  // Write JXL to buffer
@@ -1224,6 +1217,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1224
1217
  }
1225
1218
  baton->formatOut = "jpeg";
1226
1219
  baton->channels = std::min(baton->channels, 3);
1220
+ baton->hasAlphaOut = false;
1227
1221
  } else if (baton->formatOut == "jp2" || (mightMatchInput && isJp2) ||
1228
1222
  (willMatchInput && (inputImageType == sharp::ImageType::JP2))) {
1229
1223
  // Write JP2 to file
@@ -1290,6 +1284,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1290
1284
  if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) {
1291
1285
  sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
1292
1286
  baton->channels = std::min(baton->channels, 3);
1287
+ baton->hasAlphaOut = false;
1293
1288
  }
1294
1289
  // Cast pixel values to float, if required
1295
1290
  if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) {
@@ -1350,6 +1345,9 @@ class PipelineWorker : public Napi::AsyncWorker {
1350
1345
  vips::VOption *options = BuildOptionsDZ(baton);
1351
1346
  image.dzsave(const_cast<char*>(baton->fileOut.data()), options);
1352
1347
  baton->formatOut = "dz";
1348
+ if (baton->tileFormat == "jpeg") {
1349
+ baton->hasAlphaOut = false;
1350
+ }
1353
1351
  } else if (baton->formatOut == "v" || (mightMatchInput && isV) ||
1354
1352
  (willMatchInput && inputImageType == sharp::ImageType::VIPS)) {
1355
1353
  // Write V to file
@@ -1434,6 +1432,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1434
1432
  info.Set("pageHeight", static_cast<int32_t>(baton->pageHeightOut));
1435
1433
  info.Set("pages", static_cast<int32_t>(baton->pagesOut));
1436
1434
  }
1435
+ info.Set("hasAlpha", baton->hasAlphaOut);
1437
1436
 
1438
1437
  if (baton->bufferOutLength > 0) {
1439
1438
  info.Set("size", static_cast<uint32_t>(baton->bufferOutLength));
package/src/pipeline.h CHANGED
@@ -49,6 +49,7 @@ struct PipelineBaton {
49
49
  int pageHeightOut;
50
50
  int pagesOut;
51
51
  bool typedArrayOut;
52
+ bool hasAlphaOut;
52
53
  std::vector<Composite *> composite;
53
54
  std::vector<sharp::InputDescriptor *> joinChannelIn;
54
55
  int topOffsetPre;
@@ -249,6 +250,7 @@ struct PipelineBaton {
249
250
  pageHeightOut(0),
250
251
  pagesOut(0),
251
252
  typedArrayOut(false),
253
+ hasAlphaOut(false),
252
254
  topOffsetPre(-1),
253
255
  topOffsetPost(-1),
254
256
  channels(0),
package/src/utilities.cc CHANGED
@@ -23,15 +23,15 @@ Napi::Value cache(const Napi::CallbackInfo& info) {
23
23
 
24
24
  // Set memory limit
25
25
  if (info[size_t(0)].IsNumber()) {
26
- vips_cache_set_max_mem(info[size_t(0)].As<Napi::Number>().Int32Value() * 1048576);
26
+ vips_cache_set_max_mem(static_cast<size_t>(info[size_t(0)].As<Napi::Number>().Uint32Value()) * 1048576);
27
27
  }
28
28
  // Set file limit
29
29
  if (info[size_t(1)].IsNumber()) {
30
- vips_cache_set_max_files(info[size_t(1)].As<Napi::Number>().Int32Value());
30
+ vips_cache_set_max_files(info[size_t(1)].As<Napi::Number>().Uint32Value());
31
31
  }
32
32
  // Set items limit
33
33
  if (info[size_t(2)].IsNumber()) {
34
- vips_cache_set_max(info[size_t(2)].As<Napi::Number>().Int32Value());
34
+ vips_cache_set_max(info[size_t(2)].As<Napi::Number>().Uint32Value());
35
35
  }
36
36
 
37
37
  // Get memory stats