@revizly/sharp 0.33.4-revizly7 → 0.33.5-revizly2

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/install/check.js CHANGED
@@ -18,7 +18,7 @@ try {
18
18
  }
19
19
  try {
20
20
  const gyp = require('node-gyp');
21
- log(`Found node-gyp version ${gyp().version}`);
21
+ log(`Found node-gyp ${gyp().version}`);
22
22
  } catch (err) {
23
23
  log('Please add node-gyp to your dependencies');
24
24
  return;
@@ -226,6 +226,8 @@ const Sharp = function (input, options) {
226
226
  negateAlpha: true,
227
227
  medianSize: 0,
228
228
  blurSigma: 0,
229
+ precision: 'integer',
230
+ minAmpl: 0.2,
229
231
  sharpenSigma: 0,
230
232
  sharpenM1: 1,
231
233
  sharpenM2: 2,
package/lib/index.d.ts CHANGED
@@ -464,7 +464,7 @@ declare namespace sharp {
464
464
  * @throws {Error} Invalid parameters
465
465
  * @returns A sharp instance that can be used to chain operations
466
466
  */
467
- blur(sigma?: number | boolean): Sharp;
467
+ blur(sigma?: number | boolean | BlurOptions): Sharp;
468
468
 
469
469
  /**
470
470
  * Merge alpha transparency channel, if any, with background.
@@ -1069,7 +1069,7 @@ declare namespace sharp {
1069
1069
  /** Number of pixels per inch (DPI), if present */
1070
1070
  density?: number | undefined;
1071
1071
  /** String containing JPEG chroma subsampling, 4:2:0 or 4:4:4 for RGB, 4:2:0:4 or 4:4:4:4 for CMYK */
1072
- chromaSubsampling: string;
1072
+ chromaSubsampling?: string | undefined;
1073
1073
  /** Boolean indicating whether the image is interlaced using a progressive scan */
1074
1074
  isProgressive?: boolean | undefined;
1075
1075
  /** Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP */
@@ -1108,6 +1108,8 @@ declare namespace sharp {
1108
1108
  resolutionUnit?: 'inch' | 'cm' | undefined;
1109
1109
  /** String containing format for images loaded via *magick */
1110
1110
  formatMagick?: string | undefined;
1111
+ /** Array of keyword/text pairs representing PNG text blocks, if present. */
1112
+ comments?: CommentsMetadata[] | undefined;
1111
1113
  }
1112
1114
 
1113
1115
  interface LevelMetadata {
@@ -1115,6 +1117,11 @@ declare namespace sharp {
1115
1117
  height: number;
1116
1118
  }
1117
1119
 
1120
+ interface CommentsMetadata {
1121
+ keyword: string;
1122
+ text: string;
1123
+ }
1124
+
1118
1125
  interface Stats {
1119
1126
  /** Array of channel statistics for each channel in the image. */
1120
1127
  channels: ChannelStats[];
@@ -1335,6 +1342,17 @@ declare namespace sharp {
1335
1342
  background?: Color | undefined;
1336
1343
  }
1337
1344
 
1345
+ type Precision = 'integer' | 'float' | 'approximate';
1346
+
1347
+ interface BlurOptions {
1348
+ /** A value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2` */
1349
+ sigma: number;
1350
+ /** A value between 0.001 and 1. A smaller value will generate a larger, more accurate mask. */
1351
+ minAmplitude?: number;
1352
+ /** How accurate the operation should be, one of: integer, float, approximate. (optional, default "integer") */
1353
+ precision?: Precision | undefined;
1354
+ }
1355
+
1338
1356
  interface FlattenOptions {
1339
1357
  /** background colour, parsed by the color module, defaults to black. (optional, default {r:0,g:0,b:0}) */
1340
1358
  background?: Color | undefined;
package/lib/input.js CHANGED
@@ -450,6 +450,7 @@ function _isStreamInput () {
450
450
  * - `xmp`: Buffer containing raw XMP data, if present
451
451
  * - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
452
452
  * - `formatMagick`: String containing format for images loaded via *magick
453
+ * - `comments`: Array of keyword/text pairs representing PNG text blocks, if present.
453
454
  *
454
455
  * @example
455
456
  * const metadata = await sharp(input).metadata();
package/lib/libvips.js CHANGED
@@ -10,10 +10,10 @@ const semverGreaterThanOrEqualTo = require('semver/functions/gte');
10
10
  const semverSatisfies = require('semver/functions/satisfies');
11
11
  const detectLibc = require('detect-libc');
12
12
 
13
- const { engines, optionalDependencies } = require('../package.json');
13
+ const { config, engines, optionalDependencies } = require('../package.json');
14
14
 
15
15
  const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips || /* istanbul ignore next */
16
- engines.libvips;
16
+ config.libvips;
17
17
  const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
18
18
 
19
19
  const prebuiltPlatforms = [
package/lib/operation.js CHANGED
@@ -6,6 +6,17 @@
6
6
  const color = require('color');
7
7
  const is = require('./is');
8
8
 
9
+ /**
10
+ * How accurate an operation should be.
11
+ * @member
12
+ * @private
13
+ */
14
+ const vipsPrecision = {
15
+ integer: 'integer',
16
+ float: 'float',
17
+ approximate: 'approximate'
18
+ };
19
+
9
20
  /**
10
21
  * Rotate the output image by either an explicit angle
11
22
  * or auto-orient based on the EXIF `Orientation` tag.
@@ -367,23 +378,51 @@ function median (size) {
367
378
  * .blur(5)
368
379
  * .toBuffer();
369
380
  *
370
- * @param {number} [sigma] a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
381
+ * @param {Object|number|Boolean} [options]
382
+ * @param {number} [options.sigma] a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
383
+ * @param {string} [options.precision='integer'] How accurate the operation should be, one of: integer, float, approximate.
384
+ * @param {number} [options.minAmplitude=0.2] A value between 0.001 and 1. A smaller value will generate a larger, more accurate mask.
371
385
  * @returns {Sharp}
372
386
  * @throws {Error} Invalid parameters
373
387
  */
374
- function blur (sigma) {
375
- if (!is.defined(sigma)) {
388
+ function blur (options) {
389
+ let sigma;
390
+ if (is.number(options)) {
391
+ sigma = options;
392
+ } else if (is.plainObject(options)) {
393
+ if (!is.number(options.sigma)) {
394
+ throw is.invalidParameterError('options.sigma', 'number between 0.3 and 1000', sigma);
395
+ }
396
+ sigma = options.sigma;
397
+ if ('precision' in options) {
398
+ if (is.string(vipsPrecision[options.precision])) {
399
+ this.options.precision = vipsPrecision[options.precision];
400
+ } else {
401
+ throw is.invalidParameterError('precision', 'one of: integer, float, approximate', options.precision);
402
+ }
403
+ }
404
+ if ('minAmplitude' in options) {
405
+ if (is.number(options.minAmplitude) && is.inRange(options.minAmplitude, 0.001, 1)) {
406
+ this.options.minAmpl = options.minAmplitude;
407
+ } else {
408
+ throw is.invalidParameterError('minAmplitude', 'number between 0.001 and 1', options.minAmplitude);
409
+ }
410
+ }
411
+ }
412
+
413
+ if (!is.defined(options)) {
376
414
  // No arguments: default to mild blur
377
415
  this.options.blurSigma = -1;
378
- } else if (is.bool(sigma)) {
416
+ } else if (is.bool(options)) {
379
417
  // Boolean argument: apply mild blur?
380
- this.options.blurSigma = sigma ? -1 : 0;
418
+ this.options.blurSigma = options ? -1 : 0;
381
419
  } else if (is.number(sigma) && is.inRange(sigma, 0.3, 1000)) {
382
420
  // Numeric argument: specific sigma
383
421
  this.options.blurSigma = sigma;
384
422
  } else {
385
423
  throw is.invalidParameterError('sigma', 'number between 0.3 and 1000', sigma);
386
424
  }
425
+
387
426
  return this;
388
427
  }
389
428
 
package/lib/sharp.js CHANGED
@@ -57,7 +57,6 @@ if (sharp) {
57
57
  help.push(
58
58
  '- Ensure optional dependencies can be installed:',
59
59
  ' npm install --include=optional sharp',
60
- ' yarn add sharp --ignore-engines',
61
60
  '- Ensure your package manager supports multi-platform installation:',
62
61
  ' See https://sharp.pixelplumbing.com/install#cross-platform',
63
62
  '- Add platform-specific dependencies:',
@@ -73,10 +72,9 @@ if (sharp) {
73
72
  }
74
73
  if (isLinux && /(symbol not found|CXXABI_)/i.test(messages)) {
75
74
  try {
76
- const { engines } = require(`@revizly/sharp-libvips-${runtimePlatform}/package`);
77
-
75
+ const { config } = require(`@revizly/sharp-libvips-${runtimePlatform}/package`);
78
76
  const libcFound = `${familySync()} ${versionSync()}`;
79
- const libcRequires = `${engines.musl ? 'musl' : 'glibc'} ${engines.musl || engines.glibc}`;
77
+ const libcRequires = `${config.musl ? 'musl' : 'glibc'} ${config.musl || config.glibc}`;
80
78
  help.push(
81
79
  '- Update your OS:',
82
80
  ` Found ${libcFound}`,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@revizly/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.33.4-revizly7",
4
+ "version": "0.33.5-revizly2",
5
5
  "author": "Lovell Fuller <npm@lovell.info>",
6
6
  "homepage": "https://sharp.pixelplumbing.com",
7
7
  "contributors": [
@@ -139,17 +139,17 @@
139
139
  "dependencies": {
140
140
  "color": "^4.2.3",
141
141
  "detect-libc": "^2.0.3",
142
- "semver": "^7.6.0"
142
+ "semver": "^7.6.3"
143
143
  },
144
144
  "optionalDependencies": {
145
- "@revizly/sharp-libvips-linux-arm64": "1.0.7",
146
- "@revizly/sharp-libvips-linux-x64": "1.0.7",
147
- "@revizly/sharp-linux-arm64": "0.33.4-revizly6",
148
- "@revizly/sharp-linux-x64": "0.33.4-revizly6"
145
+ "@revizly/sharp-libvips-linux-arm64": "1.0.8",
146
+ "@revizly/sharp-libvips-linux-x64": "1.0.8",
147
+ "@revizly/sharp-linux-arm64": "0.33.5-revizly1",
148
+ "@revizly/sharp-linux-x64": "0.33.5-revizly1"
149
149
  },
150
150
  "devDependencies": {
151
151
  "@emnapi/runtime": "^1.2.0",
152
- "@revizly/sharp-libvips-dev": "1.0.7",
152
+ "@revizly/sharp-libvips-dev": "1.0.8",
153
153
  "@types/node": "*",
154
154
  "async": "^3.2.5",
155
155
  "cc": "^3.0.1",
@@ -157,10 +157,10 @@
157
157
  "exif-reader": "^2.0.1",
158
158
  "extract-zip": "^2.0.1",
159
159
  "icc": "^3.0.0",
160
- "jsdoc-to-markdown": "^8.0.1",
160
+ "jsdoc-to-markdown": "^8.0.3",
161
161
  "license-checker": "^25.0.1",
162
- "mocha": "^10.5.2",
163
- "node-addon-api": "^8.0.0",
162
+ "mocha": "^10.7.3",
163
+ "node-addon-api": "^8.1.0",
164
164
  "nyc": "^17.0.0",
165
165
  "prebuild": "^13.0.1",
166
166
  "semistandard": "^17.0.0",
@@ -169,8 +169,10 @@
169
169
  },
170
170
  "license": "Apache-2.0",
171
171
  "engines": {
172
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
173
- "libvips": ">=8.15.2"
172
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
173
+ },
174
+ "config": {
175
+ "libvips": ">=8.15.3"
174
176
  },
175
177
  "funding": {
176
178
  "url": "https://opencollective.com/libvips"
package/src/binding.gyp CHANGED
@@ -192,7 +192,7 @@
192
192
  '-Oz',
193
193
  '-sALLOW_MEMORY_GROWTH',
194
194
  '-sENVIRONMENT=node',
195
- '-sEXPORTED_FUNCTIONS=["_vips_shutdown", "_uv_library_shutdown"]',
195
+ '-sEXPORTED_FUNCTIONS=["emnapiInit", "_vips_shutdown", "_uv_library_shutdown"]',
196
196
  '-sNODERAWFS',
197
197
  '-sTEXTDECODER=0',
198
198
  '-sWASM_ASYNC_COMPILATION=0',
package/src/common.h CHANGED
@@ -16,8 +16,8 @@
16
16
 
17
17
  #if (VIPS_MAJOR_VERSION < 8) || \
18
18
  (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 15) || \
19
- (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 15 && VIPS_MICRO_VERSION < 2)
20
- #error "libvips version 8.15.2+ is required - please see https://sharp.pixelplumbing.com/install"
19
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 15 && VIPS_MICRO_VERSION < 3)
20
+ #error "libvips version 8.15.3+ is required - please see https://sharp.pixelplumbing.com/install"
21
21
  #endif
22
22
 
23
23
  #if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
package/src/metadata.cc CHANGED
@@ -10,6 +10,8 @@
10
10
  #include "common.h"
11
11
  #include "metadata.h"
12
12
 
13
+ static void* readPNGComment(VipsImage *image, const char *field, GValue *value, void *p);
14
+
13
15
  class MetadataWorker : public Napi::AsyncWorker {
14
16
  public:
15
17
  MetadataWorker(Napi::Function callback, MetadataBaton *baton, Napi::Function debuglog) :
@@ -131,6 +133,8 @@ class MetadataWorker : public Napi::AsyncWorker {
131
133
  memcpy(baton->tifftagPhotoshop, tifftagPhotoshop, tifftagPhotoshopLength);
132
134
  baton->tifftagPhotoshopLength = tifftagPhotoshopLength;
133
135
  }
136
+ // PNG comments
137
+ vips_image_map(image.get_image(), readPNGComment, &baton->comments);
134
138
  }
135
139
 
136
140
  // Clean up
@@ -246,6 +250,17 @@ class MetadataWorker : public Napi::AsyncWorker {
246
250
  Napi::Buffer<char>::NewOrCopy(env, baton->tifftagPhotoshop,
247
251
  baton->tifftagPhotoshopLength, sharp::FreeCallback));
248
252
  }
253
+ if (baton->comments.size() > 0) {
254
+ int i = 0;
255
+ Napi::Array comments = Napi::Array::New(env, baton->comments.size());
256
+ for (auto &c : baton->comments) {
257
+ Napi::Object comment = Napi::Object::New(env);
258
+ comment.Set("keyword", c.first);
259
+ comment.Set("text", c.second);
260
+ comments.Set(i++, comment);
261
+ }
262
+ info.Set("comments", comments);
263
+ }
249
264
  Callback().Call(Receiver().Value(), { env.Null(), info });
250
265
  } else {
251
266
  Callback().Call(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
@@ -285,3 +300,21 @@ Napi::Value metadata(const Napi::CallbackInfo& info) {
285
300
 
286
301
  return info.Env().Undefined();
287
302
  }
303
+
304
+ const char *PNG_COMMENT_START = "png-comment-";
305
+ const int PNG_COMMENT_START_LEN = strlen(PNG_COMMENT_START);
306
+
307
+ static void* readPNGComment(VipsImage *image, const char *field, GValue *value, void *p) {
308
+ MetadataComments *comments = static_cast<MetadataComments *>(p);
309
+
310
+ if (vips_isprefix(PNG_COMMENT_START, field)) {
311
+ const char *keyword = strchr(field + PNG_COMMENT_START_LEN, '-');
312
+ const char *str;
313
+ if (keyword != NULL && !vips_image_get_string(image, field, &str)) {
314
+ keyword++; // Skip the hyphen
315
+ comments->push_back(std::make_pair(keyword, str));
316
+ }
317
+ }
318
+
319
+ return NULL;
320
+ }
package/src/metadata.h CHANGED
@@ -9,6 +9,8 @@
9
9
 
10
10
  #include "./common.h"
11
11
 
12
+ typedef std::vector<std::pair<std::string, std::string>> MetadataComments;
13
+
12
14
  struct MetadataBaton {
13
15
  // Input
14
16
  sharp::InputDescriptor *input;
@@ -47,6 +49,7 @@ struct MetadataBaton {
47
49
  size_t xmpLength;
48
50
  char *tifftagPhotoshop;
49
51
  size_t tifftagPhotoshopLength;
52
+ MetadataComments comments;
50
53
  std::string err;
51
54
 
52
55
  MetadataBaton():
package/src/operations.cc CHANGED
@@ -144,7 +144,7 @@ namespace sharp {
144
144
  /*
145
145
  * Gaussian blur. Use sigma of -1.0 for fast blur.
146
146
  */
147
- VImage Blur(VImage image, double const sigma) {
147
+ VImage Blur(VImage image, double const sigma, VipsPrecision precision, double const minAmpl) {
148
148
  if (sigma == -1.0) {
149
149
  // Fast, mild blur - averages neighbouring pixels
150
150
  VImage blur = VImage::new_matrixv(3, 3,
@@ -155,7 +155,9 @@ namespace sharp {
155
155
  return image.conv(blur);
156
156
  } else {
157
157
  // Slower, accurate Gaussian blur
158
- return StaySequential(image).gaussblur(sigma);
158
+ return StaySequential(image).gaussblur(sigma, VImage::option()
159
+ ->set("precision", precision)
160
+ ->set("min_ampl", minAmpl));
159
161
  }
160
162
  }
161
163
 
package/src/operations.h CHANGED
@@ -47,7 +47,7 @@ namespace sharp {
47
47
  /*
48
48
  * Gaussian blur. Use sigma of -1.0 for fast blur.
49
49
  */
50
- VImage Blur(VImage image, double const sigma);
50
+ VImage Blur(VImage image, double const sigma, VipsPrecision precision, double const minAmpl);
51
51
 
52
52
  /*
53
53
  * Convolution with a kernel.
package/src/pipeline.cc CHANGED
@@ -325,6 +325,7 @@ class PipelineWorker : public Napi::AsyncWorker {
325
325
  if ((baton->keepMetadata & VIPS_FOREIGN_KEEP_ICC) && baton->withIccProfile.empty()) {
326
326
  // Cache input profile for use with output
327
327
  inputProfile = sharp::GetProfile(image);
328
+ baton->input->ignoreIcc = true;
328
329
  }
329
330
  char const *processingProfile = image.interpretation() == VIPS_INTERPRETATION_RGB16 ? "p3" : "srgb";
330
331
  if (
@@ -592,7 +593,7 @@ class PipelineWorker : public Napi::AsyncWorker {
592
593
 
593
594
  // Blur
594
595
  if (shouldBlur) {
595
- image = sharp::Blur(image, baton->blurSigma);
596
+ image = sharp::Blur(image, baton->blurSigma, baton->precision, baton->minAmpl);
596
597
  }
597
598
 
598
599
  // Unflatten the image
@@ -1541,6 +1542,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1541
1542
  baton->negate = sharp::AttrAsBool(options, "negate");
1542
1543
  baton->negateAlpha = sharp::AttrAsBool(options, "negateAlpha");
1543
1544
  baton->blurSigma = sharp::AttrAsDouble(options, "blurSigma");
1545
+ baton->precision = sharp::AttrAsEnum<VipsPrecision>(options, "precision", VIPS_TYPE_PRECISION);
1546
+ baton->minAmpl = sharp::AttrAsDouble(options, "minAmpl");
1544
1547
  baton->brightness = sharp::AttrAsDouble(options, "brightness");
1545
1548
  baton->saturation = sharp::AttrAsDouble(options, "saturation");
1546
1549
  baton->hue = sharp::AttrAsInt32(options, "hue");
package/src/pipeline.h CHANGED
@@ -78,6 +78,8 @@ struct PipelineBaton {
78
78
  bool negate;
79
79
  bool negateAlpha;
80
80
  double blurSigma;
81
+ VipsPrecision precision;
82
+ double minAmpl;
81
83
  double brightness;
82
84
  double saturation;
83
85
  int hue;