sharp 0.27.1 → 0.28.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.h CHANGED
@@ -26,8 +26,8 @@
26
26
 
27
27
  #if (VIPS_MAJOR_VERSION < 8) || \
28
28
  (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 10) || \
29
- (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 10 && VIPS_MICRO_VERSION < 5)
30
- #error "libvips version 8.10.5+ is required - please see https://sharp.pixelplumbing.com/install"
29
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 10 && VIPS_MICRO_VERSION < 6)
30
+ #error "libvips version 8.10.6+ is required - please see https://sharp.pixelplumbing.com/install"
31
31
  #endif
32
32
 
33
33
  #if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
@@ -57,9 +57,11 @@ namespace sharp {
57
57
  int rawChannels;
58
58
  int rawWidth;
59
59
  int rawHeight;
60
+ bool rawPremultiplied;
60
61
  int pages;
61
62
  int page;
62
63
  int level;
64
+ int subifd;
63
65
  int createChannels;
64
66
  int createWidth;
65
67
  int createHeight;
@@ -79,9 +81,11 @@ namespace sharp {
79
81
  rawChannels(0),
80
82
  rawWidth(0),
81
83
  rawHeight(0),
84
+ rawPremultiplied(false),
82
85
  pages(1),
83
86
  page(0),
84
87
  level(0),
88
+ subifd(-1),
85
89
  createChannels(0),
86
90
  createWidth(0),
87
91
  createHeight(0),
@@ -93,6 +97,7 @@ namespace sharp {
93
97
  // Convenience methods to access the attributes of a Napi::Object
94
98
  bool HasAttr(Napi::Object obj, std::string attr);
95
99
  std::string AttrAsStr(Napi::Object obj, std::string attr);
100
+ std::string AttrAsStr(Napi::Object obj, unsigned int const attr);
96
101
  uint32_t AttrAsUint32(Napi::Object obj, std::string attr);
97
102
  int32_t AttrAsInt32(Napi::Object obj, std::string attr);
98
103
  int32_t AttrAsInt32(Napi::Object obj, unsigned int const attr);
@@ -296,7 +301,7 @@ namespace sharp {
296
301
  /*
297
302
  Ensures alpha channel, if missing.
298
303
  */
299
- VImage EnsureAlpha(VImage image);
304
+ VImage EnsureAlpha(VImage image, double const value);
300
305
 
301
306
  } // namespace sharp
302
307
 
package/src/metadata.cc CHANGED
@@ -86,6 +86,9 @@ class MetadataWorker : public Napi::AsyncWorker {
86
86
  baton->levels.push_back(std::pair<int, int>(width, height));
87
87
  }
88
88
  }
89
+ if (image.get_typeof(VIPS_META_N_SUBIFDS) == G_TYPE_INT) {
90
+ baton->subifds = image.get_int(VIPS_META_N_SUBIFDS);
91
+ }
89
92
  baton->hasProfile = sharp::HasProfile(image);
90
93
  // Derived attributes
91
94
  baton->hasAlpha = sharp::HasAlpha(image);
@@ -203,6 +206,9 @@ class MetadataWorker : public Napi::AsyncWorker {
203
206
  }
204
207
  info.Set("levels", levels);
205
208
  }
209
+ if (baton->subifds > 0) {
210
+ info.Set("subifds", baton->subifds);
211
+ }
206
212
  info.Set("hasProfile", baton->hasProfile);
207
213
  info.Set("hasAlpha", baton->hasAlpha);
208
214
  if (baton->orientation > 0) {
package/src/metadata.h CHANGED
@@ -41,6 +41,7 @@ struct MetadataBaton {
41
41
  int pagePrimary;
42
42
  std::string compression;
43
43
  std::vector<std::pair<int, int>> levels;
44
+ int subifds;
44
45
  bool hasProfile;
45
46
  bool hasAlpha;
46
47
  int orientation;
@@ -68,6 +69,7 @@ struct MetadataBaton {
68
69
  pageHeight(0),
69
70
  loop(-1),
70
71
  pagePrimary(-1),
72
+ subifds(0),
71
73
  hasProfile(false),
72
74
  hasAlpha(false),
73
75
  orientation(0),
package/src/operations.cc CHANGED
@@ -149,8 +149,8 @@ namespace sharp {
149
149
  */
150
150
  VImage Recomb(VImage image, std::unique_ptr<double[]> const &matrix) {
151
151
  double *m = matrix.get();
152
+ image = image.colourspace(VIPS_INTERPRETATION_sRGB);
152
153
  return image
153
- .colourspace(VIPS_INTERPRETATION_sRGB)
154
154
  .recomb(image.bands() == 3
155
155
  ? VImage::new_from_memory(
156
156
  m, 9 * sizeof(double), 3, 3, 1, VIPS_FORMAT_DOUBLE
package/src/pipeline.cc CHANGED
@@ -226,7 +226,8 @@ class PipelineWorker : public Napi::AsyncWorker {
226
226
  if (
227
227
  xshrink == yshrink && xshrink >= 2 * shrink_on_load_factor &&
228
228
  (inputImageType == sharp::ImageType::JPEG || inputImageType == sharp::ImageType::WEBP) &&
229
- baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0
229
+ baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0 &&
230
+ image.width() > 3 && image.height() > 3
230
231
  ) {
231
232
  if (xshrink >= 8 * shrink_on_load_factor) {
232
233
  xfactor = xfactor / 8;
@@ -346,7 +347,7 @@ class PipelineWorker : public Napi::AsyncWorker {
346
347
  bool const shouldModulate = baton->brightness != 1.0 || baton->saturation != 1.0 || baton->hue != 0.0;
347
348
 
348
349
  if (shouldComposite && !sharp::HasAlpha(image)) {
349
- image = sharp::EnsureAlpha(image);
350
+ image = sharp::EnsureAlpha(image, 1);
350
351
  }
351
352
 
352
353
  bool const shouldPremultiplyAlpha = sharp::HasAlpha(image) &&
@@ -562,9 +563,17 @@ class PipelineWorker : public Napi::AsyncWorker {
562
563
  // Use gravity in overlay
563
564
  if (compositeImage.width() <= baton->width) {
564
565
  across = static_cast<int>(ceil(static_cast<double>(image.width()) / compositeImage.width()));
566
+ // Ensure odd number of tiles across when gravity is centre, north or south
567
+ if (composite->gravity == 0 || composite->gravity == 1 || composite->gravity == 3) {
568
+ across |= 1;
569
+ }
565
570
  }
566
571
  if (compositeImage.height() <= baton->height) {
567
572
  down = static_cast<int>(ceil(static_cast<double>(image.height()) / compositeImage.height()));
573
+ // Ensure odd number of tiles down when gravity is centre, east or west
574
+ if (composite->gravity == 0 || composite->gravity == 2 || composite->gravity == 4) {
575
+ down |= 1;
576
+ }
568
577
  }
569
578
  if (across != 0 || down != 0) {
570
579
  int left;
@@ -586,7 +595,7 @@ class PipelineWorker : public Napi::AsyncWorker {
586
595
  // Ensure image to composite is sRGB with premultiplied alpha
587
596
  compositeImage = compositeImage.colourspace(VIPS_INTERPRETATION_sRGB);
588
597
  if (!sharp::HasAlpha(compositeImage)) {
589
- compositeImage = sharp::EnsureAlpha(compositeImage);
598
+ compositeImage = sharp::EnsureAlpha(compositeImage, 1);
590
599
  }
591
600
  if (!composite->premultiplied) compositeImage = compositeImage.premultiply();
592
601
  // Calculate position
@@ -594,8 +603,13 @@ class PipelineWorker : public Napi::AsyncWorker {
594
603
  int top;
595
604
  if (composite->hasOffset) {
596
605
  // Composite image at given offsets
597
- std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
598
- compositeImage.width(), compositeImage.height(), composite->left, composite->top);
606
+ if (composite->tile) {
607
+ std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
608
+ compositeImage.width(), compositeImage.height(), composite->left, composite->top);
609
+ } else {
610
+ left = composite->left;
611
+ top = composite->top;
612
+ }
599
613
  } else {
600
614
  // Composite image with given gravity
601
615
  std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
@@ -678,8 +692,8 @@ class PipelineWorker : public Napi::AsyncWorker {
678
692
  }
679
693
 
680
694
  // Ensure alpha channel, if missing
681
- if (baton->ensureAlpha) {
682
- image = sharp::EnsureAlpha(image);
695
+ if (baton->ensureAlpha != -1) {
696
+ image = sharp::EnsureAlpha(image, baton->ensureAlpha);
683
697
  }
684
698
 
685
699
  // Convert image to sRGB, if not already
@@ -704,11 +718,21 @@ class PipelineWorker : public Napi::AsyncWorker {
704
718
  ->set("input_profile", "srgb")
705
719
  ->set("intent", VIPS_INTENT_PERCEPTUAL));
706
720
  }
707
-
708
721
  // Override EXIF Orientation tag
709
722
  if (baton->withMetadata && baton->withMetadataOrientation != -1) {
710
723
  image = sharp::SetExifOrientation(image, baton->withMetadataOrientation);
711
724
  }
725
+ // Override pixel density
726
+ if (baton->withMetadataDensity > 0) {
727
+ image = sharp::SetDensity(image, baton->withMetadataDensity);
728
+ }
729
+ // Metadata key/value pairs, e.g. EXIF
730
+ if (!baton->withMetadataStrs.empty()) {
731
+ image = image.copy();
732
+ for (const auto& s : baton->withMetadataStrs) {
733
+ image.set(s.first.data(), s.second.data());
734
+ }
735
+ }
712
736
 
713
737
  // Number of channels used in output image
714
738
  baton->channels = image.bands();
@@ -1038,6 +1062,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1038
1062
  ->set("angle", CalculateAngleRotation(baton->tileAngle))
1039
1063
  ->set("background", baton->tileBackground)
1040
1064
  ->set("centre", baton->tileCentre)
1065
+ ->set("id", const_cast<char*>(baton->tileId.data()))
1041
1066
  ->set("skip_blanks", baton->tileSkipBlanks);
1042
1067
  // libvips chooses a default depth based on layout. Instead of replicating that logic here by
1043
1068
  // not passing anything - libvips will handle choice
@@ -1327,7 +1352,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1327
1352
  baton->affineInterpolator = vips::VInterpolate::new_from_name(sharp::AttrAsStr(options, "affineInterpolator").data());
1328
1353
 
1329
1354
  baton->removeAlpha = sharp::AttrAsBool(options, "removeAlpha");
1330
- baton->ensureAlpha = sharp::AttrAsBool(options, "ensureAlpha");
1355
+ baton->ensureAlpha = sharp::AttrAsDouble(options, "ensureAlpha");
1331
1356
  if (options.Has("boolean")) {
1332
1357
  baton->boolean = sharp::CreateInputDescriptor(options.Get("boolean").As<Napi::Object>());
1333
1358
  baton->booleanOp = sharp::GetBooleanOperation(sharp::AttrAsStr(options, "booleanOp"));
@@ -1364,7 +1389,14 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1364
1389
  baton->fileOut = sharp::AttrAsStr(options, "fileOut");
1365
1390
  baton->withMetadata = sharp::AttrAsBool(options, "withMetadata");
1366
1391
  baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
1392
+ baton->withMetadataDensity = sharp::AttrAsDouble(options, "withMetadataDensity");
1367
1393
  baton->withMetadataIcc = sharp::AttrAsStr(options, "withMetadataIcc");
1394
+ Napi::Object mdStrs = options.Get("withMetadataStrs").As<Napi::Object>();
1395
+ Napi::Array mdStrKeys = mdStrs.GetPropertyNames();
1396
+ for (unsigned int i = 0; i < mdStrKeys.Length(); i++) {
1397
+ std::string k = sharp::AttrAsStr(mdStrKeys, i);
1398
+ baton->withMetadataStrs.insert(std::make_pair(k, sharp::AttrAsStr(mdStrs, k)));
1399
+ }
1368
1400
  // Format-specific
1369
1401
  baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
1370
1402
  baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
@@ -1438,6 +1470,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1438
1470
  vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_DEPTH,
1439
1471
  sharp::AttrAsStr(options, "tileDepth").data()));
1440
1472
  baton->tileCentre = sharp::AttrAsBool(options, "tileCentre");
1473
+ baton->tileId = sharp::AttrAsStr(options, "tileId");
1441
1474
 
1442
1475
  // Force random access for certain operations
1443
1476
  if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
package/src/pipeline.h CHANGED
@@ -18,6 +18,7 @@
18
18
  #include <memory>
19
19
  #include <string>
20
20
  #include <vector>
21
+ #include <unordered_map>
21
22
 
22
23
  #include <napi.h>
23
24
  #include <vips/vips8>
@@ -167,7 +168,9 @@ struct PipelineBaton {
167
168
  std::string err;
168
169
  bool withMetadata;
169
170
  int withMetadataOrientation;
171
+ double withMetadataDensity;
170
172
  std::string withMetadataIcc;
173
+ std::unordered_map<std::string, std::string> withMetadataStrs;
171
174
  std::unique_ptr<double[]> convKernel;
172
175
  int convKernelWidth;
173
176
  int convKernelHeight;
@@ -178,7 +181,7 @@ struct PipelineBaton {
178
181
  VipsOperationBoolean bandBoolOp;
179
182
  int extractChannel;
180
183
  bool removeAlpha;
181
- bool ensureAlpha;
184
+ double ensureAlpha;
182
185
  VipsInterpretation colourspace;
183
186
  int pageHeight;
184
187
  std::vector<int> delay;
@@ -192,6 +195,7 @@ struct PipelineBaton {
192
195
  std::vector<double> tileBackground;
193
196
  int tileSkipBlanks;
194
197
  VipsForeignDzDepth tileDepth;
198
+ std::string tileId;
195
199
  std::unique_ptr<double[]> recombMatrix;
196
200
 
197
201
  PipelineBaton():
@@ -258,7 +262,7 @@ struct PipelineBaton {
258
262
  jpegOptimiseScans(false),
259
263
  jpegOptimiseCoding(true),
260
264
  pngProgressive(false),
261
- pngCompressionLevel(9),
265
+ pngCompressionLevel(6),
262
266
  pngAdaptiveFiltering(false),
263
267
  pngPalette(false),
264
268
  pngQuality(100),
@@ -287,6 +291,7 @@ struct PipelineBaton {
287
291
  heifLossless(false),
288
292
  withMetadata(false),
289
293
  withMetadataOrientation(-1),
294
+ withMetadataDensity(0.0),
290
295
  convKernelWidth(0),
291
296
  convKernelHeight(0),
292
297
  convKernelScale(0.0),
@@ -296,7 +301,7 @@ struct PipelineBaton {
296
301
  bandBoolOp(VIPS_OPERATION_BOOLEAN_LAST),
297
302
  extractChannel(-1),
298
303
  removeAlpha(false),
299
- ensureAlpha(false),
304
+ ensureAlpha(-1.0),
300
305
  colourspace(VIPS_INTERPRETATION_LAST),
301
306
  pageHeight(0),
302
307
  delay{-1},
package/src/sharp.cc CHANGED
@@ -44,6 +44,7 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
44
44
  exports.Set("libvipsVersion", Napi::Function::New(env, libvipsVersion));
45
45
  exports.Set("format", Napi::Function::New(env, format));
46
46
  exports.Set("_maxColourDistance", Napi::Function::New(env, _maxColourDistance));
47
+ exports.Set("_isUsingJemalloc", Napi::Function::New(env, _isUsingJemalloc));
47
48
  exports.Set("stats", Napi::Function::New(env, stats));
48
49
  return exports;
49
50
  }
package/src/utilities.cc CHANGED
@@ -225,3 +225,19 @@ Napi::Value _maxColourDistance(const Napi::CallbackInfo& info) {
225
225
 
226
226
  return Napi::Number::New(env, maxColourDistance);
227
227
  }
228
+
229
+ #if defined(__GNUC__)
230
+ // mallctl will be resolved by the runtime linker when jemalloc is being used
231
+ extern "C" {
232
+ int mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) __attribute__((weak));
233
+ }
234
+ Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
235
+ Napi::Env env = info.Env();
236
+ return Napi::Boolean::New(env, mallctl != nullptr);
237
+ }
238
+ #else
239
+ Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
240
+ Napi::Env env = info.Env();
241
+ return Napi::Boolean::New(env, false);
242
+ }
243
+ #endif
package/src/utilities.h CHANGED
@@ -24,5 +24,6 @@ Napi::Value simd(const Napi::CallbackInfo& info);
24
24
  Napi::Value libvipsVersion(const Napi::CallbackInfo& info);
25
25
  Napi::Value format(const Napi::CallbackInfo& info);
26
26
  Napi::Value _maxColourDistance(const Napi::CallbackInfo& info);
27
+ Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info);
27
28
 
28
29
  #endif // SRC_UTILITIES_H_