sharp 0.32.2 → 0.32.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/composite.js CHANGED
@@ -108,14 +108,14 @@ const blend = {
108
108
  * @param {string} [images[].input.text.align='left'] - text alignment (`'left'`, `'centre'`, `'center'`, `'right'`).
109
109
  * @param {boolean} [images[].input.text.justify=false] - set this to true to apply justification to the text.
110
110
  * @param {number} [images[].input.text.dpi=72] - the resolution (size) at which to render the text. Does not take effect if `height` is specified.
111
- * @param {boolean} [images[].input.text.rgba=false] - set this to true to enable RGBA output. This is useful for colour emoji rendering, or support for pango markup features like `<span foreground="red">Red!</span>`.
111
+ * @param {boolean} [images[].input.text.rgba=false] - set this to true to enable RGBA output. This is useful for colour emoji rendering, or support for Pango markup features like `<span foreground="red">Red!</span>`.
112
112
  * @param {number} [images[].input.text.spacing=0] - text line height in points. Will use the font line height if none is specified.
113
113
  * @param {String} [images[].blend='over'] - how to blend this image with the image below.
114
114
  * @param {String} [images[].gravity='centre'] - gravity at which to place the overlay.
115
115
  * @param {Number} [images[].top] - the pixel offset from the top edge.
116
116
  * @param {Number} [images[].left] - the pixel offset from the left edge.
117
117
  * @param {Boolean} [images[].tile=false] - set to true to repeat the overlay image across the entire image with the given `gravity`.
118
- * @param {Boolean} [images[].premultiplied=false] - set to true to avoid premultipling the image below. Equivalent to the `--premultiplied` vips option.
118
+ * @param {Boolean} [images[].premultiplied=false] - set to true to avoid premultiplying the image below. Equivalent to the `--premultiplied` vips option.
119
119
  * @param {Number} [images[].density=72] - number representing the DPI for vector overlay image.
120
120
  * @param {Object} [images[].raw] - describes overlay when using raw pixel data.
121
121
  * @param {Number} [images[].raw.width]
@@ -49,7 +49,7 @@ const debuglog = util.debuglog('sharp');
49
49
  * readableStream.pipe(transformer).pipe(writableStream);
50
50
  *
51
51
  * @example
52
- * // Create a blank 300x200 PNG image of semi-transluent red pixels
52
+ * // Create a blank 300x200 PNG image of semi-translucent red pixels
53
53
  * sharp({
54
54
  * create: {
55
55
  * width: 300,
@@ -122,7 +122,7 @@ const debuglog = util.debuglog('sharp');
122
122
  * a String containing the filesystem path to an JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image file.
123
123
  * JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
124
124
  * @param {Object} [options] - if present, is an Object with optional attributes.
125
- * @param {string} [options.failOn='warning'] - when to abort processing of invalid pixel data, one of (in order of sensitivity): 'none' (least), 'truncated', 'error' or 'warning' (most), highers level imply lower levels, invalid metadata will always abort.
125
+ * @param {string} [options.failOn='warning'] - when to abort processing of invalid pixel data, one of (in order of sensitivity): 'none' (least), 'truncated', 'error' or 'warning' (most), higher levels imply lower levels, invalid metadata will always abort.
126
126
  * @param {number|boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
127
127
  * (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
128
128
  * An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
@@ -291,6 +291,7 @@ const Sharp = function (input, options) {
291
291
  webpLossless: false,
292
292
  webpNearLossless: false,
293
293
  webpSmartSubsample: false,
294
+ webpPreset: 'default',
294
295
  webpEffort: 4,
295
296
  webpMinSize: false,
296
297
  webpMixed: false,
package/lib/operation.js CHANGED
@@ -11,7 +11,7 @@ const is = require('./is');
11
11
  * or auto-orient based on the EXIF `Orientation` tag.
12
12
  *
13
13
  * If an angle is provided, it is converted to a valid positive degree rotation.
14
- * For example, `-450` will produce a 270deg rotation.
14
+ * For example, `-450` will produce a 270 degree rotation.
15
15
  *
16
16
  * When rotating by an angle other than a multiple of 90,
17
17
  * the background colour can be provided with the `background` option.
@@ -772,7 +772,7 @@ function linear (a, b) {
772
772
  }
773
773
 
774
774
  /**
775
- * Recomb the image with the specified matrix.
775
+ * Recombine the image with the specified matrix.
776
776
  *
777
777
  * @since 0.21.1
778
778
  *
@@ -785,7 +785,7 @@ function linear (a, b) {
785
785
  * ])
786
786
  * .raw()
787
787
  * .toBuffer(function(err, data, info) {
788
- * // data contains the raw pixel data after applying the recomb
788
+ * // data contains the raw pixel data after applying the matrix
789
789
  * // With this example input, a sepia filter has been applied
790
790
  * });
791
791
  *
@@ -842,7 +842,7 @@ function recomb (inputMatrix) {
842
842
  * .toBuffer();
843
843
  *
844
844
  * @example
845
- * // decreate brightness and saturation while also hue-rotating by 90 degrees
845
+ * // decrease brightness and saturation while also hue-rotating by 90 degrees
846
846
  * const output = await sharp(input)
847
847
  * .modulate({
848
848
  * brightness: 0.5,
package/lib/output.js CHANGED
@@ -483,6 +483,7 @@ function png (options) {
483
483
  * @param {boolean} [options.lossless=false] - use lossless compression mode
484
484
  * @param {boolean} [options.nearLossless=false] - use near_lossless compression mode
485
485
  * @param {boolean} [options.smartSubsample=false] - use high quality chroma subsampling
486
+ * @param {string} [options.preset='default'] - named preset for preprocessing/filtering, one of: default, photo, picture, drawing, icon, text
486
487
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 6 (slowest)
487
488
  * @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation
488
489
  * @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
@@ -517,6 +518,13 @@ function webp (options) {
517
518
  if (is.defined(options.smartSubsample)) {
518
519
  this._setBooleanOption('webpSmartSubsample', options.smartSubsample);
519
520
  }
521
+ if (is.defined(options.preset)) {
522
+ if (is.string(options.preset) && is.inArray(options.preset, ['default', 'photo', 'picture', 'drawing', 'icon', 'text'])) {
523
+ this.options.webpPreset = options.preset;
524
+ } else {
525
+ throw is.invalidParameterError('preset', 'one of: default, photo, picture, drawing, icon, text', options.preset);
526
+ }
527
+ }
520
528
  if (is.defined(options.effort)) {
521
529
  if (is.integer(options.effort) && is.inRange(options.effort, 0, 6)) {
522
530
  this.options.webpEffort = options.effort;
package/lib/utility.js CHANGED
@@ -202,6 +202,72 @@ function simd (simd) {
202
202
  }
203
203
  simd(true);
204
204
 
205
+ /**
206
+ * Block libvips operations at runtime.
207
+ *
208
+ * This is in addition to the `VIPS_BLOCK_UNTRUSTED` environment variable,
209
+ * which when set will block all "untrusted" operations.
210
+ *
211
+ * @since 0.32.4
212
+ *
213
+ * @example <caption>Block all TIFF input.</caption>
214
+ * sharp.block({
215
+ * operation: ['VipsForeignLoadTiff']
216
+ * });
217
+ *
218
+ * @param {Object} options
219
+ * @param {Array<string>} options.operation - List of libvips low-level operation names to block.
220
+ */
221
+ function block (options) {
222
+ if (is.object(options)) {
223
+ if (Array.isArray(options.operation) && options.operation.every(is.string)) {
224
+ sharp.block(options.operation, true);
225
+ } else {
226
+ throw is.invalidParameterError('operation', 'Array<string>', options.operation);
227
+ }
228
+ } else {
229
+ throw is.invalidParameterError('options', 'object', options);
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Unblock libvips operations at runtime.
235
+ *
236
+ * This is useful for defining a list of allowed operations.
237
+ *
238
+ * @since 0.32.4
239
+ *
240
+ * @example <caption>Block all input except WebP from the filesystem.</caption>
241
+ * sharp.block({
242
+ * operation: ['VipsForeignLoad']
243
+ * });
244
+ * sharp.unblock({
245
+ * operation: ['VipsForeignLoadWebpFile']
246
+ * });
247
+ *
248
+ * @example <caption>Block all input except JPEG and PNG from a Buffer or Stream.</caption>
249
+ * sharp.block({
250
+ * operation: ['VipsForeignLoad']
251
+ * });
252
+ * sharp.unblock({
253
+ * operation: ['VipsForeignLoadJpegBuffer', 'VipsForeignLoadPngBuffer']
254
+ * });
255
+ *
256
+ * @param {Object} options
257
+ * @param {Array<string>} options.operation - List of libvips low-level operation names to unblock.
258
+ */
259
+ function unblock (options) {
260
+ if (is.object(options)) {
261
+ if (Array.isArray(options.operation) && options.operation.every(is.string)) {
262
+ sharp.block(options.operation, false);
263
+ } else {
264
+ throw is.invalidParameterError('operation', 'Array<string>', options.operation);
265
+ }
266
+ } else {
267
+ throw is.invalidParameterError('options', 'object', options);
268
+ }
269
+ }
270
+
205
271
  /**
206
272
  * Decorate the Sharp class with utility-related functions.
207
273
  * @private
@@ -216,4 +282,6 @@ module.exports = function (Sharp) {
216
282
  Sharp.versions = versions;
217
283
  Sharp.vendor = vendor;
218
284
  Sharp.queue = queue;
285
+ Sharp.block = block;
286
+ Sharp.unblock = unblock;
219
287
  };
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.32.2",
4
+ "version": "0.32.4",
5
5
  "author": "Lovell Fuller <npm@lovell.info>",
6
6
  "homepage": "https://github.com/lovell/sharp",
7
7
  "contributors": [
@@ -133,7 +133,7 @@
133
133
  ],
134
134
  "dependencies": {
135
135
  "color": "^4.2.3",
136
- "detect-libc": "^2.0.1",
136
+ "detect-libc": "^2.0.2",
137
137
  "node-addon-api": "^6.1.0",
138
138
  "prebuild-install": "^7.1.1",
139
139
  "semver": "^7.5.4",
@@ -159,19 +159,19 @@
159
159
  },
160
160
  "license": "Apache-2.0",
161
161
  "config": {
162
- "libvips": "8.14.2",
162
+ "libvips": "8.14.3",
163
163
  "integrity": {
164
- "darwin-arm64v8": "sha512-eUuxg6H0tXgX4z2lsaGtZ4cbPAm7yoFgkvPDd4csxoiVt+QUB25pEJwiXw7oB53VlBFIp3O8lbydSFS5zH8MQQ==",
165
- "darwin-x64": "sha512-cMT4v76IgzSR0VoXqLk/yftRyzMEZ+SBVMLzXCgqP/lmnYisrpmHHNqrWnoZbUUBXbPXLn6KMultYOJHe/c9ZQ==",
166
- "linux-arm64v8": "sha512-OcDJ/ly80pxwaKnw0W91sSvZczPtWsjmzrY/+6NMiQZT84LkmeaRuwErbHhorKDxnl7iZuNn9Uj5V25Xmj+LDQ==",
167
- "linux-armv6": "sha512-hk2ohSOYTJEtVQxEQFyQ+tuayKpYqx6NiXa7AE+8MF+yscxt+g+mLJ7TjDqtmb4ttFGH4IVfsEfU2YXIqWqkpg==",
168
- "linux-armv7": "sha512-/5Ci2Cd+yLZmTaEt9lVJ89elxX3RMJpps0ESjj43X40yrwka51QfXeg1QV38uNzZpCDIZkrbXZK0lyKldjpLuA==",
169
- "linux-x64": "sha512-wjCKmWfBb0uz1UB7rPDLvO0s+VWuoAY/Vv/YGCRFEQUkdSLQUgHExrOMMbOM3FleuYfQqznDYCXXphkl7X44+w==",
170
- "linuxmusl-arm64v8": "sha512-QtD2n90yi+rLE65C0gksFUU5uMUFPICI/pS3A0bgthpIcoCejAOYs3ZjVWpZbHQuV/lWahIUYO78MB9CzY860A==",
171
- "linuxmusl-x64": "sha512-TokQ/ETCJAsPYuxIMOPYDp25rlcwtpmIMtRUR9PB75TmZEJe7abRfCEInIPYeD8F/HxxnJSLiEdlbn1z1Jfzng==",
172
- "win32-arm64v8": "sha512-IIuj4EAgLqEVAoOuYH79C61a7TcJXlU/RBwk+5JsGWc2mr4J/Ar5J01e6XBvU4Lu3eqcU+3GPaACZEa1511buA==",
173
- "win32-ia32": "sha512-CsZi7lrReX3B6tmYgOGJ0IiAfcN5APDC6l+3gdosxfTfwpLLO+jXaSmyNwIGeMqrdgckG/gwwc+IrUZmkmjJ/A==",
174
- "win32-x64": "sha512-J7znmNKUK4ZKo6SnSnEtzT1xRAwvkGXxIx9/QihAadu1TFdS06yNhcENmwC4973+KZBlAdVpWbZ8sLrEoWkdCA=="
164
+ "darwin-arm64v8": "sha512-zeb7jQ/5ARZfBH9Uy5wlpN05bFpiIN0qN3gIIpfJhpN0rhGDnjJZQgK0W+pOmG1YiLL42BMCS0SHldb0xE33rA==",
165
+ "darwin-x64": "sha512-C3N6smxdfprfz58cjojv0aekYXDl6+f9SwpGpxPG5RrZnrDMn5NOXtUQOEQ8PZ3Hd9VzfkJTnW/s36EvcMPfYg==",
166
+ "linux-arm64v8": "sha512-hT6B+OswqVQH10Fggq3jpOdn+GhxNx+5bk+EMr3lY3RZy72PZ+n4ZHJDfYSxAymdiz5rCdzGxsRLMb9GgD4OSw==",
167
+ "linux-armv6": "sha512-cW9giVrBssHXFt07l+PgqGu7P7XRDv7oW8jC6iXGBcjG75N7rXz2CK0DyPclfnyoWH4IQ78dh5SkQWmb6X4tig==",
168
+ "linux-armv7": "sha512-hgqFt3UkZHK6D91JtYrYmT1niznh+N93Zxj2EWXgTLAdcS1D3QqaDPEg2EhInHbXqYvfOuQYAAXPxt7zVtKqcw==",
169
+ "linux-x64": "sha512-FKbMBbCcFcSugRtuiTsA6Cov+M2WQ8nzvmmJ5xYYpRg/rsrWvObFT+6x/YBpblur9uXGjGIehjXVZtB3VXc+pg==",
170
+ "linuxmusl-arm64v8": "sha512-RTf6mrFyLGWnyt0DH4nHeXv5oSZMSJWxTdTt4cjvJsgp2Husz3mNJLQJGeehCuqPCYj/liJ9NIczw8u71eHFng==",
171
+ "linuxmusl-x64": "sha512-y/8UOkHzKhi/5UM1/ONyPvpuhO11nPQmuJWfzqUKj8kSKnDasmxv3FN46yI0XY3xA2oFC8lQNFBnLudQsi3Nvw==",
172
+ "win32-arm64v8": "sha512-D3PiVL981S7V0bSUwW3OqDS48H9QRw2vqQhYIY3JcIEssOnjWxmJGaz0Y9Zb8TYF5DHnnD6g5kEhob5Y2PIVEw==",
173
+ "win32-ia32": "sha512-FuLIaSIYJGJAcxyKkG/3/uuTzputekKSCcRCpRHkQS9J8IwM+yHzQeJ5W2PyAvNdeGIEwlYq3wnCNcXe1UGXWA==",
174
+ "win32-x64": "sha512-VQg4aBqpEfybgV8bjnrjfvnosxQDII/23mouFUfKHCsH5kvvHV5tTuPsxm6qbl+SCVploDK/zK1qpjop8YEvtg=="
175
175
  },
176
176
  "runtime": "napi",
177
177
  "target": 7
package/src/common.cc CHANGED
@@ -1035,4 +1035,13 @@ namespace sharp {
1035
1035
  return std::make_pair(hshrink, vshrink);
1036
1036
  }
1037
1037
 
1038
+ /*
1039
+ Ensure decoding remains sequential.
1040
+ */
1041
+ VImage StaySequential(VImage image, VipsAccess access, bool condition) {
1042
+ if (access == VIPS_ACCESS_SEQUENTIAL && condition) {
1043
+ return image.copy_memory();
1044
+ }
1045
+ return image;
1046
+ }
1038
1047
  } // namespace sharp
package/src/common.h CHANGED
@@ -15,8 +15,8 @@
15
15
 
16
16
  #if (VIPS_MAJOR_VERSION < 8) || \
17
17
  (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 14) || \
18
- (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 14 && VIPS_MICRO_VERSION < 2)
19
- #error "libvips version 8.14.2+ is required - please see https://sharp.pixelplumbing.com/install"
18
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 14 && VIPS_MICRO_VERSION < 3)
19
+ #error "libvips version 8.14.3+ is required - please see https://sharp.pixelplumbing.com/install"
20
20
  #endif
21
21
 
22
22
  #if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
@@ -370,6 +370,11 @@ namespace sharp {
370
370
  std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
371
371
  Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction);
372
372
 
373
+ /*
374
+ Ensure decoding remains sequential.
375
+ */
376
+ VImage StaySequential(VImage image, VipsAccess access, bool condition = TRUE);
377
+
373
378
  } // namespace sharp
374
379
 
375
380
  #endif // SRC_COMMON_H_
package/src/pipeline.cc CHANGED
@@ -56,6 +56,7 @@ class PipelineWorker : public Napi::AsyncWorker {
56
56
  vips::VImage image;
57
57
  sharp::ImageType inputImageType;
58
58
  std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
59
+ VipsAccess access = baton->input->access;
59
60
  image = sharp::EnsureColourspace(image, baton->colourspaceInput);
60
61
 
61
62
  int nPages = baton->input->pages;
@@ -79,9 +80,6 @@ class PipelineWorker : public Napi::AsyncWorker {
79
80
  // Rotate and flip image according to Exif orientation
80
81
  std::tie(autoRotation, autoFlip, autoFlop) = CalculateExifRotationAndFlip(sharp::ExifOrientation(image));
81
82
  image = sharp::RemoveExifOrientation(image);
82
- if (baton->input->access == VIPS_ACCESS_SEQUENTIAL && (autoRotation != VIPS_ANGLE_D0 || autoFlip)) {
83
- image = image.copy_memory();
84
- }
85
83
  } else {
86
84
  rotation = CalculateAngleRotation(baton->angle);
87
85
  }
@@ -93,6 +91,13 @@ class PipelineWorker : public Napi::AsyncWorker {
93
91
  baton->rotationAngle != 0.0);
94
92
 
95
93
  if (shouldRotateBefore) {
94
+ image = sharp::StaySequential(image, access,
95
+ rotation != VIPS_ANGLE_D0 ||
96
+ autoRotation != VIPS_ANGLE_D0 ||
97
+ autoFlip ||
98
+ baton->flip ||
99
+ baton->rotationAngle != 0.0);
100
+
96
101
  if (autoRotation != VIPS_ANGLE_D0) {
97
102
  image = image.rot(autoRotation);
98
103
  autoRotation = VIPS_ANGLE_D0;
@@ -126,6 +131,7 @@ class PipelineWorker : public Napi::AsyncWorker {
126
131
  // Trim
127
132
  if (baton->trimThreshold > 0.0) {
128
133
  MultiPageUnsupported(nPages, "Trim");
134
+ image = sharp::StaySequential(image, access);
129
135
  image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold);
130
136
  baton->trimOffsetLeft = image.xoffset();
131
137
  baton->trimOffsetTop = image.yoffset();
@@ -212,7 +218,7 @@ class PipelineWorker : public Napi::AsyncWorker {
212
218
  // pdfload* and svgload*
213
219
  if (jpegShrinkOnLoad > 1) {
214
220
  vips::VOption *option = VImage::option()
215
- ->set("access", baton->input->access)
221
+ ->set("access", access)
216
222
  ->set("shrink", jpegShrinkOnLoad)
217
223
  ->set("unlimited", baton->input->unlimited)
218
224
  ->set("fail_on", baton->input->failOn);
@@ -227,7 +233,7 @@ class PipelineWorker : public Napi::AsyncWorker {
227
233
  }
228
234
  } else if (scale != 1.0) {
229
235
  vips::VOption *option = VImage::option()
230
- ->set("access", baton->input->access)
236
+ ->set("access", access)
231
237
  ->set("scale", scale)
232
238
  ->set("fail_on", baton->input->failOn);
233
239
  if (inputImageType == sharp::ImageType::WEBP) {
@@ -379,6 +385,11 @@ class PipelineWorker : public Napi::AsyncWorker {
379
385
  ->set("kernel", baton->kernel));
380
386
  }
381
387
 
388
+ image = sharp::StaySequential(image, access,
389
+ autoRotation != VIPS_ANGLE_D0 ||
390
+ baton->flip ||
391
+ autoFlip ||
392
+ rotation != VIPS_ANGLE_D0);
382
393
  // Auto-rotate post-extract
383
394
  if (autoRotation != VIPS_ANGLE_D0) {
384
395
  image = image.rot(autoRotation);
@@ -402,7 +413,7 @@ class PipelineWorker : public Napi::AsyncWorker {
402
413
  sharp::ImageType joinImageType = sharp::ImageType::UNKNOWN;
403
414
 
404
415
  for (unsigned int i = 0; i < baton->joinChannelIn.size(); i++) {
405
- baton->joinChannelIn[i]->access = baton->input->access;
416
+ baton->joinChannelIn[i]->access = access;
406
417
  std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i]);
407
418
  joinImage = sharp::EnsureColourspace(joinImage, baton->colourspaceInput);
408
419
  image = image.bandjoin(joinImage);
@@ -471,10 +482,7 @@ class PipelineWorker : public Napi::AsyncWorker {
471
482
 
472
483
  // Attention-based or Entropy-based crop
473
484
  MultiPageUnsupported(nPages, "Resize strategy");
474
- image = image.tilecache(VImage::option()
475
- ->set("access", VIPS_ACCESS_RANDOM)
476
- ->set("threaded", TRUE));
477
-
485
+ image = sharp::StaySequential(image, access);
478
486
  image = image.smartcrop(baton->width, baton->height, VImage::option()
479
487
  ->set("interesting", baton->position == 16 ? VIPS_INTERESTING_ENTROPY : VIPS_INTERESTING_ATTENTION)
480
488
  #if (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 15)
@@ -495,6 +503,7 @@ class PipelineWorker : public Napi::AsyncWorker {
495
503
  // Rotate post-extract non-90 angle
496
504
  if (!baton->rotateBeforePreExtract && baton->rotationAngle != 0.0) {
497
505
  MultiPageUnsupported(nPages, "Rotate");
506
+ image = sharp::StaySequential(image, access);
498
507
  std::vector<double> background;
499
508
  std::tie(image, background) = sharp::ApplyAlpha(image, baton->rotationBackground, shouldPremultiplyAlpha);
500
509
  image = image.rotate(baton->rotationAngle, VImage::option()->set("background", background));
@@ -518,6 +527,7 @@ class PipelineWorker : public Napi::AsyncWorker {
518
527
  // Affine transform
519
528
  if (!baton->affineMatrix.empty()) {
520
529
  MultiPageUnsupported(nPages, "Affine");
530
+ image = sharp::StaySequential(image, access);
521
531
  std::vector<double> background;
522
532
  std::tie(image, background) = sharp::ApplyAlpha(image, baton->affineBackground, shouldPremultiplyAlpha);
523
533
  vips::VInterpolate interp = vips::VInterpolate::new_from_name(
@@ -614,7 +624,7 @@ class PipelineWorker : public Napi::AsyncWorker {
614
624
  for (Composite *composite : baton->composite) {
615
625
  VImage compositeImage;
616
626
  sharp::ImageType compositeImageType = sharp::ImageType::UNKNOWN;
617
- composite->input->access = baton->input->access;
627
+ composite->input->access = access;
618
628
  std::tie(compositeImage, compositeImageType) = sharp::OpenInput(composite->input);
619
629
  compositeImage = sharp::EnsureColourspace(compositeImage, baton->colourspaceInput);
620
630
  // Verify within current dimensions
@@ -701,11 +711,13 @@ class PipelineWorker : public Napi::AsyncWorker {
701
711
 
702
712
  // Apply normalisation - stretch luminance to cover full dynamic range
703
713
  if (baton->normalise) {
704
- image = sharp::Normalise(image, baton->normaliseLower, baton->normaliseUpper);
714
+ image = sharp::StaySequential(image, access);
715
+ image = sharp::Normalise(image, baton->normaliseLower, baton->normaliseUpper);
705
716
  }
706
717
 
707
718
  // Apply contrast limiting adaptive histogram equalization (CLAHE)
708
719
  if (baton->claheWidth != 0 && baton->claheHeight != 0) {
720
+ image = sharp::StaySequential(image, access);
709
721
  image = sharp::Clahe(image, baton->claheWidth, baton->claheHeight, baton->claheMaxSlope);
710
722
  }
711
723
 
@@ -713,7 +725,7 @@ class PipelineWorker : public Napi::AsyncWorker {
713
725
  if (baton->boolean != nullptr) {
714
726
  VImage booleanImage;
715
727
  sharp::ImageType booleanImageType = sharp::ImageType::UNKNOWN;
716
- baton->boolean->access = baton->input->access;
728
+ baton->boolean->access = access;
717
729
  std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean);
718
730
  booleanImage = sharp::EnsureColourspace(booleanImage, baton->colourspaceInput);
719
731
  image = sharp::Boolean(image, booleanImage, baton->booleanOp);
@@ -882,6 +894,7 @@ class PipelineWorker : public Napi::AsyncWorker {
882
894
  ->set("lossless", baton->webpLossless)
883
895
  ->set("near_lossless", baton->webpNearLossless)
884
896
  ->set("smart_subsample", baton->webpSmartSubsample)
897
+ ->set("preset", baton->webpPreset)
885
898
  ->set("effort", baton->webpEffort)
886
899
  ->set("min_size", baton->webpMinSize)
887
900
  ->set("mixed", baton->webpMixed)
@@ -963,6 +976,7 @@ class PipelineWorker : public Napi::AsyncWorker {
963
976
  if (!sharp::HasAlpha(image)) {
964
977
  baton->tileBackground.pop_back();
965
978
  }
979
+ image = sharp::StaySequential(image, access, baton->tileAngle != 0);
966
980
  vips::VOption *options = BuildOptionsDZ(baton);
967
981
  VipsArea *area = reinterpret_cast<VipsArea*>(image.dzsave_buffer(options));
968
982
  baton->bufferOut = static_cast<char*>(area->data);
@@ -1086,6 +1100,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1086
1100
  ->set("lossless", baton->webpLossless)
1087
1101
  ->set("near_lossless", baton->webpNearLossless)
1088
1102
  ->set("smart_subsample", baton->webpSmartSubsample)
1103
+ ->set("preset", baton->webpPreset)
1089
1104
  ->set("effort", baton->webpEffort)
1090
1105
  ->set("min_size", baton->webpMinSize)
1091
1106
  ->set("mixed", baton->webpMixed)
@@ -1162,6 +1177,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1162
1177
  if (!sharp::HasAlpha(image)) {
1163
1178
  baton->tileBackground.pop_back();
1164
1179
  }
1180
+ image = sharp::StaySequential(image, access, baton->tileAngle != 0);
1165
1181
  vips::VOption *options = BuildOptionsDZ(baton);
1166
1182
  image.dzsave(const_cast<char*>(baton->fileOut.data()), options);
1167
1183
  baton->formatOut = "dz";
@@ -1363,6 +1379,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1363
1379
  {"lossless", baton->webpLossless ? "TRUE" : "FALSE"},
1364
1380
  {"near_lossless", baton->webpNearLossless ? "TRUE" : "FALSE"},
1365
1381
  {"smart_subsample", baton->webpSmartSubsample ? "TRUE" : "FALSE"},
1382
+ {"preset", vips_enum_nick(VIPS_TYPE_FOREIGN_WEBP_PRESET, baton->webpPreset)},
1366
1383
  {"min_size", baton->webpMinSize ? "TRUE" : "FALSE"},
1367
1384
  {"mixed", baton->webpMixed ? "TRUE" : "FALSE"},
1368
1385
  {"effort", std::to_string(baton->webpEffort)}
@@ -1615,6 +1632,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1615
1632
  baton->webpLossless = sharp::AttrAsBool(options, "webpLossless");
1616
1633
  baton->webpNearLossless = sharp::AttrAsBool(options, "webpNearLossless");
1617
1634
  baton->webpSmartSubsample = sharp::AttrAsBool(options, "webpSmartSubsample");
1635
+ baton->webpPreset = sharp::AttrAsEnum<VipsForeignWebpPreset>(options, "webpPreset", VIPS_TYPE_FOREIGN_WEBP_PRESET);
1618
1636
  baton->webpEffort = sharp::AttrAsUint32(options, "webpEffort");
1619
1637
  baton->webpMinSize = sharp::AttrAsBool(options, "webpMinSize");
1620
1638
  baton->webpMixed = sharp::AttrAsBool(options, "webpMixed");
@@ -1674,23 +1692,6 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1674
1692
  baton->tileId = sharp::AttrAsStr(options, "tileId");
1675
1693
  baton->tileBasename = sharp::AttrAsStr(options, "tileBasename");
1676
1694
 
1677
- // Force random access for certain operations
1678
- if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
1679
- if (
1680
- baton->trimThreshold > 0.0 ||
1681
- baton->normalise ||
1682
- baton->position == 16 || baton->position == 17 ||
1683
- baton->angle != 0 ||
1684
- baton->rotationAngle != 0.0 ||
1685
- baton->tileAngle != 0 ||
1686
- baton->flip ||
1687
- baton->claheWidth != 0 ||
1688
- !baton->affineMatrix.empty()
1689
- ) {
1690
- baton->input->access = VIPS_ACCESS_RANDOM;
1691
- }
1692
- }
1693
-
1694
1695
  // Function to notify of libvips warnings
1695
1696
  Napi::Function debuglog = options.Get("debuglog").As<Napi::Function>();
1696
1697
 
package/src/pipeline.h CHANGED
@@ -153,6 +153,7 @@ struct PipelineBaton {
153
153
  bool webpNearLossless;
154
154
  bool webpLossless;
155
155
  bool webpSmartSubsample;
156
+ VipsForeignWebpPreset webpPreset;
156
157
  int webpEffort;
157
158
  bool webpMinSize;
158
159
  bool webpMixed;
@@ -318,6 +319,7 @@ struct PipelineBaton {
318
319
  webpNearLossless(false),
319
320
  webpLossless(false),
320
321
  webpSmartSubsample(false),
322
+ webpPreset(VIPS_FOREIGN_WEBP_PRESET_DEFAULT),
321
323
  webpEffort(4),
322
324
  webpMinSize(false),
323
325
  webpMixed(false),
package/src/sharp.cc CHANGED
@@ -31,6 +31,7 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
31
31
  exports.Set("simd", Napi::Function::New(env, simd));
32
32
  exports.Set("libvipsVersion", Napi::Function::New(env, libvipsVersion));
33
33
  exports.Set("format", Napi::Function::New(env, format));
34
+ exports.Set("block", Napi::Function::New(env, block));
34
35
  exports.Set("_maxColourDistance", Napi::Function::New(env, _maxColourDistance));
35
36
  exports.Set("_isUsingJemalloc", Napi::Function::New(env, _isUsingJemalloc));
36
37
  exports.Set("stats", Napi::Function::New(env, stats));
package/src/utilities.cc CHANGED
@@ -164,6 +164,17 @@ Napi::Value format(const Napi::CallbackInfo& info) {
164
164
  return format;
165
165
  }
166
166
 
167
+ /*
168
+ (Un)block libvips operations at runtime.
169
+ */
170
+ void block(const Napi::CallbackInfo& info) {
171
+ Napi::Array ops = info[size_t(0)].As<Napi::Array>();
172
+ bool const state = info[size_t(1)].As<Napi::Boolean>().Value();
173
+ for (unsigned int i = 0; i < ops.Length(); i++) {
174
+ vips_operation_block_set(ops.Get(i).As<Napi::String>().Utf8Value().c_str(), state);
175
+ }
176
+ }
177
+
167
178
  /*
168
179
  Synchronous, internal-only method used by some of the functional tests.
169
180
  Calculates the maximum colour distance using the DE2000 algorithm
package/src/utilities.h CHANGED
@@ -12,6 +12,7 @@ Napi::Value counters(const Napi::CallbackInfo& info);
12
12
  Napi::Value simd(const Napi::CallbackInfo& info);
13
13
  Napi::Value libvipsVersion(const Napi::CallbackInfo& info);
14
14
  Napi::Value format(const Napi::CallbackInfo& info);
15
+ void block(const Napi::CallbackInfo& info);
15
16
  Napi::Value _maxColourDistance(const Napi::CallbackInfo& info);
16
17
  Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info);
17
18