sharp 0.26.3 → 0.28.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/src/common.cc CHANGED
@@ -109,7 +109,13 @@ namespace sharp {
109
109
  descriptor->createChannels = AttrAsUint32(input, "createChannels");
110
110
  descriptor->createWidth = AttrAsUint32(input, "createWidth");
111
111
  descriptor->createHeight = AttrAsUint32(input, "createHeight");
112
- descriptor->createBackground = AttrAsVectorOfDouble(input, "createBackground");
112
+ if (HasAttr(input, "createNoiseType")) {
113
+ descriptor->createNoiseType = AttrAsStr(input, "createNoiseType");
114
+ descriptor->createNoiseMean = AttrAsDouble(input, "createNoiseMean");
115
+ descriptor->createNoiseSigma = AttrAsDouble(input, "createNoiseSigma");
116
+ } else {
117
+ descriptor->createBackground = AttrAsVectorOfDouble(input, "createBackground");
118
+ }
113
119
  }
114
120
  // Limit input images to a given number of pixels, where pixels = width * height
115
121
  descriptor->limitInputPixels = AttrAsUint32(input, "limitInputPixels");
@@ -189,31 +195,40 @@ namespace sharp {
189
195
  return id;
190
196
  }
191
197
 
198
+ /**
199
+ * Regenerate this table with something like:
200
+ *
201
+ * $ vips -l foreign | grep -i load | awk '{ print $2, $1; }'
202
+ *
203
+ * Plus a bit of editing.
204
+ */
192
205
  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 }
206
+ { "VipsForeignLoadJpegFile", ImageType::JPEG },
207
+ { "VipsForeignLoadJpegBuffer", ImageType::JPEG },
208
+ { "VipsForeignLoadPngFile", ImageType::PNG },
209
+ { "VipsForeignLoadPngBuffer", ImageType::PNG },
210
+ { "VipsForeignLoadWebpFile", ImageType::WEBP },
211
+ { "VipsForeignLoadWebpBuffer", ImageType::WEBP },
212
+ { "VipsForeignLoadTiffFile", ImageType::TIFF },
213
+ { "VipsForeignLoadTiffBuffer", ImageType::TIFF },
214
+ { "VipsForeignLoadGifFile", ImageType::GIF },
215
+ { "VipsForeignLoadGifBuffer", ImageType::GIF },
216
+ { "VipsForeignLoadNsgifFile", ImageType::GIF },
217
+ { "VipsForeignLoadNsgifBuffer", ImageType::GIF },
218
+ { "VipsForeignLoadSvgFile", ImageType::SVG },
219
+ { "VipsForeignLoadSvgBuffer", ImageType::SVG },
220
+ { "VipsForeignLoadHeifFile", ImageType::HEIF },
221
+ { "VipsForeignLoadHeifBuffer", ImageType::HEIF },
222
+ { "VipsForeignLoadPdfFile", ImageType::PDF },
223
+ { "VipsForeignLoadPdfBuffer", ImageType::PDF },
224
+ { "VipsForeignLoadMagickFile", ImageType::MAGICK },
225
+ { "VipsForeignLoadMagickBuffer", ImageType::MAGICK },
226
+ { "VipsForeignLoadOpenslide", ImageType::OPENSLIDE },
227
+ { "VipsForeignLoadPpmFile", ImageType::PPM },
228
+ { "VipsForeignLoadFits", ImageType::FITS },
229
+ { "VipsForeignLoadOpenexr", ImageType::EXR },
230
+ { "VipsForeignLoadVips", ImageType::VIPS },
231
+ { "VipsForeignLoadRaw", ImageType::RAW }
217
232
  };
218
233
 
219
234
  /*
@@ -223,7 +238,7 @@ namespace sharp {
223
238
  ImageType imageType = ImageType::UNKNOWN;
224
239
  char const *load = vips_foreign_find_load_buffer(buffer, length);
225
240
  if (load != nullptr) {
226
- auto it = loaderToType.find(vips_nickname_find(g_type_from_name(load)));
241
+ auto it = loaderToType.find(load);
227
242
  if (it != loaderToType.end()) {
228
243
  imageType = it->second;
229
244
  }
@@ -238,7 +253,7 @@ namespace sharp {
238
253
  ImageType imageType = ImageType::UNKNOWN;
239
254
  char const *load = vips_foreign_find_load(file);
240
255
  if (load != nullptr) {
241
- auto it = loaderToType.find(vips_nickname_find(g_type_from_name(load)));
256
+ auto it = loaderToType.find(load);
242
257
  if (it != loaderToType.end()) {
243
258
  imageType = it->second;
244
259
  }
@@ -318,15 +333,35 @@ namespace sharp {
318
333
  } else {
319
334
  if (descriptor->createChannels > 0) {
320
335
  // Create new image
321
- std::vector<double> background = {
322
- descriptor->createBackground[0],
323
- descriptor->createBackground[1],
324
- descriptor->createBackground[2]
325
- };
326
- if (descriptor->createChannels == 4) {
327
- background.push_back(descriptor->createBackground[3]);
336
+ if (descriptor->createNoiseType == "gaussian") {
337
+ int const channels = descriptor->createChannels;
338
+ image = VImage::new_matrix(descriptor->createWidth, descriptor->createHeight);
339
+ std::vector<VImage> bands = {};
340
+ bands.reserve(channels);
341
+ for (int _band = 0; _band < channels; _band++) {
342
+ bands.push_back(image.gaussnoise(
343
+ descriptor->createWidth,
344
+ descriptor->createHeight,
345
+ VImage::option()->set("mean", descriptor->createNoiseMean)->set("sigma", descriptor->createNoiseSigma)));
346
+ }
347
+ image = image.bandjoin(bands);
348
+ image = image.cast(VipsBandFormat::VIPS_FORMAT_UCHAR);
349
+ if (channels < 3) {
350
+ image = image.colourspace(VIPS_INTERPRETATION_B_W);
351
+ } else {
352
+ image = image.colourspace(VIPS_INTERPRETATION_sRGB);
353
+ }
354
+ } else {
355
+ std::vector<double> background = {
356
+ descriptor->createBackground[0],
357
+ descriptor->createBackground[1],
358
+ descriptor->createBackground[2]
359
+ };
360
+ if (descriptor->createChannels == 4) {
361
+ background.push_back(descriptor->createBackground[3]);
362
+ }
363
+ image = VImage::new_matrix(descriptor->createWidth, descriptor->createHeight).new_from_image(background);
328
364
  }
329
- image = VImage::new_matrix(descriptor->createWidth, descriptor->createHeight).new_from_image(background);
330
365
  image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
331
366
  imageType = ImageType::RAW;
332
367
  } else {
@@ -388,12 +423,7 @@ namespace sharp {
388
423
  Uses colour space interpretation with number of channels to guess this.
389
424
  */
390
425
  bool HasAlpha(VImage image) {
391
- int const bands = image.bands();
392
- VipsInterpretation const interpretation = image.interpretation();
393
- return (
394
- (bands == 2 && interpretation == VIPS_INTERPRETATION_B_W) ||
395
- (bands == 4 && interpretation != VIPS_INTERPRETATION_CMYK) ||
396
- (bands == 5 && interpretation == VIPS_INTERPRETATION_CMYK));
426
+ return image.has_alpha();
397
427
  }
398
428
 
399
429
  /*
@@ -658,26 +688,18 @@ namespace sharp {
658
688
  int top = 0;
659
689
 
660
690
  // assign only if valid
661
- if (x >= 0 && x < (inWidth - outWidth)) {
691
+ if (x < (inWidth - outWidth)) {
662
692
  left = x;
663
693
  } else if (x >= (inWidth - outWidth)) {
664
694
  left = inWidth - outWidth;
665
695
  }
666
696
 
667
- if (y >= 0 && y < (inHeight - outHeight)) {
697
+ if (y < (inHeight - outHeight)) {
668
698
  top = y;
669
699
  } else if (y >= (inHeight - outHeight)) {
670
700
  top = inHeight - outHeight;
671
701
  }
672
702
 
673
- // the resulting left and top could have been outside the image after calculation from bottom/right edges
674
- if (left < 0) {
675
- left = 0;
676
- }
677
- if (top < 0) {
678
- top = 0;
679
- }
680
-
681
703
  return std::make_tuple(left, top);
682
704
  }
683
705
 
package/src/common.h CHANGED
@@ -24,8 +24,10 @@
24
24
 
25
25
  // Verify platform and compiler compatibility
26
26
 
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"
27
+ #if (VIPS_MAJOR_VERSION < 8) || \
28
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 10) || \
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"
29
31
  #endif
30
32
 
31
33
  #if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
@@ -62,6 +64,9 @@ namespace sharp {
62
64
  int createWidth;
63
65
  int createHeight;
64
66
  std::vector<double> createBackground;
67
+ std::string createNoiseType;
68
+ double createNoiseMean;
69
+ double createNoiseSigma;
65
70
 
66
71
  InputDescriptor():
67
72
  buffer(nullptr),
@@ -80,7 +85,9 @@ namespace sharp {
80
85
  createChannels(0),
81
86
  createWidth(0),
82
87
  createHeight(0),
83
- createBackground{ 0.0, 0.0, 0.0, 255.0 } {}
88
+ createBackground{ 0.0, 0.0, 0.0, 255.0 },
89
+ createNoiseMean(0.0),
90
+ createNoiseSigma(0.0) {}
84
91
  };
85
92
 
86
93
  // Convenience methods to access the attributes of a Napi::Object
package/src/metadata.cc CHANGED
@@ -74,6 +74,9 @@ class MetadataWorker : public Napi::AsyncWorker {
74
74
  if (image.get_typeof("heif-primary") == G_TYPE_INT) {
75
75
  baton->pagePrimary = image.get_int("heif-primary");
76
76
  }
77
+ if (image.get_typeof("heif-compression") == VIPS_TYPE_REF_STRING) {
78
+ baton->compression = image.get_string("heif-compression");
79
+ }
77
80
  if (image.get_typeof("openslide.level-count") == VIPS_TYPE_REF_STRING) {
78
81
  int const levels = std::stoi(image.get_string("openslide.level-count"));
79
82
  for (int l = 0; l < levels; l++) {
@@ -186,6 +189,9 @@ class MetadataWorker : public Napi::AsyncWorker {
186
189
  if (baton->pagePrimary > -1) {
187
190
  info.Set("pagePrimary", baton->pagePrimary);
188
191
  }
192
+ if (!baton->compression.empty()) {
193
+ info.Set("compression", baton->compression);
194
+ }
189
195
  if (!baton->levels.empty()) {
190
196
  int i = 0;
191
197
  Napi::Array levels = Napi::Array::New(env, static_cast<size_t>(baton->levels.size()));
package/src/metadata.h CHANGED
@@ -39,6 +39,7 @@ struct MetadataBaton {
39
39
  int loop;
40
40
  std::vector<int> delay;
41
41
  int pagePrimary;
42
+ std::string compression;
42
43
  std::vector<std::pair<int, int>> levels;
43
44
  bool hasProfile;
44
45
  bool hasAlpha;
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
@@ -562,15 +562,23 @@ class PipelineWorker : public Napi::AsyncWorker {
562
562
  // Use gravity in overlay
563
563
  if (compositeImage.width() <= baton->width) {
564
564
  across = static_cast<int>(ceil(static_cast<double>(image.width()) / compositeImage.width()));
565
+ // Ensure odd number of tiles across when gravity is centre, north or south
566
+ if (composite->gravity == 0 || composite->gravity == 1 || composite->gravity == 3) {
567
+ across |= 1;
568
+ }
565
569
  }
566
570
  if (compositeImage.height() <= baton->height) {
567
571
  down = static_cast<int>(ceil(static_cast<double>(image.height()) / compositeImage.height()));
572
+ // Ensure odd number of tiles down when gravity is centre, east or west
573
+ if (composite->gravity == 0 || composite->gravity == 2 || composite->gravity == 4) {
574
+ down |= 1;
575
+ }
568
576
  }
569
577
  if (across != 0 || down != 0) {
570
578
  int left;
571
579
  int top;
572
580
  compositeImage = compositeImage.replicate(across, down);
573
- if (composite->left >= 0 && composite->top >= 0) {
581
+ if (composite->hasOffset) {
574
582
  std::tie(left, top) = sharp::CalculateCrop(
575
583
  compositeImage.width(), compositeImage.height(), image.width(), image.height(),
576
584
  composite->left, composite->top);
@@ -592,10 +600,15 @@ class PipelineWorker : public Napi::AsyncWorker {
592
600
  // Calculate position
593
601
  int left;
594
602
  int top;
595
- if (composite->left >= 0 && composite->top >= 0) {
603
+ if (composite->hasOffset) {
596
604
  // 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);
605
+ if (composite->tile) {
606
+ std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
607
+ compositeImage.width(), compositeImage.height(), composite->left, composite->top);
608
+ } else {
609
+ left = composite->left;
610
+ top = composite->top;
611
+ }
599
612
  } else {
600
613
  // Composite image with given gravity
601
614
  std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
@@ -730,7 +743,7 @@ class PipelineWorker : public Napi::AsyncWorker {
730
743
  if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == sharp::ImageType::JPEG)) {
731
744
  // Write JPEG to buffer
732
745
  sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
733
- VipsArea *area = VIPS_AREA(image.jpegsave_buffer(VImage::option()
746
+ VipsArea *area = reinterpret_cast<VipsArea*>(image.jpegsave_buffer(VImage::option()
734
747
  ->set("strip", !baton->withMetadata)
735
748
  ->set("Q", baton->jpegQuality)
736
749
  ->set("interlace", baton->jpegProgressive)
@@ -757,7 +770,7 @@ class PipelineWorker : public Napi::AsyncWorker {
757
770
  inputImageType == sharp::ImageType::SVG))) {
758
771
  // Write PNG to buffer
759
772
  sharp::AssertImageTypeDimensions(image, sharp::ImageType::PNG);
760
- VipsArea *area = VIPS_AREA(image.pngsave_buffer(VImage::option()
773
+ VipsArea *area = reinterpret_cast<VipsArea*>(image.pngsave_buffer(VImage::option()
761
774
  ->set("strip", !baton->withMetadata)
762
775
  ->set("interlace", baton->pngProgressive)
763
776
  ->set("compression", baton->pngCompressionLevel)
@@ -775,7 +788,7 @@ class PipelineWorker : public Napi::AsyncWorker {
775
788
  (baton->formatOut == "input" && inputImageType == sharp::ImageType::WEBP)) {
776
789
  // Write WEBP to buffer
777
790
  sharp::AssertImageTypeDimensions(image, sharp::ImageType::WEBP);
778
- VipsArea *area = VIPS_AREA(image.webpsave_buffer(VImage::option()
791
+ VipsArea *area = reinterpret_cast<VipsArea*>(image.webpsave_buffer(VImage::option()
779
792
  ->set("strip", !baton->withMetadata)
780
793
  ->set("Q", baton->webpQuality)
781
794
  ->set("lossless", baton->webpLossless)
@@ -792,7 +805,7 @@ class PipelineWorker : public Napi::AsyncWorker {
792
805
  (baton->formatOut == "input" && inputImageType == sharp::ImageType::GIF && supportsGifOutput)) {
793
806
  // Write GIF to buffer
794
807
  sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
795
- VipsArea *area = VIPS_AREA(image.magicksave_buffer(VImage::option()
808
+ VipsArea *area = reinterpret_cast<VipsArea*>(image.magicksave_buffer(VImage::option()
796
809
  ->set("strip", !baton->withMetadata)
797
810
  ->set("optimize_gif_frames", TRUE)
798
811
  ->set("optimize_gif_transparency", TRUE)
@@ -813,7 +826,7 @@ class PipelineWorker : public Napi::AsyncWorker {
813
826
  if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) {
814
827
  image = image.cast(VIPS_FORMAT_FLOAT);
815
828
  }
816
- VipsArea *area = VIPS_AREA(image.tiffsave_buffer(VImage::option()
829
+ VipsArea *area = reinterpret_cast<VipsArea*>(image.tiffsave_buffer(VImage::option()
817
830
  ->set("strip", !baton->withMetadata)
818
831
  ->set("Q", baton->tiffQuality)
819
832
  ->set("bitdepth", baton->tiffBitdepth)
@@ -833,10 +846,15 @@ class PipelineWorker : public Napi::AsyncWorker {
833
846
  } else if (baton->formatOut == "heif" ||
834
847
  (baton->formatOut == "input" && inputImageType == sharp::ImageType::HEIF)) {
835
848
  // Write HEIF to buffer
836
- VipsArea *area = VIPS_AREA(image.heifsave_buffer(VImage::option()
849
+ VipsArea *area = reinterpret_cast<VipsArea*>(image.heifsave_buffer(VImage::option()
837
850
  ->set("strip", !baton->withMetadata)
838
851
  ->set("compression", baton->heifCompression)
839
852
  ->set("Q", baton->heifQuality)
853
+ ->set("speed", baton->heifSpeed)
854
+ #if defined(VIPS_TYPE_FOREIGN_SUBSAMPLE)
855
+ ->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
856
+ ? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
857
+ #endif
840
858
  ->set("lossless", baton->heifLossless)));
841
859
  baton->bufferOut = static_cast<char*>(area->data);
842
860
  baton->bufferOutLength = area->length;
@@ -885,7 +903,7 @@ class PipelineWorker : public Napi::AsyncWorker {
885
903
  bool const isV = sharp::IsV(baton->fileOut);
886
904
  bool const mightMatchInput = baton->formatOut == "input";
887
905
  bool const willMatchInput = mightMatchInput &&
888
- !(isJpeg || isPng || isWebp || isGif || isTiff || isDz || isDzZip || isV);
906
+ !(isJpeg || isPng || isWebp || isGif || isTiff || isHeif || isDz || isDzZip || isV);
889
907
 
890
908
  if (baton->formatOut == "jpeg" || (mightMatchInput && isJpeg) ||
891
909
  (willMatchInput && inputImageType == sharp::ImageType::JPEG)) {
@@ -950,6 +968,10 @@ class PipelineWorker : public Napi::AsyncWorker {
950
968
  sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
951
969
  baton->channels = std::min(baton->channels, 3);
952
970
  }
971
+ // Cast pixel values to float, if required
972
+ if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) {
973
+ image = image.cast(VIPS_FORMAT_FLOAT);
974
+ }
953
975
  image.tiffsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
954
976
  ->set("strip", !baton->withMetadata)
955
977
  ->set("Q", baton->tiffQuality)
@@ -966,13 +988,15 @@ class PipelineWorker : public Napi::AsyncWorker {
966
988
  } else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) ||
967
989
  (willMatchInput && inputImageType == sharp::ImageType::HEIF)) {
968
990
  // Write HEIF to file
969
- if (sharp::IsAvif(baton->fileOut)) {
970
- baton->heifCompression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1;
971
- }
972
991
  image.heifsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
973
992
  ->set("strip", !baton->withMetadata)
974
993
  ->set("Q", baton->heifQuality)
975
994
  ->set("compression", baton->heifCompression)
995
+ ->set("speed", baton->heifSpeed)
996
+ #if defined(VIPS_TYPE_FOREIGN_SUBSAMPLE)
997
+ ->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
998
+ ? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
999
+ #endif
976
1000
  ->set("lossless", baton->heifLossless));
977
1001
  baton->formatOut = "heif";
978
1002
  } else if (baton->formatOut == "dz" || isDz || isDzZip) {
@@ -1027,6 +1051,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1027
1051
  ->set("angle", CalculateAngleRotation(baton->tileAngle))
1028
1052
  ->set("background", baton->tileBackground)
1029
1053
  ->set("centre", baton->tileCentre)
1054
+ ->set("id", const_cast<char*>(baton->tileId.data()))
1030
1055
  ->set("skip_blanks", baton->tileSkipBlanks);
1031
1056
  // libvips chooses a default depth based on layout. Instead of replicating that logic here by
1032
1057
  // not passing anything - libvips will handle choice
@@ -1254,6 +1279,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1254
1279
  composite->gravity = sharp::AttrAsUint32(compositeObject, "gravity");
1255
1280
  composite->left = sharp::AttrAsInt32(compositeObject, "left");
1256
1281
  composite->top = sharp::AttrAsInt32(compositeObject, "top");
1282
+ composite->hasOffset = sharp::AttrAsBool(compositeObject, "hasOffset");
1257
1283
  composite->tile = sharp::AttrAsBool(compositeObject, "tile");
1258
1284
  composite->premultiplied = sharp::AttrAsBool(compositeObject, "premultiplied");
1259
1285
  baton->composite.push_back(composite);
@@ -1395,6 +1421,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1395
1421
  baton->heifCompression = static_cast<VipsForeignHeifCompression>(
1396
1422
  vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_HEIF_COMPRESSION,
1397
1423
  sharp::AttrAsStr(options, "heifCompression").data()));
1424
+ baton->heifSpeed = sharp::AttrAsUint32(options, "heifSpeed");
1425
+ baton->heifChromaSubsampling = sharp::AttrAsStr(options, "heifChromaSubsampling");
1398
1426
 
1399
1427
  // Animated output
1400
1428
  if (sharp::HasAttr(options, "pageHeight")) {
@@ -1424,6 +1452,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1424
1452
  vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_DEPTH,
1425
1453
  sharp::AttrAsStr(options, "tileDepth").data()));
1426
1454
  baton->tileCentre = sharp::AttrAsBool(options, "tileCentre");
1455
+ baton->tileId = sharp::AttrAsStr(options, "tileId");
1427
1456
 
1428
1457
  // Force random access for certain operations
1429
1458
  if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
package/src/pipeline.h CHANGED
@@ -40,6 +40,7 @@ struct Composite {
40
40
  int gravity;
41
41
  int left;
42
42
  int top;
43
+ bool hasOffset;
43
44
  bool tile;
44
45
  bool premultiplied;
45
46
 
@@ -47,8 +48,9 @@ struct Composite {
47
48
  input(nullptr),
48
49
  mode(VIPS_BLEND_MODE_OVER),
49
50
  gravity(0),
50
- left(-1),
51
- top(-1),
51
+ left(0),
52
+ top(0),
53
+ hasOffset(false),
52
54
  tile(false),
53
55
  premultiplied(false) {}
54
56
  };
@@ -159,6 +161,8 @@ struct PipelineBaton {
159
161
  double tiffYres;
160
162
  int heifQuality;
161
163
  VipsForeignHeifCompression heifCompression;
164
+ int heifSpeed;
165
+ std::string heifChromaSubsampling;
162
166
  bool heifLossless;
163
167
  std::string err;
164
168
  bool withMetadata;
@@ -188,6 +192,7 @@ struct PipelineBaton {
188
192
  std::vector<double> tileBackground;
189
193
  int tileSkipBlanks;
190
194
  VipsForeignDzDepth tileDepth;
195
+ std::string tileId;
191
196
  std::unique_ptr<double[]> recombMatrix;
192
197
 
193
198
  PipelineBaton():
@@ -254,7 +259,7 @@ struct PipelineBaton {
254
259
  jpegOptimiseScans(false),
255
260
  jpegOptimiseCoding(true),
256
261
  pngProgressive(false),
257
- pngCompressionLevel(9),
262
+ pngCompressionLevel(6),
258
263
  pngAdaptiveFiltering(false),
259
264
  pngPalette(false),
260
265
  pngQuality(100),
@@ -276,8 +281,10 @@ struct PipelineBaton {
276
281
  tiffTileWidth(256),
277
282
  tiffXres(1.0),
278
283
  tiffYres(1.0),
279
- heifQuality(80),
280
- heifCompression(VIPS_FOREIGN_HEIF_COMPRESSION_HEVC),
284
+ heifQuality(50),
285
+ heifCompression(VIPS_FOREIGN_HEIF_COMPRESSION_AV1),
286
+ heifSpeed(5),
287
+ heifChromaSubsampling("4:2:0"),
281
288
  heifLossless(false),
282
289
  withMetadata(false),
283
290
  withMetadataOrientation(-1),
package/src/sharp.cc CHANGED
@@ -22,6 +22,7 @@
22
22
  #include "stats.h"
23
23
 
24
24
  static void* sharp_vips_init(void*) {
25
+ g_setenv("VIPS_MIN_STACK_SIZE", "2m", FALSE);
25
26
  vips_init("sharp");
26
27
  return nullptr;
27
28
  }
@@ -43,6 +44,7 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
43
44
  exports.Set("libvipsVersion", Napi::Function::New(env, libvipsVersion));
44
45
  exports.Set("format", Napi::Function::New(env, format));
45
46
  exports.Set("_maxColourDistance", Napi::Function::New(env, _maxColourDistance));
47
+ exports.Set("_isUsingJemalloc", Napi::Function::New(env, _isUsingJemalloc));
46
48
  exports.Set("stats", Napi::Function::New(env, stats));
47
49
  return exports;
48
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_