sharp 0.25.3 → 0.26.2

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/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
  }
@@ -161,6 +180,7 @@ namespace sharp {
161
180
  case ImageType::OPENSLIDE: id = "openslide"; break;
162
181
  case ImageType::PPM: id = "ppm"; break;
163
182
  case ImageType::FITS: id = "fits"; break;
183
+ case ImageType::EXR: id = "exr"; break;
164
184
  case ImageType::VIPS: id = "vips"; break;
165
185
  case ImageType::RAW: id = "raw"; break;
166
186
  case ImageType::UNKNOWN: id = "unknown"; break;
@@ -169,32 +189,43 @@ namespace sharp {
169
189
  return id;
170
190
  }
171
191
 
192
+ std::map<std::string, ImageType> loaderToType = {
193
+ { "jpegload", ImageType::JPEG },
194
+ { "jpegload_buffer", ImageType::JPEG },
195
+ { "pngload", ImageType::PNG },
196
+ { "pngload_buffer", ImageType::PNG },
197
+ { "webpload", ImageType::WEBP },
198
+ { "webpload_buffer", ImageType::WEBP },
199
+ { "tiffload", ImageType::TIFF },
200
+ { "tiffload_buffer", ImageType::TIFF },
201
+ { "gifload", ImageType::GIF },
202
+ { "gifload_buffer", ImageType::GIF },
203
+ { "svgload", ImageType::SVG },
204
+ { "svgload_buffer", ImageType::SVG },
205
+ { "heifload", ImageType::HEIF },
206
+ { "heifload_buffer", ImageType::HEIF },
207
+ { "pdfload", ImageType::PDF },
208
+ { "pdfload_buffer", ImageType::PDF },
209
+ { "magickload", ImageType::MAGICK },
210
+ { "magickload_buffer", ImageType::MAGICK },
211
+ { "openslideload", ImageType::OPENSLIDE },
212
+ { "ppmload", ImageType::PPM },
213
+ { "fitsload", ImageType::FITS },
214
+ { "openexrload", ImageType::EXR },
215
+ { "vipsload", ImageType::VIPS },
216
+ { "rawload", ImageType::RAW }
217
+ };
218
+
172
219
  /*
173
220
  Determine image format of a buffer.
174
221
  */
175
222
  ImageType DetermineImageType(void *buffer, size_t const length) {
176
223
  ImageType imageType = ImageType::UNKNOWN;
177
224
  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;
225
+ if (load != nullptr) {
226
+ auto it = loaderToType.find(vips_nickname_find(g_type_from_name(load)));
227
+ if (it != loaderToType.end()) {
228
+ imageType = it->second;
198
229
  }
199
230
  }
200
231
  return imageType;
@@ -207,36 +238,12 @@ namespace sharp {
207
238
  ImageType imageType = ImageType::UNKNOWN;
208
239
  char const *load = vips_foreign_find_load(file);
209
240
  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;
241
+ auto it = loaderToType.find(vips_nickname_find(g_type_from_name(load)));
242
+ if (it != loaderToType.end()) {
243
+ imageType = it->second;
237
244
  }
238
245
  } else {
239
- if (EndsWith(vips::VError().what(), " not found\n")) {
246
+ if (EndsWith(vips::VError().what(), " does not exist\n")) {
240
247
  imageType = ImageType::MISSING;
241
248
  }
242
249
  }
@@ -248,6 +255,8 @@ namespace sharp {
248
255
  */
249
256
  bool ImageTypeSupportsPage(ImageType imageType) {
250
257
  return
258
+ imageType == ImageType::WEBP ||
259
+ imageType == ImageType::MAGICK ||
251
260
  imageType == ImageType::GIF ||
252
261
  imageType == ImageType::TIFF ||
253
262
  imageType == ImageType::HEIF ||
@@ -292,6 +301,9 @@ namespace sharp {
292
301
  option->set("n", descriptor->pages);
293
302
  option->set("page", descriptor->page);
294
303
  }
304
+ if (imageType == ImageType::OPENSLIDE) {
305
+ option->set("level", descriptor->level);
306
+ }
295
307
  image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
296
308
  if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
297
309
  image = SetDensity(image, descriptor->density);
@@ -341,6 +353,9 @@ namespace sharp {
341
353
  option->set("n", descriptor->pages);
342
354
  option->set("page", descriptor->page);
343
355
  }
356
+ if (imageType == ImageType::OPENSLIDE) {
357
+ option->set("level", descriptor->level);
358
+ }
344
359
  image = VImage::new_from_file(descriptor->file.data(), option);
345
360
  if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
346
361
  image = SetDensity(image, descriptor->density);
@@ -410,6 +425,38 @@ namespace sharp {
410
425
  return copy;
411
426
  }
412
427
 
428
+ /*
429
+ Set animation properties if necessary.
430
+ Non-provided properties will be loaded from image.
431
+ */
432
+ VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop) {
433
+ bool hasDelay = delay.size() != 1 || delay.front() != -1;
434
+
435
+ if (pageHeight == 0 && image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT) {
436
+ pageHeight = image.get_int(VIPS_META_PAGE_HEIGHT);
437
+ }
438
+
439
+ if (!hasDelay && image.get_typeof("delay") == VIPS_TYPE_ARRAY_INT) {
440
+ delay = image.get_array_int("delay");
441
+ hasDelay = true;
442
+ }
443
+
444
+ if (loop == -1 && image.get_typeof("loop") == G_TYPE_INT) {
445
+ loop = image.get_int("loop");
446
+ }
447
+
448
+ if (pageHeight == 0) return image;
449
+
450
+ // It is necessary to create the copy as otherwise, pageHeight will be ignored!
451
+ VImage copy = image.copy();
452
+
453
+ copy.set(VIPS_META_PAGE_HEIGHT, pageHeight);
454
+ if (hasDelay) copy.set("delay", delay);
455
+ if (loop != -1) copy.set("loop", loop);
456
+
457
+ return copy;
458
+ }
459
+
413
460
  /*
414
461
  Does this image have a non-default density?
415
462
  */
@@ -440,14 +487,21 @@ namespace sharp {
440
487
  Check the proposed format supports the current dimensions.
441
488
  */
442
489
  void AssertImageTypeDimensions(VImage image, ImageType const imageType) {
490
+ const int height = image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT
491
+ ? image.get_int(VIPS_META_PAGE_HEIGHT)
492
+ : image.height();
443
493
  if (imageType == ImageType::JPEG) {
444
- if (image.width() > 65535 || image.height() > 65535) {
494
+ if (image.width() > 65535 || height > 65535) {
445
495
  throw vips::VError("Processed image is too large for the JPEG format");
446
496
  }
447
497
  } else if (imageType == ImageType::WEBP) {
448
- if (image.width() > 16383 || image.height() > 16383) {
498
+ if (image.width() > 16383 || height > 16383) {
449
499
  throw vips::VError("Processed image is too large for the WebP format");
450
500
  }
501
+ } else if (imageType == ImageType::GIF) {
502
+ if (image.width() > 65535 || height > 65535) {
503
+ throw vips::VError("Processed image is too large for the GIF format");
504
+ }
451
505
  }
452
506
  }
453
507
 
@@ -710,4 +764,25 @@ namespace sharp {
710
764
  return std::make_tuple(image, alphaColour);
711
765
  }
712
766
 
767
+ /*
768
+ Removes alpha channel, if any.
769
+ */
770
+ VImage RemoveAlpha(VImage image) {
771
+ if (HasAlpha(image)) {
772
+ image = image.extract_band(0, VImage::option()->set("n", image.bands() - 1));
773
+ }
774
+ return image;
775
+ }
776
+
777
+ /*
778
+ Ensures alpha channel, if missing.
779
+ */
780
+ VImage EnsureAlpha(VImage image) {
781
+ if (!HasAlpha(image)) {
782
+ std::vector<double> alpha;
783
+ alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
784
+ image = image.bandjoin_const(alpha);
785
+ }
786
+ return image;
787
+ }
713
788
  } // 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);
@@ -107,6 +111,7 @@ namespace sharp {
107
111
  OPENSLIDE,
108
112
  PPM,
109
113
  FITS,
114
+ EXR,
110
115
  VIPS,
111
116
  RAW,
112
117
  UNKNOWN,
@@ -123,6 +128,7 @@ namespace sharp {
123
128
  bool IsJpeg(std::string const &str);
124
129
  bool IsPng(std::string const &str);
125
130
  bool IsWebp(std::string const &str);
131
+ bool IsGif(std::string const &str);
126
132
  bool IsTiff(std::string const &str);
127
133
  bool IsHeic(std::string const &str);
128
134
  bool IsHeif(std::string const &str);
@@ -182,6 +188,12 @@ namespace sharp {
182
188
  */
183
189
  VImage RemoveExifOrientation(VImage image);
184
190
 
191
+ /*
192
+ Set animation properties if necessary.
193
+ Non-provided properties will be loaded from image.
194
+ */
195
+ VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop);
196
+
185
197
  /*
186
198
  Does this image have a non-default density?
187
199
  */
@@ -269,6 +281,16 @@ namespace sharp {
269
281
  */
270
282
  std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour);
271
283
 
284
+ /*
285
+ Removes alpha channel, if any.
286
+ */
287
+ VImage RemoveAlpha(VImage image);
288
+
289
+ /*
290
+ Ensures alpha channel, if missing.
291
+ */
292
+ VImage EnsureAlpha(VImage image);
293
+
272
294
  } // namespace sharp
273
295
 
274
296
  #endif // SRC_COMMON_H_