sharp 0.25.1 → 0.26.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/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 and TIFF images",
4
- "version": "0.25.1",
4
+ "version": "0.26.0",
5
5
  "author": "Lovell Fuller <npm@lovell.info>",
6
6
  "homepage": "https://github.com/lovell/sharp",
7
7
  "contributors": [
@@ -65,17 +65,21 @@
65
65
  "Andargor <andargor@yahoo.com>",
66
66
  "Paul Neave <paul.neave@gmail.com>",
67
67
  "Brendan Kennedy <brenwken@gmail.com>",
68
- "Brychan Bennett-Odlum <git@brychan.io>"
68
+ "Brychan Bennett-Odlum <git@brychan.io>",
69
+ "Edward Silverton <e.silverton@gmail.com>",
70
+ "Roman Malieiev <aromaleev@gmail.com>",
71
+ "Tomas Szabo <tomas.szabo@deftomat.com>",
72
+ "Robert O'Rourke <robert@o-rourke.org>"
69
73
  ],
70
74
  "scripts": {
71
- "install": "(node install/libvips && node install/dll-copy && prebuild-install --runtime=napi) || (node-gyp rebuild && node install/dll-copy)",
75
+ "install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
72
76
  "clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
73
- "test": "semistandard && cpplint && npm run test-unit && npm run test-licensing && prebuild-ci",
77
+ "test": "semistandard && cpplint && npm run test-unit && npm run test-licensing && node install/prebuild-ci",
74
78
  "test-unit": "nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js",
75
79
  "test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;MIT\"",
76
80
  "test-coverage": "./test/coverage/report.sh",
77
81
  "test-leak": "./test/leak/leak.sh",
78
- "docs-build": "for m in constructor input resize composite operation colour channel output utility; do documentation build --shallow --format=md --markdown-toc=false lib/$m.js >docs/api-$m.md; done",
82
+ "docs-build": "documentation lint lib && for m in constructor input resize composite operation colour channel output utility; do documentation build --shallow --format=md --markdown-toc=false lib/$m.js >docs/api-$m.md; done && node docs/search-index/build",
79
83
  "docs-serve": "cd docs && npx serve",
80
84
  "docs-publish": "cd docs && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp"
81
85
  },
@@ -83,6 +87,7 @@
83
87
  "files": [
84
88
  "binding.gyp",
85
89
  "install/**",
90
+ "!install/prebuild-ci.js",
86
91
  "lib/**",
87
92
  "src/**"
88
93
  ],
@@ -109,36 +114,37 @@
109
114
  "dependencies": {
110
115
  "color": "^3.1.2",
111
116
  "detect-libc": "^1.0.3",
112
- "node-addon-api": "^2.0.0",
117
+ "node-addon-api": "^3.0.0",
113
118
  "npmlog": "^4.1.2",
114
- "prebuild-install": "^5.3.3",
115
- "semver": "^7.1.3",
116
- "simple-get": "^3.1.0",
117
- "tar": "^6.0.1",
119
+ "prebuild-install": "^5.3.5",
120
+ "semver": "^7.3.2",
121
+ "simple-get": "^4.0.0",
122
+ "tar-fs": "^2.1.0",
118
123
  "tunnel-agent": "^0.6.0"
119
124
  },
120
125
  "devDependencies": {
121
126
  "async": "^3.2.0",
122
127
  "cc": "^2.0.1",
123
128
  "decompress-zip": "^0.3.2",
124
- "documentation": "^12.1.4",
129
+ "documentation": "^13.0.2",
125
130
  "exif-reader": "^1.0.3",
126
- "icc": "^1.0.0",
131
+ "icc": "^2.0.0",
127
132
  "license-checker": "^25.0.1",
128
- "mocha": "^7.1.0",
129
- "mock-fs": "^4.11.0",
130
- "nyc": "^15.0.0",
131
- "prebuild": "^10.0.0",
132
- "prebuild-ci": "^3.1.0",
133
+ "mocha": "^8.1.1",
134
+ "mock-fs": "^4.13.0",
135
+ "nyc": "^15.1.0",
136
+ "prebuild": "^10.0.1",
133
137
  "rimraf": "^3.0.2",
134
- "semistandard": "^14.2.0"
138
+ "semistandard": "^14.2.3"
135
139
  },
136
140
  "license": "Apache-2.0",
137
141
  "config": {
138
- "libvips": "8.9.1"
142
+ "libvips": "8.10.0",
143
+ "runtime": "napi",
144
+ "target": 3
139
145
  },
140
146
  "engines": {
141
- "node": ">=10"
147
+ "node": ">=10.16.0"
142
148
  },
143
149
  "funding": {
144
150
  "url": "https://opencollective.com/libvips"
package/src/common.cc CHANGED
@@ -17,6 +17,7 @@
17
17
  #include <string.h>
18
18
  #include <vector>
19
19
  #include <queue>
20
+ #include <map>
20
21
  #include <mutex> // NOLINT(build/c++11)
21
22
 
22
23
  #include <napi.h>
@@ -41,6 +42,9 @@ namespace sharp {
41
42
  int32_t AttrAsInt32(Napi::Object obj, std::string attr) {
42
43
  return obj.Get(attr).As<Napi::Number>().Int32Value();
43
44
  }
45
+ int32_t AttrAsInt32(Napi::Object obj, unsigned int const attr) {
46
+ return obj.Get(attr).As<Napi::Number>().Int32Value();
47
+ }
44
48
  double AttrAsDouble(Napi::Object obj, std::string attr) {
45
49
  return obj.Get(attr).As<Napi::Number>().DoubleValue();
46
50
  }
@@ -58,6 +62,14 @@ namespace sharp {
58
62
  }
59
63
  return rgba;
60
64
  }
65
+ std::vector<int32_t> AttrAsInt32Vector(Napi::Object obj, std::string attr) {
66
+ Napi::Array array = obj.Get(attr).As<Napi::Array>();
67
+ std::vector<int32_t> vector(array.Length());
68
+ for (unsigned int i = 0; i < array.Length(); i++) {
69
+ vector[i] = AttrAsInt32(array, i);
70
+ }
71
+ return vector;
72
+ }
61
73
 
62
74
  // Create an InputDescriptor instance from a Napi::Object describing an input image
63
75
  InputDescriptor* CreateInputDescriptor(Napi::Object input) {
@@ -88,6 +100,10 @@ namespace sharp {
88
100
  if (HasAttr(input, "page")) {
89
101
  descriptor->page = AttrAsUint32(input, "page");
90
102
  }
103
+ // Multi-level input (OpenSlide)
104
+ if (HasAttr(input, "level")) {
105
+ descriptor->level = AttrAsUint32(input, "level");
106
+ }
91
107
  // Create new image
92
108
  if (HasAttr(input, "createChannels")) {
93
109
  descriptor->createChannels = AttrAsUint32(input, "createChannels");
@@ -121,6 +137,9 @@ namespace sharp {
121
137
  bool IsWebp(std::string const &str) {
122
138
  return EndsWith(str, ".webp") || EndsWith(str, ".WEBP");
123
139
  }
140
+ bool IsGif(std::string const &str) {
141
+ return EndsWith(str, ".gif") || EndsWith(str, ".GIF");
142
+ }
124
143
  bool IsTiff(std::string const &str) {
125
144
  return EndsWith(str, ".tif") || EndsWith(str, ".tiff") || EndsWith(str, ".TIF") || EndsWith(str, ".TIFF");
126
145
  }
@@ -169,32 +188,42 @@ namespace sharp {
169
188
  return id;
170
189
  }
171
190
 
191
+ std::map<std::string, ImageType> loaderToType = {
192
+ { "jpegload", ImageType::JPEG },
193
+ { "jpegload_buffer", ImageType::JPEG },
194
+ { "pngload", ImageType::PNG },
195
+ { "pngload_buffer", ImageType::PNG },
196
+ { "webpload", ImageType::WEBP },
197
+ { "webpload_buffer", ImageType::WEBP },
198
+ { "tiffload", ImageType::TIFF },
199
+ { "tiffload_buffer", ImageType::TIFF },
200
+ { "gifload", ImageType::GIF },
201
+ { "gifload_buffer", ImageType::GIF },
202
+ { "svgload", ImageType::SVG },
203
+ { "svgload_buffer", ImageType::SVG },
204
+ { "heifload", ImageType::HEIF },
205
+ { "heifload_buffer", ImageType::HEIF },
206
+ { "pdfload", ImageType::PDF },
207
+ { "pdfload_buffer", ImageType::PDF },
208
+ { "magickload", ImageType::MAGICK },
209
+ { "magickload_buffer", ImageType::MAGICK },
210
+ { "openslideload", ImageType::OPENSLIDE },
211
+ { "ppmload", ImageType::PPM },
212
+ { "fitsload", ImageType::FITS },
213
+ { "vipsload", ImageType::VIPS },
214
+ { "rawload", ImageType::RAW }
215
+ };
216
+
172
217
  /*
173
218
  Determine image format of a buffer.
174
219
  */
175
220
  ImageType DetermineImageType(void *buffer, size_t const length) {
176
221
  ImageType imageType = ImageType::UNKNOWN;
177
222
  char const *load = vips_foreign_find_load_buffer(buffer, length);
178
- if (load != NULL) {
179
- std::string const loader = load;
180
- if (EndsWith(loader, "JpegBuffer")) {
181
- imageType = ImageType::JPEG;
182
- } else if (EndsWith(loader, "PngBuffer")) {
183
- imageType = ImageType::PNG;
184
- } else if (EndsWith(loader, "WebpBuffer")) {
185
- imageType = ImageType::WEBP;
186
- } else if (EndsWith(loader, "TiffBuffer")) {
187
- imageType = ImageType::TIFF;
188
- } else if (EndsWith(loader, "GifBuffer")) {
189
- imageType = ImageType::GIF;
190
- } else if (EndsWith(loader, "SvgBuffer")) {
191
- imageType = ImageType::SVG;
192
- } else if (EndsWith(loader, "HeifBuffer")) {
193
- imageType = ImageType::HEIF;
194
- } else if (EndsWith(loader, "PdfBuffer")) {
195
- imageType = ImageType::PDF;
196
- } else if (EndsWith(loader, "MagickBuffer")) {
197
- imageType = ImageType::MAGICK;
223
+ if (load != nullptr) {
224
+ auto it = loaderToType.find(vips_nickname_find(g_type_from_name(load)));
225
+ if (it != loaderToType.end()) {
226
+ imageType = it->second;
198
227
  }
199
228
  }
200
229
  return imageType;
@@ -207,36 +236,12 @@ namespace sharp {
207
236
  ImageType imageType = ImageType::UNKNOWN;
208
237
  char const *load = vips_foreign_find_load(file);
209
238
  if (load != nullptr) {
210
- std::string const loader = load;
211
- if (EndsWith(loader, "JpegFile")) {
212
- imageType = ImageType::JPEG;
213
- } else if (EndsWith(loader, "PngFile")) {
214
- imageType = ImageType::PNG;
215
- } else if (EndsWith(loader, "WebpFile")) {
216
- imageType = ImageType::WEBP;
217
- } else if (EndsWith(loader, "Openslide")) {
218
- imageType = ImageType::OPENSLIDE;
219
- } else if (EndsWith(loader, "TiffFile")) {
220
- imageType = ImageType::TIFF;
221
- } else if (EndsWith(loader, "GifFile")) {
222
- imageType = ImageType::GIF;
223
- } else if (EndsWith(loader, "SvgFile")) {
224
- imageType = ImageType::SVG;
225
- } else if (EndsWith(loader, "HeifFile")) {
226
- imageType = ImageType::HEIF;
227
- } else if (EndsWith(loader, "PdfFile")) {
228
- imageType = ImageType::PDF;
229
- } else if (EndsWith(loader, "Ppm")) {
230
- imageType = ImageType::PPM;
231
- } else if (EndsWith(loader, "Fits")) {
232
- imageType = ImageType::FITS;
233
- } else if (EndsWith(loader, "Vips")) {
234
- imageType = ImageType::VIPS;
235
- } else if (EndsWith(loader, "Magick") || EndsWith(loader, "MagickFile")) {
236
- imageType = ImageType::MAGICK;
239
+ auto it = loaderToType.find(vips_nickname_find(g_type_from_name(load)));
240
+ if (it != loaderToType.end()) {
241
+ imageType = it->second;
237
242
  }
238
243
  } else {
239
- if (EndsWith(vips::VError().what(), " not found\n")) {
244
+ if (EndsWith(vips::VError().what(), " does not exist\n")) {
240
245
  imageType = ImageType::MISSING;
241
246
  }
242
247
  }
@@ -248,6 +253,8 @@ namespace sharp {
248
253
  */
249
254
  bool ImageTypeSupportsPage(ImageType imageType) {
250
255
  return
256
+ imageType == ImageType::WEBP ||
257
+ imageType == ImageType::MAGICK ||
251
258
  imageType == ImageType::GIF ||
252
259
  imageType == ImageType::TIFF ||
253
260
  imageType == ImageType::HEIF ||
@@ -279,6 +286,9 @@ namespace sharp {
279
286
  vips::VOption *option = VImage::option()
280
287
  ->set("access", descriptor->access)
281
288
  ->set("fail", descriptor->failOnError);
289
+ if (imageType == ImageType::SVG) {
290
+ option->set("unlimited", TRUE);
291
+ }
282
292
  if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
283
293
  option->set("dpi", descriptor->density);
284
294
  }
@@ -289,6 +299,9 @@ namespace sharp {
289
299
  option->set("n", descriptor->pages);
290
300
  option->set("page", descriptor->page);
291
301
  }
302
+ if (imageType == ImageType::OPENSLIDE) {
303
+ option->set("level", descriptor->level);
304
+ }
292
305
  image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
293
306
  if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
294
307
  image = SetDensity(image, descriptor->density);
@@ -325,6 +338,9 @@ namespace sharp {
325
338
  vips::VOption *option = VImage::option()
326
339
  ->set("access", descriptor->access)
327
340
  ->set("fail", descriptor->failOnError);
341
+ if (imageType == ImageType::SVG) {
342
+ option->set("unlimited", TRUE);
343
+ }
328
344
  if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
329
345
  option->set("dpi", descriptor->density);
330
346
  }
@@ -335,6 +351,9 @@ namespace sharp {
335
351
  option->set("n", descriptor->pages);
336
352
  option->set("page", descriptor->page);
337
353
  }
354
+ if (imageType == ImageType::OPENSLIDE) {
355
+ option->set("level", descriptor->level);
356
+ }
338
357
  image = VImage::new_from_file(descriptor->file.data(), option);
339
358
  if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
340
359
  image = SetDensity(image, descriptor->density);
@@ -404,6 +423,38 @@ namespace sharp {
404
423
  return copy;
405
424
  }
406
425
 
426
+ /*
427
+ Set animation properties if necessary.
428
+ Non-provided properties will be loaded from image.
429
+ */
430
+ VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop) {
431
+ bool hasDelay = delay.size() != 1 || delay.front() != -1;
432
+
433
+ if (pageHeight == 0 && image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT) {
434
+ pageHeight = image.get_int(VIPS_META_PAGE_HEIGHT);
435
+ }
436
+
437
+ if (!hasDelay && image.get_typeof("delay") == VIPS_TYPE_ARRAY_INT) {
438
+ delay = image.get_array_int("delay");
439
+ hasDelay = true;
440
+ }
441
+
442
+ if (loop == -1 && image.get_typeof("loop") == G_TYPE_INT) {
443
+ loop = image.get_int("loop");
444
+ }
445
+
446
+ if (pageHeight == 0) return image;
447
+
448
+ // It is necessary to create the copy as otherwise, pageHeight will be ignored!
449
+ VImage copy = image.copy();
450
+
451
+ copy.set(VIPS_META_PAGE_HEIGHT, pageHeight);
452
+ if (hasDelay) copy.set("delay", delay);
453
+ if (loop != -1) copy.set("loop", loop);
454
+
455
+ return copy;
456
+ }
457
+
407
458
  /*
408
459
  Does this image have a non-default density?
409
460
  */
@@ -434,14 +485,21 @@ namespace sharp {
434
485
  Check the proposed format supports the current dimensions.
435
486
  */
436
487
  void AssertImageTypeDimensions(VImage image, ImageType const imageType) {
488
+ const int height = image.get_typeof("pageHeight") == G_TYPE_INT
489
+ ? image.get_int("pageHeight")
490
+ : image.height();
437
491
  if (imageType == ImageType::JPEG) {
438
- if (image.width() > 65535 || image.height() > 65535) {
492
+ if (image.width() > 65535 || height > 65535) {
439
493
  throw vips::VError("Processed image is too large for the JPEG format");
440
494
  }
441
495
  } else if (imageType == ImageType::WEBP) {
442
- if (image.width() > 16383 || image.height() > 16383) {
496
+ if (image.width() > 16383 || height > 16383) {
443
497
  throw vips::VError("Processed image is too large for the WebP format");
444
498
  }
499
+ } else if (imageType == ImageType::GIF) {
500
+ if (image.width() > 65535 || height > 65535) {
501
+ throw vips::VError("Processed image is too large for the GIF format");
502
+ }
445
503
  }
446
504
  }
447
505
 
@@ -704,4 +762,25 @@ namespace sharp {
704
762
  return std::make_tuple(image, alphaColour);
705
763
  }
706
764
 
765
+ /*
766
+ Removes alpha channel, if any.
767
+ */
768
+ VImage RemoveAlpha(VImage image) {
769
+ if (HasAlpha(image)) {
770
+ image = image.extract_band(0, VImage::option()->set("n", image.bands() - 1));
771
+ }
772
+ return image;
773
+ }
774
+
775
+ /*
776
+ Ensures alpha channel, if missing.
777
+ */
778
+ VImage EnsureAlpha(VImage image) {
779
+ if (!HasAlpha(image)) {
780
+ std::vector<double> alpha;
781
+ alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
782
+ image = image.bandjoin_const(alpha);
783
+ }
784
+ return image;
785
+ }
707
786
  } // namespace sharp
package/src/common.h CHANGED
@@ -24,8 +24,8 @@
24
24
 
25
25
  // Verify platform and compiler compatibility
26
26
 
27
- #if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 9))
28
- #error "libvips version 8.9.1+ is required - please see https://sharp.pixelplumbing.com/install"
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"
29
29
  #endif
30
30
 
31
31
  #if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
@@ -57,6 +57,7 @@ namespace sharp {
57
57
  int rawHeight;
58
58
  int pages;
59
59
  int page;
60
+ int level;
60
61
  int createChannels;
61
62
  int createWidth;
62
63
  int createHeight;
@@ -75,6 +76,7 @@ namespace sharp {
75
76
  rawHeight(0),
76
77
  pages(1),
77
78
  page(0),
79
+ level(0),
78
80
  createChannels(0),
79
81
  createWidth(0),
80
82
  createHeight(0),
@@ -86,10 +88,12 @@ namespace sharp {
86
88
  std::string AttrAsStr(Napi::Object obj, std::string attr);
87
89
  uint32_t AttrAsUint32(Napi::Object obj, std::string attr);
88
90
  int32_t AttrAsInt32(Napi::Object obj, std::string attr);
91
+ int32_t AttrAsInt32(Napi::Object obj, unsigned int const attr);
89
92
  double AttrAsDouble(Napi::Object obj, std::string attr);
90
93
  double AttrAsDouble(Napi::Object obj, unsigned int const attr);
91
94
  bool AttrAsBool(Napi::Object obj, std::string attr);
92
95
  std::vector<double> AttrAsRgba(Napi::Object obj, std::string attr);
96
+ std::vector<int32_t> AttrAsInt32Vector(Napi::Object obj, std::string attr);
93
97
 
94
98
  // Create an InputDescriptor instance from a Napi::Object describing an input image
95
99
  InputDescriptor* CreateInputDescriptor(Napi::Object input);
@@ -123,6 +127,7 @@ namespace sharp {
123
127
  bool IsJpeg(std::string const &str);
124
128
  bool IsPng(std::string const &str);
125
129
  bool IsWebp(std::string const &str);
130
+ bool IsGif(std::string const &str);
126
131
  bool IsTiff(std::string const &str);
127
132
  bool IsHeic(std::string const &str);
128
133
  bool IsHeif(std::string const &str);
@@ -182,6 +187,12 @@ namespace sharp {
182
187
  */
183
188
  VImage RemoveExifOrientation(VImage image);
184
189
 
190
+ /*
191
+ Set animation properties if necessary.
192
+ Non-provided properties will be loaded from image.
193
+ */
194
+ VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop);
195
+
185
196
  /*
186
197
  Does this image have a non-default density?
187
198
  */
@@ -269,6 +280,16 @@ namespace sharp {
269
280
  */
270
281
  std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour);
271
282
 
283
+ /*
284
+ Removes alpha channel, if any.
285
+ */
286
+ VImage RemoveAlpha(VImage image);
287
+
288
+ /*
289
+ Ensures alpha channel, if missing.
290
+ */
291
+ VImage EnsureAlpha(VImage image);
292
+
272
293
  } // namespace sharp
273
294
 
274
295
  #endif // SRC_COMMON_H_