sharp 0.27.1 → 0.30.5

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
@@ -36,6 +36,9 @@ namespace sharp {
36
36
  std::string AttrAsStr(Napi::Object obj, std::string attr) {
37
37
  return obj.Get(attr).As<Napi::String>();
38
38
  }
39
+ std::string AttrAsStr(Napi::Object obj, unsigned int const attr) {
40
+ return obj.Get(attr).As<Napi::String>();
41
+ }
39
42
  uint32_t AttrAsUint32(Napi::Object obj, std::string attr) {
40
43
  return obj.Get(attr).As<Napi::Number>().Uint32Value();
41
44
  }
@@ -82,16 +85,22 @@ namespace sharp {
82
85
  descriptor->buffer = buffer.Data();
83
86
  descriptor->isBuffer = TRUE;
84
87
  }
85
- descriptor->failOnError = AttrAsBool(input, "failOnError");
88
+ descriptor->failOn = static_cast<VipsFailOn>(
89
+ vips_enum_from_nick(nullptr, VIPS_TYPE_FAIL_ON,
90
+ AttrAsStr(input, "failOn").data()));
86
91
  // Density for vector-based input
87
92
  if (HasAttr(input, "density")) {
88
93
  descriptor->density = AttrAsDouble(input, "density");
89
94
  }
90
95
  // Raw pixel input
91
96
  if (HasAttr(input, "rawChannels")) {
97
+ descriptor->rawDepth = static_cast<VipsBandFormat>(
98
+ vips_enum_from_nick(nullptr, VIPS_TYPE_BAND_FORMAT,
99
+ AttrAsStr(input, "rawDepth").data()));
92
100
  descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
93
101
  descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
94
102
  descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
103
+ descriptor->rawPremultiplied = AttrAsBool(input, "rawPremultiplied");
95
104
  }
96
105
  // Multi-page input (GIF, TIFF, PDF)
97
106
  if (HasAttr(input, "pages")) {
@@ -104,6 +113,10 @@ namespace sharp {
104
113
  if (HasAttr(input, "level")) {
105
114
  descriptor->level = AttrAsUint32(input, "level");
106
115
  }
116
+ // subIFD (OME-TIFF)
117
+ if (HasAttr(input, "subifd")) {
118
+ descriptor->subifd = AttrAsInt32(input, "subifd");
119
+ }
107
120
  // Create new image
108
121
  if (HasAttr(input, "createChannels")) {
109
122
  descriptor->createChannels = AttrAsUint32(input, "createChannels");
@@ -121,6 +134,8 @@ namespace sharp {
121
134
  descriptor->limitInputPixels = AttrAsUint32(input, "limitInputPixels");
122
135
  // Allow switch from random to sequential access
123
136
  descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
137
+ // Remove safety features and allow unlimited SVG/PNG input
138
+ descriptor->unlimited = AttrAsBool(input, "unlimited");
124
139
  return descriptor;
125
140
  }
126
141
 
@@ -146,6 +161,10 @@ namespace sharp {
146
161
  bool IsGif(std::string const &str) {
147
162
  return EndsWith(str, ".gif") || EndsWith(str, ".GIF");
148
163
  }
164
+ bool IsJp2(std::string const &str) {
165
+ return EndsWith(str, ".jp2") || EndsWith(str, ".jpx") || EndsWith(str, ".j2k") || EndsWith(str, ".j2c")
166
+ || EndsWith(str, ".JP2") || EndsWith(str, ".JPX") || EndsWith(str, ".J2K") || EndsWith(str, ".J2C");
167
+ }
149
168
  bool IsTiff(std::string const &str) {
150
169
  return EndsWith(str, ".tif") || EndsWith(str, ".tiff") || EndsWith(str, ".TIF") || EndsWith(str, ".TIFF");
151
170
  }
@@ -179,6 +198,7 @@ namespace sharp {
179
198
  case ImageType::WEBP: id = "webp"; break;
180
199
  case ImageType::TIFF: id = "tiff"; break;
181
200
  case ImageType::GIF: id = "gif"; break;
201
+ case ImageType::JP2: id = "jp2"; break;
182
202
  case ImageType::SVG: id = "svg"; break;
183
203
  case ImageType::HEIF: id = "heif"; break;
184
204
  case ImageType::PDF: id = "pdf"; break;
@@ -213,6 +233,10 @@ namespace sharp {
213
233
  { "VipsForeignLoadTiffBuffer", ImageType::TIFF },
214
234
  { "VipsForeignLoadGifFile", ImageType::GIF },
215
235
  { "VipsForeignLoadGifBuffer", ImageType::GIF },
236
+ { "VipsForeignLoadNsgifFile", ImageType::GIF },
237
+ { "VipsForeignLoadNsgifBuffer", ImageType::GIF },
238
+ { "VipsForeignLoadJp2kBuffer", ImageType::JP2 },
239
+ { "VipsForeignLoadJp2kFile", ImageType::JP2 },
216
240
  { "VipsForeignLoadSvgFile", ImageType::SVG },
217
241
  { "VipsForeignLoadSvgBuffer", ImageType::SVG },
218
242
  { "VipsForeignLoadHeifFile", ImageType::HEIF },
@@ -221,11 +245,14 @@ namespace sharp {
221
245
  { "VipsForeignLoadPdfBuffer", ImageType::PDF },
222
246
  { "VipsForeignLoadMagickFile", ImageType::MAGICK },
223
247
  { "VipsForeignLoadMagickBuffer", ImageType::MAGICK },
248
+ { "VipsForeignLoadMagick7File", ImageType::MAGICK },
249
+ { "VipsForeignLoadMagick7Buffer", ImageType::MAGICK },
224
250
  { "VipsForeignLoadOpenslide", ImageType::OPENSLIDE },
225
251
  { "VipsForeignLoadPpmFile", ImageType::PPM },
226
252
  { "VipsForeignLoadFits", ImageType::FITS },
227
253
  { "VipsForeignLoadOpenexr", ImageType::EXR },
228
254
  { "VipsForeignLoadVips", ImageType::VIPS },
255
+ { "VipsForeignLoadVipsFile", ImageType::VIPS },
229
256
  { "VipsForeignLoadRaw", ImageType::RAW }
230
257
  };
231
258
 
@@ -271,6 +298,7 @@ namespace sharp {
271
298
  imageType == ImageType::WEBP ||
272
299
  imageType == ImageType::MAGICK ||
273
300
  imageType == ImageType::GIF ||
301
+ imageType == ImageType::JP2 ||
274
302
  imageType == ImageType::TIFF ||
275
303
  imageType == ImageType::HEIF ||
276
304
  imageType == ImageType::PDF;
@@ -286,12 +314,15 @@ namespace sharp {
286
314
  if (descriptor->rawChannels > 0) {
287
315
  // Raw, uncompressed pixel data
288
316
  image = VImage::new_from_memory(descriptor->buffer, descriptor->bufferLength,
289
- descriptor->rawWidth, descriptor->rawHeight, descriptor->rawChannels, VIPS_FORMAT_UCHAR);
317
+ descriptor->rawWidth, descriptor->rawHeight, descriptor->rawChannels, descriptor->rawDepth);
290
318
  if (descriptor->rawChannels < 3) {
291
319
  image.get_image()->Type = VIPS_INTERPRETATION_B_W;
292
320
  } else {
293
321
  image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
294
322
  }
323
+ if (descriptor->rawPremultiplied) {
324
+ image = image.unpremultiply();
325
+ }
295
326
  imageType = ImageType::RAW;
296
327
  } else {
297
328
  // Compressed data
@@ -300,8 +331,8 @@ namespace sharp {
300
331
  try {
301
332
  vips::VOption *option = VImage::option()
302
333
  ->set("access", descriptor->access)
303
- ->set("fail", descriptor->failOnError);
304
- if (imageType == ImageType::SVG) {
334
+ ->set("fail_on", descriptor->failOn);
335
+ if (descriptor->unlimited && (imageType == ImageType::SVG || imageType == ImageType::PNG)) {
305
336
  option->set("unlimited", TRUE);
306
337
  }
307
338
  if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
@@ -317,6 +348,9 @@ namespace sharp {
317
348
  if (imageType == ImageType::OPENSLIDE) {
318
349
  option->set("level", descriptor->level);
319
350
  }
351
+ if (imageType == ImageType::TIFF) {
352
+ option->set("subifd", descriptor->subifd);
353
+ }
320
354
  image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
321
355
  if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
322
356
  image = SetDensity(image, descriptor->density);
@@ -343,12 +377,6 @@ namespace sharp {
343
377
  VImage::option()->set("mean", descriptor->createNoiseMean)->set("sigma", descriptor->createNoiseSigma)));
344
378
  }
345
379
  image = image.bandjoin(bands);
346
- image = image.cast(VipsBandFormat::VIPS_FORMAT_UCHAR);
347
- if (channels < 3) {
348
- image = image.colourspace(VIPS_INTERPRETATION_B_W);
349
- } else {
350
- image = image.colourspace(VIPS_INTERPRETATION_sRGB);
351
- }
352
380
  } else {
353
381
  std::vector<double> background = {
354
382
  descriptor->createBackground[0],
@@ -360,20 +388,25 @@ namespace sharp {
360
388
  }
361
389
  image = VImage::new_matrix(descriptor->createWidth, descriptor->createHeight).new_from_image(background);
362
390
  }
363
- image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
391
+ image.get_image()->Type = image.guess_interpretation();
392
+ image = image.cast(VIPS_FORMAT_UCHAR);
364
393
  imageType = ImageType::RAW;
365
394
  } else {
366
395
  // From filesystem
367
396
  imageType = DetermineImageType(descriptor->file.data());
368
397
  if (imageType == ImageType::MISSING) {
369
- throw vips::VError("Input file is missing");
398
+ if (descriptor->file.find("<svg") != std::string::npos) {
399
+ throw vips::VError("Input file is missing, did you mean "
400
+ "sharp(Buffer.from('" + descriptor->file.substr(0, 8) + "...')?");
401
+ }
402
+ throw vips::VError("Input file is missing: " + descriptor->file);
370
403
  }
371
404
  if (imageType != ImageType::UNKNOWN) {
372
405
  try {
373
406
  vips::VOption *option = VImage::option()
374
407
  ->set("access", descriptor->access)
375
- ->set("fail", descriptor->failOnError);
376
- if (imageType == ImageType::SVG) {
408
+ ->set("fail_on", descriptor->failOn);
409
+ if (descriptor->unlimited && (imageType == ImageType::SVG || imageType == ImageType::PNG)) {
377
410
  option->set("unlimited", TRUE);
378
411
  }
379
412
  if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
@@ -389,6 +422,9 @@ namespace sharp {
389
422
  if (imageType == ImageType::OPENSLIDE) {
390
423
  option->set("level", descriptor->level);
391
424
  }
425
+ if (imageType == ImageType::TIFF) {
426
+ option->set("subifd", descriptor->subifd);
427
+ }
392
428
  image = VImage::new_from_file(descriptor->file.data(), option);
393
429
  if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
394
430
  image = SetDensity(image, descriptor->density);
@@ -421,12 +457,7 @@ namespace sharp {
421
457
  Uses colour space interpretation with number of channels to guess this.
422
458
  */
423
459
  bool HasAlpha(VImage image) {
424
- int const bands = image.bands();
425
- VipsInterpretation const interpretation = image.interpretation();
426
- return (
427
- (bands == 2 && interpretation == VIPS_INTERPRETATION_B_W) ||
428
- (bands == 4 && interpretation != VIPS_INTERPRETATION_CMYK) ||
429
- (bands == 5 && interpretation == VIPS_INTERPRETATION_CMYK));
460
+ return image.has_alpha();
430
461
  }
431
462
 
432
463
  /*
@@ -460,36 +491,41 @@ namespace sharp {
460
491
 
461
492
  /*
462
493
  Set animation properties if necessary.
463
- Non-provided properties will be loaded from image.
464
494
  */
465
- VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop) {
466
- bool hasDelay = delay.size() != 1 || delay.front() != -1;
495
+ VImage SetAnimationProperties(VImage image, int nPages, int pageHeight, std::vector<int> delay, int loop) {
496
+ bool hasDelay = !delay.empty();
467
497
 
468
- if (pageHeight == 0 && image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT) {
469
- pageHeight = image.get_int(VIPS_META_PAGE_HEIGHT);
470
- }
498
+ // Avoid a copy if none of the animation properties are needed.
499
+ if (nPages == 1 && !hasDelay && loop == -1) return image;
471
500
 
472
- if (!hasDelay && image.get_typeof("delay") == VIPS_TYPE_ARRAY_INT) {
473
- delay = image.get_array_int("delay");
474
- hasDelay = true;
501
+ if (delay.size() == 1) {
502
+ // We have just one delay, repeat that value for all frames.
503
+ delay.insert(delay.end(), nPages - 1, delay[0]);
475
504
  }
476
505
 
477
- if (loop == -1 && image.get_typeof("loop") == G_TYPE_INT) {
478
- loop = image.get_int("loop");
479
- }
480
-
481
- if (pageHeight == 0) return image;
482
-
483
- // It is necessary to create the copy as otherwise, pageHeight will be ignored!
506
+ // Attaching metadata, need to copy the image.
484
507
  VImage copy = image.copy();
485
508
 
486
- copy.set(VIPS_META_PAGE_HEIGHT, pageHeight);
509
+ // Only set page-height if we have more than one page, or this could
510
+ // accidentally turn into an animated image later.
511
+ if (nPages > 1) copy.set(VIPS_META_PAGE_HEIGHT, pageHeight);
487
512
  if (hasDelay) copy.set("delay", delay);
488
513
  if (loop != -1) copy.set("loop", loop);
489
514
 
490
515
  return copy;
491
516
  }
492
517
 
518
+ /*
519
+ Remove animation properties from image.
520
+ */
521
+ VImage RemoveAnimationProperties(VImage image) {
522
+ VImage copy = image.copy();
523
+ copy.remove(VIPS_META_PAGE_HEIGHT);
524
+ copy.remove("delay");
525
+ copy.remove("loop");
526
+ return copy;
527
+ }
528
+
493
529
  /*
494
530
  Does this image have a non-default density?
495
531
  */
@@ -510,12 +546,19 @@ namespace sharp {
510
546
  VImage SetDensity(VImage image, const double density) {
511
547
  const double pixelsPerMm = density / 25.4;
512
548
  VImage copy = image.copy();
513
- copy.set("Xres", pixelsPerMm);
514
- copy.set("Yres", pixelsPerMm);
515
- copy.set(VIPS_META_RESOLUTION_UNIT, "in");
549
+ copy.get_image()->Xres = pixelsPerMm;
550
+ copy.get_image()->Yres = pixelsPerMm;
516
551
  return copy;
517
552
  }
518
553
 
554
+ /*
555
+ Multi-page images can have a page height. Fetch it, and sanity check it.
556
+ If page-height is not set, it defaults to the image height
557
+ */
558
+ int GetPageHeight(VImage image) {
559
+ return vips_image_get_page_height(image.get_image());
560
+ }
561
+
519
562
  /*
520
563
  Check the proposed format supports the current dimensions.
521
564
  */
@@ -572,6 +615,33 @@ namespace sharp {
572
615
  return warning;
573
616
  }
574
617
 
618
+ /*
619
+ Attach an event listener for progress updates, used to detect timeout
620
+ */
621
+ void SetTimeout(VImage image, int const seconds) {
622
+ if (seconds > 0) {
623
+ VipsImage *im = image.get_image();
624
+ if (im->progress_signal == NULL) {
625
+ int *timeout = VIPS_NEW(im, int);
626
+ *timeout = seconds;
627
+ g_signal_connect(im, "eval", G_CALLBACK(VipsProgressCallBack), timeout);
628
+ vips_image_set_progress(im, TRUE);
629
+ }
630
+ }
631
+ }
632
+
633
+ /*
634
+ Event listener for progress updates, used to detect timeout
635
+ */
636
+ void VipsProgressCallBack(VipsImage *im, VipsProgress *progress, int *timeout) {
637
+ // printf("VipsProgressCallBack progress=%d run=%d timeout=%d\n", progress->percent, progress->run, *timeout);
638
+ if (*timeout > 0 && progress->run >= *timeout) {
639
+ vips_image_set_kill(im, TRUE);
640
+ vips_error("timeout", "%d%% complete", progress->percent);
641
+ *timeout = 0;
642
+ }
643
+ }
644
+
575
645
  /*
576
646
  Calculate the (left, top) coordinates of the output image
577
647
  within the input image, applying the given gravity during an embed.
@@ -740,23 +810,27 @@ namespace sharp {
740
810
  /*
741
811
  Convert RGBA value to another colourspace
742
812
  */
743
- std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba, VipsInterpretation const interpretation) {
813
+ std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba,
814
+ VipsInterpretation const interpretation, bool premultiply) {
744
815
  int const bands = static_cast<int>(rgba.size());
745
- if (bands < 3 || interpretation == VIPS_INTERPRETATION_sRGB || interpretation == VIPS_INTERPRETATION_RGB) {
816
+ if (bands < 3) {
746
817
  return rgba;
747
- } else {
748
- VImage pixel = VImage::new_matrix(1, 1);
749
- pixel.set("bands", bands);
750
- pixel = pixel.new_from_image(rgba);
751
- pixel = pixel.colourspace(interpretation, VImage::option()->set("source_space", VIPS_INTERPRETATION_sRGB));
752
- return pixel(0, 0);
753
818
  }
819
+ VImage pixel = VImage::new_matrix(1, 1);
820
+ pixel.set("bands", bands);
821
+ pixel = pixel
822
+ .new_from_image(rgba)
823
+ .colourspace(interpretation, VImage::option()->set("source_space", VIPS_INTERPRETATION_sRGB));
824
+ if (premultiply) {
825
+ pixel = pixel.premultiply();
826
+ }
827
+ return pixel(0, 0);
754
828
  }
755
829
 
756
830
  /*
757
831
  Apply the alpha channel to a given colour
758
832
  */
759
- std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour) {
833
+ std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour, bool premultiply) {
760
834
  // Scale up 8-bit values to match 16-bit input image
761
835
  double const multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0;
762
836
  // Create alphaColour colour
@@ -780,7 +854,7 @@ namespace sharp {
780
854
  alphaColour.push_back(colour[3] * multiplier);
781
855
  }
782
856
  // Ensure alphaColour colour uses correct colourspace
783
- alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation());
857
+ alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation(), premultiply);
784
858
  // Add non-transparent alpha channel, if required
785
859
  if (colour[3] < 255.0 && !HasAlpha(image)) {
786
860
  image = image.bandjoin(
@@ -802,12 +876,88 @@ namespace sharp {
802
876
  /*
803
877
  Ensures alpha channel, if missing.
804
878
  */
805
- VImage EnsureAlpha(VImage image) {
879
+ VImage EnsureAlpha(VImage image, double const value) {
806
880
  if (!HasAlpha(image)) {
807
881
  std::vector<double> alpha;
808
- alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
882
+ alpha.push_back(value * sharp::MaximumImageAlpha(image.interpretation()));
809
883
  image = image.bandjoin_const(alpha);
810
884
  }
811
885
  return image;
812
886
  }
887
+
888
+ std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
889
+ Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction) {
890
+ if (swap) {
891
+ // Swap input width and height when requested.
892
+ std::swap(width, height);
893
+ }
894
+
895
+ double hshrink = 1.0;
896
+ double vshrink = 1.0;
897
+
898
+ if (targetWidth > 0 && targetHeight > 0) {
899
+ // Fixed width and height
900
+ hshrink = static_cast<double>(width) / targetWidth;
901
+ vshrink = static_cast<double>(height) / targetHeight;
902
+
903
+ switch (canvas) {
904
+ case Canvas::CROP:
905
+ case Canvas::MIN:
906
+ if (hshrink < vshrink) {
907
+ vshrink = hshrink;
908
+ } else {
909
+ hshrink = vshrink;
910
+ }
911
+ break;
912
+ case Canvas::EMBED:
913
+ case Canvas::MAX:
914
+ if (hshrink > vshrink) {
915
+ vshrink = hshrink;
916
+ } else {
917
+ hshrink = vshrink;
918
+ }
919
+ break;
920
+ case Canvas::IGNORE_ASPECT:
921
+ if (swap) {
922
+ std::swap(hshrink, vshrink);
923
+ }
924
+ break;
925
+ }
926
+ } else if (targetWidth > 0) {
927
+ // Fixed width
928
+ hshrink = static_cast<double>(width) / targetWidth;
929
+
930
+ if (canvas != Canvas::IGNORE_ASPECT) {
931
+ // Auto height
932
+ vshrink = hshrink;
933
+ }
934
+ } else if (targetHeight > 0) {
935
+ // Fixed height
936
+ vshrink = static_cast<double>(height) / targetHeight;
937
+
938
+ if (canvas != Canvas::IGNORE_ASPECT) {
939
+ // Auto width
940
+ hshrink = vshrink;
941
+ }
942
+ }
943
+
944
+ // We should not reduce or enlarge the output image, if
945
+ // withoutReduction or withoutEnlargement is specified.
946
+ if (withoutReduction) {
947
+ // Equivalent of VIPS_SIZE_UP
948
+ hshrink = std::min(1.0, hshrink);
949
+ vshrink = std::min(1.0, vshrink);
950
+ } else if (withoutEnlargement) {
951
+ // Equivalent of VIPS_SIZE_DOWN
952
+ hshrink = std::max(1.0, hshrink);
953
+ vshrink = std::max(1.0, vshrink);
954
+ }
955
+
956
+ // We don't want to shrink so much that we send an axis to 0
957
+ hshrink = std::min(hshrink, static_cast<double>(width));
958
+ vshrink = std::min(vshrink, static_cast<double>(height));
959
+
960
+ return std::make_pair(hshrink, vshrink);
961
+ }
962
+
813
963
  } // namespace sharp
package/src/common.h CHANGED
@@ -25,9 +25,9 @@
25
25
  // Verify platform and compiler compatibility
26
26
 
27
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 < 5)
30
- #error "libvips version 8.10.5+ is required - please see https://sharp.pixelplumbing.com/install"
28
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 12) || \
29
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 12 && VIPS_MICRO_VERSION < 2)
30
+ #error "libvips version 8.12.2+ 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)))
@@ -48,18 +48,22 @@ namespace sharp {
48
48
  std::string name;
49
49
  std::string file;
50
50
  char *buffer;
51
- bool failOnError;
51
+ VipsFailOn failOn;
52
52
  int limitInputPixels;
53
+ bool unlimited;
53
54
  VipsAccess access;
54
55
  size_t bufferLength;
55
56
  bool isBuffer;
56
57
  double density;
58
+ VipsBandFormat rawDepth;
57
59
  int rawChannels;
58
60
  int rawWidth;
59
61
  int rawHeight;
62
+ bool rawPremultiplied;
60
63
  int pages;
61
64
  int page;
62
65
  int level;
66
+ int subifd;
63
67
  int createChannels;
64
68
  int createWidth;
65
69
  int createHeight;
@@ -70,18 +74,22 @@ namespace sharp {
70
74
 
71
75
  InputDescriptor():
72
76
  buffer(nullptr),
73
- failOnError(TRUE),
77
+ failOn(VIPS_FAIL_ON_WARNING),
74
78
  limitInputPixels(0x3FFF * 0x3FFF),
79
+ unlimited(FALSE),
75
80
  access(VIPS_ACCESS_RANDOM),
76
81
  bufferLength(0),
77
82
  isBuffer(FALSE),
78
83
  density(72.0),
84
+ rawDepth(VIPS_FORMAT_UCHAR),
79
85
  rawChannels(0),
80
86
  rawWidth(0),
81
87
  rawHeight(0),
88
+ rawPremultiplied(false),
82
89
  pages(1),
83
90
  page(0),
84
91
  level(0),
92
+ subifd(-1),
85
93
  createChannels(0),
86
94
  createWidth(0),
87
95
  createHeight(0),
@@ -93,6 +101,7 @@ namespace sharp {
93
101
  // Convenience methods to access the attributes of a Napi::Object
94
102
  bool HasAttr(Napi::Object obj, std::string attr);
95
103
  std::string AttrAsStr(Napi::Object obj, std::string attr);
104
+ std::string AttrAsStr(Napi::Object obj, unsigned int const attr);
96
105
  uint32_t AttrAsUint32(Napi::Object obj, std::string attr);
97
106
  int32_t AttrAsInt32(Napi::Object obj, std::string attr);
98
107
  int32_t AttrAsInt32(Napi::Object obj, unsigned int const attr);
@@ -109,6 +118,7 @@ namespace sharp {
109
118
  JPEG,
110
119
  PNG,
111
120
  WEBP,
121
+ JP2,
112
122
  TIFF,
113
123
  GIF,
114
124
  SVG,
@@ -125,6 +135,14 @@ namespace sharp {
125
135
  MISSING
126
136
  };
127
137
 
138
+ enum class Canvas {
139
+ CROP,
140
+ EMBED,
141
+ MAX,
142
+ MIN,
143
+ IGNORE_ASPECT
144
+ };
145
+
128
146
  // How many tasks are in the queue?
129
147
  extern volatile int counterQueue;
130
148
 
@@ -135,6 +153,7 @@ namespace sharp {
135
153
  bool IsJpeg(std::string const &str);
136
154
  bool IsPng(std::string const &str);
137
155
  bool IsWebp(std::string const &str);
156
+ bool IsJp2(std::string const &str);
138
157
  bool IsGif(std::string const &str);
139
158
  bool IsTiff(std::string const &str);
140
159
  bool IsHeic(std::string const &str);
@@ -197,9 +216,13 @@ namespace sharp {
197
216
 
198
217
  /*
199
218
  Set animation properties if necessary.
200
- Non-provided properties will be loaded from image.
201
219
  */
202
- VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop);
220
+ VImage SetAnimationProperties(VImage image, int nPages, int pageHeight, std::vector<int> delay, int loop);
221
+
222
+ /*
223
+ Remove animation properties from image.
224
+ */
225
+ VImage RemoveAnimationProperties(VImage image);
203
226
 
204
227
  /*
205
228
  Does this image have a non-default density?
@@ -216,6 +239,12 @@ namespace sharp {
216
239
  */
217
240
  VImage SetDensity(VImage image, const double density);
218
241
 
242
+ /*
243
+ Multi-page images can have a page height. Fetch it, and sanity check it.
244
+ If page-height is not set, it defaults to the image height
245
+ */
246
+ int GetPageHeight(VImage image);
247
+
219
248
  /*
220
249
  Check the proposed format supports the current dimensions.
221
250
  */
@@ -236,6 +265,16 @@ namespace sharp {
236
265
  */
237
266
  std::string VipsWarningPop();
238
267
 
268
+ /*
269
+ Attach an event listener for progress updates, used to detect timeout
270
+ */
271
+ void SetTimeout(VImage image, int const timeoutSeconds);
272
+
273
+ /*
274
+ Event listener for progress updates, used to detect timeout
275
+ */
276
+ void VipsProgressCallBack(VipsImage *image, VipsProgress *progress, int *timeoutSeconds);
277
+
239
278
  /*
240
279
  Calculate the (left, top) coordinates of the output image
241
280
  within the input image, applying the given gravity during an embed.
@@ -281,12 +320,13 @@ namespace sharp {
281
320
  /*
282
321
  Convert RGBA value to another colourspace
283
322
  */
284
- std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba, VipsInterpretation const interpretation);
323
+ std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba,
324
+ VipsInterpretation const interpretation, bool premultiply);
285
325
 
286
326
  /*
287
327
  Apply the alpha channel to a given colour
288
328
  */
289
- std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour);
329
+ std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour, bool premultiply);
290
330
 
291
331
  /*
292
332
  Removes alpha channel, if any.
@@ -296,7 +336,16 @@ namespace sharp {
296
336
  /*
297
337
  Ensures alpha channel, if missing.
298
338
  */
299
- VImage EnsureAlpha(VImage image);
339
+ VImage EnsureAlpha(VImage image, double const value);
340
+
341
+ /*
342
+ Calculate the shrink factor, taking into account auto-rotate, the canvas
343
+ mode, and so on. The hshrink/vshrink are the amount to shrink the input
344
+ image axes by in order for the output axes (ie. after rotation) to match
345
+ the required thumbnail width/height and canvas mode.
346
+ */
347
+ std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
348
+ Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction);
300
349
 
301
350
  } // namespace sharp
302
351
 
@@ -110,19 +110,6 @@ VSource::new_from_options( const char *options )
110
110
  return( out );
111
111
  }
112
112
 
113
- VOption *
114
- VOption::set( const char *name, const VSource value )
115
- {
116
- Pair *pair = new Pair( name );
117
-
118
- pair->input = true;
119
- g_value_init( &pair->value, VIPS_TYPE_SOURCE );
120
- g_value_set_object( &pair->value, value.get_source() );
121
- options.push_back( pair );
122
-
123
- return( this );
124
- }
125
-
126
113
  VTarget
127
114
  VTarget::new_to_descriptor( int descriptor )
128
115
  {
@@ -162,17 +149,4 @@ VTarget::new_to_memory()
162
149
  return( out );
163
150
  }
164
151
 
165
- VOption *
166
- VOption::set( const char *name, const VTarget value )
167
- {
168
- Pair *pair = new Pair( name );
169
-
170
- pair->input = true;
171
- g_value_init( &pair->value, VIPS_TYPE_TARGET );
172
- g_value_set_object( &pair->value, value.get_target() );
173
- options.push_back( pair );
174
-
175
- return( this );
176
- }
177
-
178
152
  VIPS_NAMESPACE_END