sharp 0.26.3 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  The typical use case for this high speed Node.js module
6
6
  is to convert large images in common formats to
7
- smaller, web-friendly JPEG, PNG and WebP images of varying dimensions.
7
+ smaller, web-friendly JPEG, PNG, WebP and AVIF images of varying dimensions.
8
8
 
9
9
  Resizing an image is typically 4x-5x faster than using the
10
10
  quickest ImageMagick and GraphicsMagick settings
package/lib/channel.js CHANGED
@@ -85,7 +85,7 @@ function extractChannel (channel) {
85
85
  * - sRGB: 0: Red, 1: Green, 2: Blue, 3: Alpha.
86
86
  * - CMYK: 0: Magenta, 1: Cyan, 2: Yellow, 3: Black, 4: Alpha.
87
87
  *
88
- * Buffers may be any of the image formats supported by sharp: JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data.
88
+ * Buffers may be any of the image formats supported by sharp.
89
89
  * For raw pixel input, the `options` object should contain a `raw` attribute, which follows the format of the attribute of the same name in the `sharp()` constructor.
90
90
  *
91
91
  * @param {Array<string|Buffer>|string|Buffer} images - one or more images (file paths, Buffers).
package/lib/composite.js CHANGED
@@ -105,8 +105,9 @@ function composite (images) {
105
105
  input: this._createInputDescriptor(image.input, inputOptions, { allowStream: false }),
106
106
  blend: 'over',
107
107
  tile: false,
108
- left: -1,
109
- top: -1,
108
+ left: 0,
109
+ top: 0,
110
+ hasOffset: false,
110
111
  gravity: 0,
111
112
  premultiplied: false
112
113
  };
@@ -125,21 +126,23 @@ function composite (images) {
125
126
  }
126
127
  }
127
128
  if (is.defined(image.left)) {
128
- if (is.integer(image.left) && image.left >= 0) {
129
+ if (is.integer(image.left)) {
129
130
  composite.left = image.left;
130
131
  } else {
131
- throw is.invalidParameterError('left', 'positive integer', image.left);
132
+ throw is.invalidParameterError('left', 'integer', image.left);
132
133
  }
133
134
  }
134
135
  if (is.defined(image.top)) {
135
- if (is.integer(image.top) && image.top >= 0) {
136
+ if (is.integer(image.top)) {
136
137
  composite.top = image.top;
137
138
  } else {
138
- throw is.invalidParameterError('top', 'positive integer', image.top);
139
+ throw is.invalidParameterError('top', 'integer', image.top);
139
140
  }
140
141
  }
141
- if (composite.left !== composite.top && Math.min(composite.left, composite.top) === -1) {
142
+ if (is.defined(image.top) !== is.defined(image.left)) {
142
143
  throw new Error('Expected both left and top to be set');
144
+ } else {
145
+ composite.hasOffset = is.integer(image.top) && is.integer(image.left);
143
146
  }
144
147
  if (is.defined(image.gravity)) {
145
148
  if (is.integer(image.gravity) && is.inRange(image.gravity, 0, 8)) {
@@ -40,7 +40,7 @@ const debuglog = util.debuglog('sharp');
40
40
  /**
41
41
  * Constructor factory to create an instance of `sharp`, to which further methods are chained.
42
42
  *
43
- * JPEG, PNG, WebP or TIFF format image data can be streamed out from this object.
43
+ * JPEG, PNG, WebP, AVIF or TIFF format image data can be streamed out from this object.
44
44
  * When using Stream based output, derived attributes are available from the `info` event.
45
45
  *
46
46
  * Non-critical problems encountered during processing are emitted as `warning` events.
@@ -91,9 +91,9 @@ const debuglog = util.debuglog('sharp');
91
91
  * await sharp('in.gif', { animated: true }).toFile('out.webp');
92
92
  *
93
93
  * @param {(Buffer|string)} [input] - if present, can be
94
- * a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
95
- * a String containing the filesystem path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
96
- * JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
94
+ * a Buffer containing JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data, or
95
+ * a String containing the filesystem path to an JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image file.
96
+ * JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
97
97
  * @param {Object} [options] - if present, is an Object with optional attributes.
98
98
  * @param {boolean} [options.failOnError=true] - by default halt processing and raise an error when loading invalid images.
99
99
  * Set this flag to `false` if you'd rather apply a "best effort" to decode images, even if the data is corrupt or invalid.
@@ -103,8 +103,8 @@ const debuglog = util.debuglog('sharp');
103
103
  * @param {boolean} [options.sequentialRead=false] - Set this to `true` to use sequential rather than random access where possible.
104
104
  * This can reduce memory usage and might improve performance on some systems.
105
105
  * @param {number} [options.density=72] - number representing the DPI for vector images in the range 1 to 100000.
106
- * @param {number} [options.pages=1] - number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages.
107
- * @param {number} [options.page=0] - page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based.
106
+ * @param {number} [options.pages=1] - number of pages to extract for multi-page input (GIF, WebP, AVIF, TIFF, PDF), use -1 for all pages.
107
+ * @param {number} [options.page=0] - page number to start extracting from for multi-page input (GIF, WebP, AVIF, TIFF, PDF), zero based.
108
108
  * @param {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based.
109
109
  * @param {boolean} [options.animated=false] - Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`).
110
110
  * @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering.
@@ -233,9 +233,10 @@ const Sharp = function (input, options) {
233
233
  tiffTileWidth: 256,
234
234
  tiffXres: 1.0,
235
235
  tiffYres: 1.0,
236
- heifQuality: 80,
236
+ heifQuality: 50,
237
237
  heifLossless: false,
238
- heifCompression: 'hevc',
238
+ heifCompression: 'av1',
239
+ heifSpeed: 5,
239
240
  tileSize: 256,
240
241
  tileOverlap: 0,
241
242
  tileContainer: 'fs',
package/lib/output.js CHANGED
@@ -6,6 +6,7 @@ const sharp = require('../build/Release/sharp.node');
6
6
  const formats = new Map([
7
7
  ['heic', 'heif'],
8
8
  ['heif', 'heif'],
9
+ ['avif', 'avif'],
9
10
  ['jpeg', 'jpeg'],
10
11
  ['jpg', 'jpeg'],
11
12
  ['png', 'png'],
@@ -19,7 +20,7 @@ const formats = new Map([
19
20
  * Write output image data to a file.
20
21
  *
21
22
  * If an explicit output format is not selected, it will be inferred from the extension,
22
- * with JPEG, PNG, WebP, TIFF, DZI, and libvips' V format supported.
23
+ * with JPEG, PNG, WebP, AVIF, TIFF, DZI, and libvips' V format supported.
23
24
  * Note that raw pixel data is only supported for buffer output.
24
25
  *
25
26
  * By default all metadata will be removed, which includes EXIF-based orientation.
@@ -71,7 +72,7 @@ function toFile (fileOut, callback) {
71
72
 
72
73
  /**
73
74
  * Write output to a Buffer.
74
- * JPEG, PNG, WebP, TIFF and RAW output are supported.
75
+ * JPEG, PNG, WebP, AVIF, TIFF and raw pixel data output are supported.
75
76
  *
76
77
  * If no explicit format is set, the output format will match the input image, except GIF and SVG input which become PNG output.
77
78
  *
@@ -557,28 +558,41 @@ function tiff (options) {
557
558
  }
558
559
 
559
560
  /**
560
- * Use these HEIF options for output image.
561
+ * Use these AVIF options for output image.
562
+ *
563
+ * Whilst it is possible to create AVIF images smaller than 16x16 pixels,
564
+ * most web browsers do not display these properly.
561
565
  *
562
- * Support for HEIF (HEIC/AVIF) is experimental.
563
- * Do not use this in production systems.
566
+ * @since 0.27.0
564
567
  *
565
- * Requires a custom, globally-installed libvips compiled with support for libheif.
568
+ * @param {Object} [options] - output options
569
+ * @param {number} [options.quality=50] - quality, integer 1-100
570
+ * @param {boolean} [options.lossless=false] - use lossless compression
571
+ * @param {boolean} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest)
572
+ * @returns {Sharp}
573
+ * @throws {Error} Invalid options
574
+ */
575
+ function avif (options) {
576
+ return this.heif({ ...options, compression: 'av1' });
577
+ }
578
+
579
+ /**
580
+ * Use these HEIF options for output image.
566
581
  *
567
- * Most versions of libheif support only the patent-encumbered HEVC compression format.
582
+ * Support for patent-encumbered HEIC images requires the use of a
583
+ * globally-installed libvips compiled with support for libheif, libde265 and x265.
568
584
  *
569
585
  * @since 0.23.0
570
586
  *
571
587
  * @param {Object} [options] - output options
572
- * @param {number} [options.quality=80] - quality, integer 1-100
573
- * @param {boolean} [options.compression='hevc'] - compression format: hevc, avc, jpeg, av1
588
+ * @param {number} [options.quality=50] - quality, integer 1-100
589
+ * @param {boolean} [options.compression='av1'] - compression format: av1, hevc
574
590
  * @param {boolean} [options.lossless=false] - use lossless compression
591
+ * @param {boolean} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest)
575
592
  * @returns {Sharp}
576
593
  * @throws {Error} Invalid options
577
594
  */
578
595
  function heif (options) {
579
- if (!this.constructor.format.heif.output.buffer) {
580
- throw new Error('The heif operation requires libvips to have been installed with support for libheif');
581
- }
582
596
  if (is.object(options)) {
583
597
  if (is.defined(options.quality)) {
584
598
  if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
@@ -595,10 +609,17 @@ function heif (options) {
595
609
  }
596
610
  }
597
611
  if (is.defined(options.compression)) {
598
- if (is.string(options.compression) && is.inArray(options.compression, ['hevc', 'avc', 'jpeg', 'av1'])) {
612
+ if (is.string(options.compression) && is.inArray(options.compression, ['av1', 'hevc'])) {
599
613
  this.options.heifCompression = options.compression;
600
614
  } else {
601
- throw is.invalidParameterError('compression', 'one of: hevc, avc, jpeg, av1', options.compression);
615
+ throw is.invalidParameterError('compression', 'one of: av1, hevc', options.compression);
616
+ }
617
+ }
618
+ if (is.defined(options.speed)) {
619
+ if (is.integer(options.speed) && is.inRange(options.speed, 0, 8)) {
620
+ this.options.heifSpeed = options.speed;
621
+ } else {
622
+ throw is.invalidParameterError('speed', 'integer between 0 and 8', options.speed);
602
623
  }
603
624
  }
604
625
  }
@@ -891,6 +912,7 @@ module.exports = function (Sharp) {
891
912
  png,
892
913
  webp,
893
914
  tiff,
915
+ avif,
894
916
  heif,
895
917
  gif,
896
918
  raw,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sharp",
3
- "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
4
- "version": "0.26.3",
3
+ "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, AVIF and TIFF images",
4
+ "version": "0.27.0",
5
5
  "author": "Lovell Fuller <npm@lovell.info>",
6
6
  "homepage": "https://github.com/lovell/sharp",
7
7
  "contributors": [
@@ -70,12 +70,14 @@
70
70
  "Roman Malieiev <aromaleev@gmail.com>",
71
71
  "Tomas Szabo <tomas.szabo@deftomat.com>",
72
72
  "Robert O'Rourke <robert@o-rourke.org>",
73
- "Guillermo Alfonso Varela Chouciño <guillevch@gmail.com>"
73
+ "Guillermo Alfonso Varela Chouciño <guillevch@gmail.com>",
74
+ "Christian Flintrup <chr@gigahost.dk>",
75
+ "Manan Jadhav <manan@motionden.com>"
74
76
  ],
75
77
  "scripts": {
76
78
  "install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
77
79
  "clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
78
- "test": "semistandard && cpplint && npm run test-unit && npm run test-licensing && node install/prebuild-ci",
80
+ "test": "semistandard && cpplint && npm run test-unit && npm run test-licensing",
79
81
  "test-unit": "nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js",
80
82
  "test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;MIT\"",
81
83
  "test-coverage": "./test/coverage/report.sh",
@@ -88,7 +90,6 @@
88
90
  "files": [
89
91
  "binding.gyp",
90
92
  "install/**",
91
- "!install/prebuild-ci.js",
92
93
  "lib/**",
93
94
  "src/**"
94
95
  ],
@@ -100,6 +101,7 @@
100
101
  "jpeg",
101
102
  "png",
102
103
  "webp",
104
+ "avif",
103
105
  "tiff",
104
106
  "gif",
105
107
  "svg",
@@ -116,17 +118,17 @@
116
118
  "array-flatten": "^3.0.0",
117
119
  "color": "^3.1.3",
118
120
  "detect-libc": "^1.0.3",
119
- "node-addon-api": "^3.0.2",
121
+ "node-addon-api": "^3.1.0",
120
122
  "npmlog": "^4.1.2",
121
123
  "prebuild-install": "^6.0.0",
122
- "semver": "^7.3.2",
124
+ "semver": "^7.3.4",
123
125
  "simple-get": "^4.0.0",
124
126
  "tar-fs": "^2.1.1",
125
127
  "tunnel-agent": "^0.6.0"
126
128
  },
127
129
  "devDependencies": {
128
130
  "async": "^3.2.0",
129
- "cc": "^2.0.1",
131
+ "cc": "^3.0.1",
130
132
  "decompress-zip": "^0.3.2",
131
133
  "documentation": "^13.1.0",
132
134
  "exif-reader": "^1.0.3",
@@ -141,7 +143,7 @@
141
143
  },
142
144
  "license": "Apache-2.0",
143
145
  "config": {
144
- "libvips": "8.10.0",
146
+ "libvips": "8.10.5",
145
147
  "runtime": "napi",
146
148
  "target": 3
147
149
  },
package/src/common.cc CHANGED
@@ -658,26 +658,18 @@ namespace sharp {
658
658
  int top = 0;
659
659
 
660
660
  // assign only if valid
661
- if (x >= 0 && x < (inWidth - outWidth)) {
661
+ if (x < (inWidth - outWidth)) {
662
662
  left = x;
663
663
  } else if (x >= (inWidth - outWidth)) {
664
664
  left = inWidth - outWidth;
665
665
  }
666
666
 
667
- if (y >= 0 && y < (inHeight - outHeight)) {
667
+ if (y < (inHeight - outHeight)) {
668
668
  top = y;
669
669
  } else if (y >= (inHeight - outHeight)) {
670
670
  top = inHeight - outHeight;
671
671
  }
672
672
 
673
- // the resulting left and top could have been outside the image after calculation from bottom/right edges
674
- if (left < 0) {
675
- left = 0;
676
- }
677
- if (top < 0) {
678
- top = 0;
679
- }
680
-
681
673
  return std::make_tuple(left, top);
682
674
  }
683
675
 
package/src/common.h CHANGED
@@ -24,8 +24,10 @@
24
24
 
25
25
  // Verify platform and compiler compatibility
26
26
 
27
- #if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 10))
28
- #error "libvips version 8.10.0+ is required - please see https://sharp.pixelplumbing.com/install"
27
+ #if (VIPS_MAJOR_VERSION < 8) || \
28
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 10) || \
29
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 10 && VIPS_MICRO_VERSION < 5)
30
+ #error "libvips version 8.10.5+ is required - please see https://sharp.pixelplumbing.com/install"
29
31
  #endif
30
32
 
31
33
  #if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
package/src/pipeline.cc CHANGED
@@ -570,7 +570,7 @@ class PipelineWorker : public Napi::AsyncWorker {
570
570
  int left;
571
571
  int top;
572
572
  compositeImage = compositeImage.replicate(across, down);
573
- if (composite->left >= 0 && composite->top >= 0) {
573
+ if (composite->hasOffset) {
574
574
  std::tie(left, top) = sharp::CalculateCrop(
575
575
  compositeImage.width(), compositeImage.height(), image.width(), image.height(),
576
576
  composite->left, composite->top);
@@ -592,7 +592,7 @@ class PipelineWorker : public Napi::AsyncWorker {
592
592
  // Calculate position
593
593
  int left;
594
594
  int top;
595
- if (composite->left >= 0 && composite->top >= 0) {
595
+ if (composite->hasOffset) {
596
596
  // Composite image at given offsets
597
597
  std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
598
598
  compositeImage.width(), compositeImage.height(), composite->left, composite->top);
@@ -837,6 +837,7 @@ class PipelineWorker : public Napi::AsyncWorker {
837
837
  ->set("strip", !baton->withMetadata)
838
838
  ->set("compression", baton->heifCompression)
839
839
  ->set("Q", baton->heifQuality)
840
+ ->set("speed", baton->heifSpeed)
840
841
  ->set("lossless", baton->heifLossless)));
841
842
  baton->bufferOut = static_cast<char*>(area->data);
842
843
  baton->bufferOutLength = area->length;
@@ -885,7 +886,7 @@ class PipelineWorker : public Napi::AsyncWorker {
885
886
  bool const isV = sharp::IsV(baton->fileOut);
886
887
  bool const mightMatchInput = baton->formatOut == "input";
887
888
  bool const willMatchInput = mightMatchInput &&
888
- !(isJpeg || isPng || isWebp || isGif || isTiff || isDz || isDzZip || isV);
889
+ !(isJpeg || isPng || isWebp || isGif || isTiff || isHeif || isDz || isDzZip || isV);
889
890
 
890
891
  if (baton->formatOut == "jpeg" || (mightMatchInput && isJpeg) ||
891
892
  (willMatchInput && inputImageType == sharp::ImageType::JPEG)) {
@@ -966,13 +967,11 @@ class PipelineWorker : public Napi::AsyncWorker {
966
967
  } else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) ||
967
968
  (willMatchInput && inputImageType == sharp::ImageType::HEIF)) {
968
969
  // Write HEIF to file
969
- if (sharp::IsAvif(baton->fileOut)) {
970
- baton->heifCompression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1;
971
- }
972
970
  image.heifsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
973
971
  ->set("strip", !baton->withMetadata)
974
972
  ->set("Q", baton->heifQuality)
975
973
  ->set("compression", baton->heifCompression)
974
+ ->set("speed", baton->heifSpeed)
976
975
  ->set("lossless", baton->heifLossless));
977
976
  baton->formatOut = "heif";
978
977
  } else if (baton->formatOut == "dz" || isDz || isDzZip) {
@@ -1254,6 +1253,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1254
1253
  composite->gravity = sharp::AttrAsUint32(compositeObject, "gravity");
1255
1254
  composite->left = sharp::AttrAsInt32(compositeObject, "left");
1256
1255
  composite->top = sharp::AttrAsInt32(compositeObject, "top");
1256
+ composite->hasOffset = sharp::AttrAsBool(compositeObject, "hasOffset");
1257
1257
  composite->tile = sharp::AttrAsBool(compositeObject, "tile");
1258
1258
  composite->premultiplied = sharp::AttrAsBool(compositeObject, "premultiplied");
1259
1259
  baton->composite.push_back(composite);
@@ -1395,6 +1395,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1395
1395
  baton->heifCompression = static_cast<VipsForeignHeifCompression>(
1396
1396
  vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_HEIF_COMPRESSION,
1397
1397
  sharp::AttrAsStr(options, "heifCompression").data()));
1398
+ baton->heifSpeed = sharp::AttrAsUint32(options, "heifSpeed");
1398
1399
 
1399
1400
  // Animated output
1400
1401
  if (sharp::HasAttr(options, "pageHeight")) {
package/src/pipeline.h CHANGED
@@ -40,6 +40,7 @@ struct Composite {
40
40
  int gravity;
41
41
  int left;
42
42
  int top;
43
+ bool hasOffset;
43
44
  bool tile;
44
45
  bool premultiplied;
45
46
 
@@ -47,8 +48,9 @@ struct Composite {
47
48
  input(nullptr),
48
49
  mode(VIPS_BLEND_MODE_OVER),
49
50
  gravity(0),
50
- left(-1),
51
- top(-1),
51
+ left(0),
52
+ top(0),
53
+ hasOffset(false),
52
54
  tile(false),
53
55
  premultiplied(false) {}
54
56
  };
@@ -159,6 +161,7 @@ struct PipelineBaton {
159
161
  double tiffYres;
160
162
  int heifQuality;
161
163
  VipsForeignHeifCompression heifCompression;
164
+ int heifSpeed;
162
165
  bool heifLossless;
163
166
  std::string err;
164
167
  bool withMetadata;
@@ -276,8 +279,9 @@ struct PipelineBaton {
276
279
  tiffTileWidth(256),
277
280
  tiffXres(1.0),
278
281
  tiffYres(1.0),
279
- heifQuality(80),
280
- heifCompression(VIPS_FOREIGN_HEIF_COMPRESSION_HEVC),
282
+ heifQuality(50),
283
+ heifCompression(VIPS_FOREIGN_HEIF_COMPRESSION_AV1),
284
+ heifSpeed(5),
281
285
  heifLossless(false),
282
286
  withMetadata(false),
283
287
  withMetadataOrientation(-1),
package/src/sharp.cc CHANGED
@@ -22,6 +22,8 @@
22
22
  #include "stats.h"
23
23
 
24
24
  static void* sharp_vips_init(void*) {
25
+ g_setenv("VIPS_MIN_STACK_SIZE", "2m", FALSE);
26
+ g_setenv("PANGOCAIRO_BACKEND", "fontconfig", FALSE);
25
27
  vips_init("sharp");
26
28
  return nullptr;
27
29
  }