@revizly/sharp 0.33.4-revizly7 → 0.33.5-revizly1

Sign up to get free protection for your applications and to get access to all the features.
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-revizly1",
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",
145
+ "@revizly/sharp-libvips-linux-arm64": "1.0.8",
146
+ "@revizly/sharp-libvips-linux-x64": "1.0.8",
147
147
  "@revizly/sharp-linux-arm64": "0.33.4-revizly6",
148
148
  "@revizly/sharp-linux-x64": "0.33.4-revizly6"
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;