sharp 0.25.4 → 0.26.3

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.
@@ -1,5 +1,5 @@
1
1
  // bodies for vips operations
2
- // Wed 01 Jan 2020 12:22:12 PM CET
2
+ // Sun 5 Jul 22:36:37 BST 2020
3
3
  // this file is generated automatically, do not edit!
4
4
 
5
5
  VImage VImage::CMC2LCh( VOption *options ) const
@@ -754,6 +754,18 @@ VImage VImage::csvload( const char *filename, VOption *options )
754
754
  return( out );
755
755
  }
756
756
 
757
+ VImage VImage::csvload_source( VSource source, VOption *options )
758
+ {
759
+ VImage out;
760
+
761
+ call( "csvload_source",
762
+ (options ? options : VImage::option())->
763
+ set( "out", &out )->
764
+ set( "source", source ) );
765
+
766
+ return( out );
767
+ }
768
+
757
769
  void VImage::csvsave( const char *filename, VOption *options ) const
758
770
  {
759
771
  call( "csvsave",
@@ -762,6 +774,14 @@ void VImage::csvsave( const char *filename, VOption *options ) const
762
774
  set( "filename", filename ) );
763
775
  }
764
776
 
777
+ void VImage::csvsave_target( VTarget target, VOption *options ) const
778
+ {
779
+ call( "csvsave_target",
780
+ (options ? options : VImage::option())->
781
+ set( "in", *this )->
782
+ set( "target", target ) );
783
+ }
784
+
765
785
  VImage VImage::dE00( VImage right, VOption *options ) const
766
786
  {
767
787
  VImage out;
@@ -1218,6 +1238,18 @@ VImage VImage::gifload_buffer( VipsBlob *buffer, VOption *options )
1218
1238
  return( out );
1219
1239
  }
1220
1240
 
1241
+ VImage VImage::gifload_source( VSource source, VOption *options )
1242
+ {
1243
+ VImage out;
1244
+
1245
+ call( "gifload_source",
1246
+ (options ? options : VImage::option())->
1247
+ set( "out", &out )->
1248
+ set( "source", source ) );
1249
+
1250
+ return( out );
1251
+ }
1252
+
1221
1253
  VImage VImage::globalbalance( VOption *options ) const
1222
1254
  {
1223
1255
  VImage out;
@@ -1297,6 +1329,18 @@ VImage VImage::heifload_buffer( VipsBlob *buffer, VOption *options )
1297
1329
  return( out );
1298
1330
  }
1299
1331
 
1332
+ VImage VImage::heifload_source( VSource source, VOption *options )
1333
+ {
1334
+ VImage out;
1335
+
1336
+ call( "heifload_source",
1337
+ (options ? options : VImage::option())->
1338
+ set( "out", &out )->
1339
+ set( "source", source ) );
1340
+
1341
+ return( out );
1342
+ }
1343
+
1300
1344
  void VImage::heifsave( const char *filename, VOption *options ) const
1301
1345
  {
1302
1346
  call( "heifsave",
@@ -1317,6 +1361,14 @@ VipsBlob *VImage::heifsave_buffer( VOption *options ) const
1317
1361
  return( buffer );
1318
1362
  }
1319
1363
 
1364
+ void VImage::heifsave_target( VTarget target, VOption *options ) const
1365
+ {
1366
+ call( "heifsave_target",
1367
+ (options ? options : VImage::option())->
1368
+ set( "in", *this )->
1369
+ set( "target", target ) );
1370
+ }
1371
+
1320
1372
  VImage VImage::hist_cum( VOption *options ) const
1321
1373
  {
1322
1374
  VImage out;
@@ -2028,6 +2080,18 @@ VImage VImage::matload( const char *filename, VOption *options )
2028
2080
  return( out );
2029
2081
  }
2030
2082
 
2083
+ VImage VImage::matrixinvert( VOption *options ) const
2084
+ {
2085
+ VImage out;
2086
+
2087
+ call( "matrixinvert",
2088
+ (options ? options : VImage::option())->
2089
+ set( "in", *this )->
2090
+ set( "out", &out ) );
2091
+
2092
+ return( out );
2093
+ }
2094
+
2031
2095
  VImage VImage::matrixload( const char *filename, VOption *options )
2032
2096
  {
2033
2097
  VImage out;
@@ -2040,6 +2104,18 @@ VImage VImage::matrixload( const char *filename, VOption *options )
2040
2104
  return( out );
2041
2105
  }
2042
2106
 
2107
+ VImage VImage::matrixload_source( VSource source, VOption *options )
2108
+ {
2109
+ VImage out;
2110
+
2111
+ call( "matrixload_source",
2112
+ (options ? options : VImage::option())->
2113
+ set( "out", &out )->
2114
+ set( "source", source ) );
2115
+
2116
+ return( out );
2117
+ }
2118
+
2043
2119
  void VImage::matrixprint( VOption *options ) const
2044
2120
  {
2045
2121
  call( "matrixprint",
@@ -2055,6 +2131,14 @@ void VImage::matrixsave( const char *filename, VOption *options ) const
2055
2131
  set( "filename", filename ) );
2056
2132
  }
2057
2133
 
2134
+ void VImage::matrixsave_target( VTarget target, VOption *options ) const
2135
+ {
2136
+ call( "matrixsave_target",
2137
+ (options ? options : VImage::option())->
2138
+ set( "in", *this )->
2139
+ set( "target", target ) );
2140
+ }
2141
+
2058
2142
  double VImage::max( VOption *options ) const
2059
2143
  {
2060
2144
  double out;
@@ -2256,6 +2340,18 @@ VImage VImage::pdfload_buffer( VipsBlob *buffer, VOption *options )
2256
2340
  return( out );
2257
2341
  }
2258
2342
 
2343
+ VImage VImage::pdfload_source( VSource source, VOption *options )
2344
+ {
2345
+ VImage out;
2346
+
2347
+ call( "pdfload_source",
2348
+ (options ? options : VImage::option())->
2349
+ set( "out", &out )->
2350
+ set( "source", source ) );
2351
+
2352
+ return( out );
2353
+ }
2354
+
2259
2355
  int VImage::percent( double percent, VOption *options ) const
2260
2356
  {
2261
2357
  int threshold;
@@ -2371,6 +2467,18 @@ VImage VImage::ppmload( const char *filename, VOption *options )
2371
2467
  return( out );
2372
2468
  }
2373
2469
 
2470
+ VImage VImage::ppmload_source( VSource source, VOption *options )
2471
+ {
2472
+ VImage out;
2473
+
2474
+ call( "ppmload_source",
2475
+ (options ? options : VImage::option())->
2476
+ set( "out", &out )->
2477
+ set( "source", source ) );
2478
+
2479
+ return( out );
2480
+ }
2481
+
2374
2482
  void VImage::ppmsave( const char *filename, VOption *options ) const
2375
2483
  {
2376
2484
  call( "ppmsave",
@@ -2379,6 +2487,14 @@ void VImage::ppmsave( const char *filename, VOption *options ) const
2379
2487
  set( "filename", filename ) );
2380
2488
  }
2381
2489
 
2490
+ void VImage::ppmsave_target( VTarget target, VOption *options ) const
2491
+ {
2492
+ call( "ppmsave_target",
2493
+ (options ? options : VImage::option())->
2494
+ set( "in", *this )->
2495
+ set( "target", target ) );
2496
+ }
2497
+
2382
2498
  VImage VImage::premultiply( VOption *options ) const
2383
2499
  {
2384
2500
  VImage out;
package/src/metadata.cc CHANGED
@@ -189,7 +189,7 @@ class MetadataWorker : public Napi::AsyncWorker {
189
189
  if (!baton->levels.empty()) {
190
190
  int i = 0;
191
191
  Napi::Array levels = Napi::Array::New(env, static_cast<size_t>(baton->levels.size()));
192
- for (std::pair<int, int> const l : baton->levels) {
192
+ for (std::pair<int, int> const &l : baton->levels) {
193
193
  Napi::Object level = Napi::Object::New(env);
194
194
  level.Set("width", l.first);
195
195
  level.Set("height", l.second);
package/src/operations.cc CHANGED
@@ -27,29 +27,6 @@ using vips::VImage;
27
27
  using vips::VError;
28
28
 
29
29
  namespace sharp {
30
-
31
- /*
32
- Removes alpha channel, if any.
33
- */
34
- VImage RemoveAlpha(VImage image) {
35
- if (HasAlpha(image)) {
36
- image = image.extract_band(0, VImage::option()->set("n", image.bands() - 1));
37
- }
38
- return image;
39
- }
40
-
41
- /*
42
- Ensures alpha channel, if missing.
43
- */
44
- VImage EnsureAlpha(VImage image) {
45
- if (!HasAlpha(image)) {
46
- std::vector<double> alpha;
47
- alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
48
- image = image.bandjoin_const(alpha);
49
- }
50
- return image;
51
- }
52
-
53
30
  /*
54
31
  * Tint an image using the specified chroma, preserving the original image luminance
55
32
  */
package/src/operations.h CHANGED
@@ -25,16 +25,6 @@ using vips::VImage;
25
25
 
26
26
  namespace sharp {
27
27
 
28
- /*
29
- Removes alpha channel, if any.
30
- */
31
- VImage RemoveAlpha(VImage image);
32
-
33
- /*
34
- Ensures alpha channel, if missing.
35
- */
36
- VImage EnsureAlpha(VImage image);
37
-
38
28
  /*
39
29
  * Tint an image using the specified chroma, preserving the original image luminance
40
30
  */
package/src/pipeline.cc CHANGED
@@ -485,6 +485,18 @@ class PipelineWorker : public Napi::AsyncWorker {
485
485
  baton->leftOffsetPost, baton->topOffsetPost, baton->widthPost, baton->heightPost);
486
486
  }
487
487
 
488
+ // Affine transform
489
+ if (baton->affineMatrix.size() > 0) {
490
+ std::vector<double> background;
491
+ std::tie(image, background) = sharp::ApplyAlpha(image, baton->affineBackground);
492
+ image = image.affine(baton->affineMatrix, VImage::option()->set("background", background)
493
+ ->set("idx", baton->affineIdx)
494
+ ->set("idy", baton->affineIdy)
495
+ ->set("odx", baton->affineOdx)
496
+ ->set("ody", baton->affineOdy)
497
+ ->set("interpolate", baton->affineInterpolator));
498
+ }
499
+
488
500
  // Extend edges
489
501
  if (baton->extendTop > 0 || baton->extendBottom > 0 || baton->extendLeft > 0 || baton->extendRight > 0) {
490
502
  std::vector<double> background;
@@ -684,6 +696,15 @@ class PipelineWorker : public Napi::AsyncWorker {
684
696
  }
685
697
  }
686
698
 
699
+ // Apply output ICC profile
700
+ if (!baton->withMetadataIcc.empty()) {
701
+ image = image.icc_transform(
702
+ const_cast<char*>(baton->withMetadataIcc.data()),
703
+ VImage::option()
704
+ ->set("input_profile", "srgb")
705
+ ->set("intent", VIPS_INTENT_PERCEPTUAL));
706
+ }
707
+
687
708
  // Override EXIF Orientation tag
688
709
  if (baton->withMetadata && baton->withMetadataOrientation != -1) {
689
710
  image = sharp::SetExifOrientation(image, baton->withMetadataOrientation);
@@ -693,6 +714,16 @@ class PipelineWorker : public Napi::AsyncWorker {
693
714
  baton->channels = image.bands();
694
715
  baton->width = image.width();
695
716
  baton->height = image.height();
717
+
718
+ bool const supportsGifOutput = vips_type_find("VipsOperation", "magicksave") != 0 &&
719
+ vips_type_find("VipsOperation", "magicksave_buffer") != 0;
720
+
721
+ image = sharp::SetAnimationProperties(
722
+ image,
723
+ baton->pageHeight,
724
+ baton->delay,
725
+ baton->loop);
726
+
696
727
  // Output
697
728
  if (baton->fileOut.empty()) {
698
729
  // Buffer output
@@ -703,7 +734,9 @@ class PipelineWorker : public Napi::AsyncWorker {
703
734
  ->set("strip", !baton->withMetadata)
704
735
  ->set("Q", baton->jpegQuality)
705
736
  ->set("interlace", baton->jpegProgressive)
706
- ->set("no_subsample", baton->jpegChromaSubsampling == "4:4:4")
737
+ ->set("subsample_mode", baton->jpegChromaSubsampling == "4:4:4"
738
+ ? VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF
739
+ : VIPS_FOREIGN_JPEG_SUBSAMPLE_ON)
707
740
  ->set("trellis_quant", baton->jpegTrellisQuantisation)
708
741
  ->set("quant_table", baton->jpegQuantisationTable)
709
742
  ->set("overshoot_deringing", baton->jpegOvershootDeringing)
@@ -720,8 +753,8 @@ class PipelineWorker : public Napi::AsyncWorker {
720
753
  baton->channels = std::min(baton->channels, 3);
721
754
  }
722
755
  } else if (baton->formatOut == "png" || (baton->formatOut == "input" &&
723
- (inputImageType == sharp::ImageType::PNG || inputImageType == sharp::ImageType::GIF ||
724
- inputImageType == sharp::ImageType::SVG))) {
756
+ (inputImageType == sharp::ImageType::PNG || (inputImageType == sharp::ImageType::GIF && !supportsGifOutput) ||
757
+ inputImageType == sharp::ImageType::SVG))) {
725
758
  // Write PNG to buffer
726
759
  sharp::AssertImageTypeDimensions(image, sharp::ImageType::PNG);
727
760
  VipsArea *area = VIPS_AREA(image.pngsave_buffer(VImage::option()
@@ -755,6 +788,20 @@ class PipelineWorker : public Napi::AsyncWorker {
755
788
  area->free_fn = nullptr;
756
789
  vips_area_unref(area);
757
790
  baton->formatOut = "webp";
791
+ } else if (baton->formatOut == "gif" ||
792
+ (baton->formatOut == "input" && inputImageType == sharp::ImageType::GIF && supportsGifOutput)) {
793
+ // Write GIF to buffer
794
+ sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
795
+ VipsArea *area = VIPS_AREA(image.magicksave_buffer(VImage::option()
796
+ ->set("strip", !baton->withMetadata)
797
+ ->set("optimize_gif_frames", TRUE)
798
+ ->set("optimize_gif_transparency", TRUE)
799
+ ->set("format", "gif")));
800
+ baton->bufferOut = static_cast<char*>(area->data);
801
+ baton->bufferOutLength = area->length;
802
+ area->free_fn = nullptr;
803
+ vips_area_unref(area);
804
+ baton->formatOut = "gif";
758
805
  } else if (baton->formatOut == "tiff" ||
759
806
  (baton->formatOut == "input" && inputImageType == sharp::ImageType::TIFF)) {
760
807
  // Write TIFF to buffer
@@ -769,7 +816,7 @@ class PipelineWorker : public Napi::AsyncWorker {
769
816
  VipsArea *area = VIPS_AREA(image.tiffsave_buffer(VImage::option()
770
817
  ->set("strip", !baton->withMetadata)
771
818
  ->set("Q", baton->tiffQuality)
772
- ->set("squash", baton->tiffSquash)
819
+ ->set("bitdepth", baton->tiffBitdepth)
773
820
  ->set("compression", baton->tiffCompression)
774
821
  ->set("predictor", baton->tiffPredictor)
775
822
  ->set("pyramid", baton->tiffPyramid)
@@ -830,13 +877,16 @@ class PipelineWorker : public Napi::AsyncWorker {
830
877
  bool const isJpeg = sharp::IsJpeg(baton->fileOut);
831
878
  bool const isPng = sharp::IsPng(baton->fileOut);
832
879
  bool const isWebp = sharp::IsWebp(baton->fileOut);
880
+ bool const isGif = sharp::IsGif(baton->fileOut);
833
881
  bool const isTiff = sharp::IsTiff(baton->fileOut);
834
882
  bool const isHeif = sharp::IsHeif(baton->fileOut);
835
883
  bool const isDz = sharp::IsDz(baton->fileOut);
836
884
  bool const isDzZip = sharp::IsDzZip(baton->fileOut);
837
885
  bool const isV = sharp::IsV(baton->fileOut);
838
886
  bool const mightMatchInput = baton->formatOut == "input";
839
- bool const willMatchInput = mightMatchInput && !(isJpeg || isPng || isWebp || isTiff || isDz || isDzZip || isV);
887
+ bool const willMatchInput = mightMatchInput &&
888
+ !(isJpeg || isPng || isWebp || isGif || isTiff || isDz || isDzZip || isV);
889
+
840
890
  if (baton->formatOut == "jpeg" || (mightMatchInput && isJpeg) ||
841
891
  (willMatchInput && inputImageType == sharp::ImageType::JPEG)) {
842
892
  // Write JPEG to file
@@ -845,7 +895,9 @@ class PipelineWorker : public Napi::AsyncWorker {
845
895
  ->set("strip", !baton->withMetadata)
846
896
  ->set("Q", baton->jpegQuality)
847
897
  ->set("interlace", baton->jpegProgressive)
848
- ->set("no_subsample", baton->jpegChromaSubsampling == "4:4:4")
898
+ ->set("subsample_mode", baton->jpegChromaSubsampling == "4:4:4"
899
+ ? VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF
900
+ : VIPS_FOREIGN_JPEG_SUBSAMPLE_ON)
849
901
  ->set("trellis_quant", baton->jpegTrellisQuantisation)
850
902
  ->set("quant_table", baton->jpegQuantisationTable)
851
903
  ->set("overshoot_deringing", baton->jpegOvershootDeringing)
@@ -854,8 +906,8 @@ class PipelineWorker : public Napi::AsyncWorker {
854
906
  baton->formatOut = "jpeg";
855
907
  baton->channels = std::min(baton->channels, 3);
856
908
  } else if (baton->formatOut == "png" || (mightMatchInput && isPng) || (willMatchInput &&
857
- (inputImageType == sharp::ImageType::PNG || inputImageType == sharp::ImageType::GIF ||
858
- inputImageType == sharp::ImageType::SVG))) {
909
+ (inputImageType == sharp::ImageType::PNG || (inputImageType == sharp::ImageType::GIF && !supportsGifOutput) ||
910
+ inputImageType == sharp::ImageType::SVG))) {
859
911
  // Write PNG to file
860
912
  sharp::AssertImageTypeDimensions(image, sharp::ImageType::PNG);
861
913
  image.pngsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
@@ -881,6 +933,16 @@ class PipelineWorker : public Napi::AsyncWorker {
881
933
  ->set("reduction_effort", baton->webpReductionEffort)
882
934
  ->set("alpha_q", baton->webpAlphaQuality));
883
935
  baton->formatOut = "webp";
936
+ } else if (baton->formatOut == "gif" || (mightMatchInput && isGif) ||
937
+ (willMatchInput && inputImageType == sharp::ImageType::GIF && supportsGifOutput)) {
938
+ // Write GIF to file
939
+ sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
940
+ image.magicksave(const_cast<char*>(baton->fileOut.data()), VImage::option()
941
+ ->set("strip", !baton->withMetadata)
942
+ ->set("optimize_gif_frames", TRUE)
943
+ ->set("optimize_gif_transparency", TRUE)
944
+ ->set("format", "gif"));
945
+ baton->formatOut = "gif";
884
946
  } else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
885
947
  (willMatchInput && inputImageType == sharp::ImageType::TIFF)) {
886
948
  // Write TIFF to file
@@ -891,7 +953,7 @@ class PipelineWorker : public Napi::AsyncWorker {
891
953
  image.tiffsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
892
954
  ->set("strip", !baton->withMetadata)
893
955
  ->set("Q", baton->tiffQuality)
894
- ->set("squash", baton->tiffSquash)
956
+ ->set("bitdepth", baton->tiffBitdepth)
895
957
  ->set("compression", baton->tiffCompression)
896
958
  ->set("predictor", baton->tiffPredictor)
897
959
  ->set("pyramid", baton->tiffPyramid)
@@ -940,7 +1002,7 @@ class PipelineWorker : public Napi::AsyncWorker {
940
1002
  std::vector<std::pair<std::string, std::string>> options {
941
1003
  {"Q", std::to_string(baton->jpegQuality)},
942
1004
  {"interlace", baton->jpegProgressive ? "TRUE" : "FALSE"},
943
- {"no_subsample", baton->jpegChromaSubsampling == "4:4:4" ? "TRUE": "FALSE"},
1005
+ {"subsample_mode", baton->jpegChromaSubsampling == "4:4:4" ? "off" : "on"},
944
1006
  {"trellis_quant", baton->jpegTrellisQuantisation ? "TRUE" : "FALSE"},
945
1007
  {"quant_table", std::to_string(baton->jpegQuantisationTable)},
946
1008
  {"overshoot_deringing", baton->jpegOvershootDeringing ? "TRUE": "FALSE"},
@@ -964,6 +1026,7 @@ class PipelineWorker : public Napi::AsyncWorker {
964
1026
  ->set("suffix", const_cast<char*>(suffix.data()))
965
1027
  ->set("angle", CalculateAngleRotation(baton->tileAngle))
966
1028
  ->set("background", baton->tileBackground)
1029
+ ->set("centre", baton->tileCentre)
967
1030
  ->set("skip_blanks", baton->tileSkipBlanks);
968
1031
  // libvips chooses a default depth based on layout. Instead of replicating that logic here by
969
1032
  // not passing anything - libvips will handle choice
@@ -1198,7 +1261,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1198
1261
  // Resize options
1199
1262
  baton->withoutEnlargement = sharp::AttrAsBool(options, "withoutEnlargement");
1200
1263
  baton->position = sharp::AttrAsInt32(options, "position");
1201
- baton->resizeBackground = sharp::AttrAsRgba(options, "resizeBackground");
1264
+ baton->resizeBackground = sharp::AttrAsVectorOfDouble(options, "resizeBackground");
1202
1265
  baton->kernel = sharp::AttrAsStr(options, "kernel");
1203
1266
  baton->fastShrinkOnLoad = sharp::AttrAsBool(options, "fastShrinkOnLoad");
1204
1267
  // Join Channel Options
@@ -1211,7 +1274,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1211
1274
  }
1212
1275
  // Operators
1213
1276
  baton->flatten = sharp::AttrAsBool(options, "flatten");
1214
- baton->flattenBackground = sharp::AttrAsRgba(options, "flattenBackground");
1277
+ baton->flattenBackground = sharp::AttrAsVectorOfDouble(options, "flattenBackground");
1215
1278
  baton->negate = sharp::AttrAsBool(options, "negate");
1216
1279
  baton->blurSigma = sharp::AttrAsDouble(options, "blurSigma");
1217
1280
  baton->brightness = sharp::AttrAsDouble(options, "brightness");
@@ -1233,7 +1296,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1233
1296
  baton->useExifOrientation = sharp::AttrAsBool(options, "useExifOrientation");
1234
1297
  baton->angle = sharp::AttrAsInt32(options, "angle");
1235
1298
  baton->rotationAngle = sharp::AttrAsDouble(options, "rotationAngle");
1236
- baton->rotationBackground = sharp::AttrAsRgba(options, "rotationBackground");
1299
+ baton->rotationBackground = sharp::AttrAsVectorOfDouble(options, "rotationBackground");
1237
1300
  baton->rotateBeforePreExtract = sharp::AttrAsBool(options, "rotateBeforePreExtract");
1238
1301
  baton->flip = sharp::AttrAsBool(options, "flip");
1239
1302
  baton->flop = sharp::AttrAsBool(options, "flop");
@@ -1241,8 +1304,15 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1241
1304
  baton->extendBottom = sharp::AttrAsInt32(options, "extendBottom");
1242
1305
  baton->extendLeft = sharp::AttrAsInt32(options, "extendLeft");
1243
1306
  baton->extendRight = sharp::AttrAsInt32(options, "extendRight");
1244
- baton->extendBackground = sharp::AttrAsRgba(options, "extendBackground");
1307
+ baton->extendBackground = sharp::AttrAsVectorOfDouble(options, "extendBackground");
1245
1308
  baton->extractChannel = sharp::AttrAsInt32(options, "extractChannel");
1309
+ baton->affineMatrix = sharp::AttrAsVectorOfDouble(options, "affineMatrix");
1310
+ baton->affineBackground = sharp::AttrAsVectorOfDouble(options, "affineBackground");
1311
+ baton->affineIdx = sharp::AttrAsDouble(options, "affineIdx");
1312
+ baton->affineIdy = sharp::AttrAsDouble(options, "affineIdy");
1313
+ baton->affineOdx = sharp::AttrAsDouble(options, "affineOdx");
1314
+ baton->affineOdy = sharp::AttrAsDouble(options, "affineOdy");
1315
+ baton->affineInterpolator = vips::VInterpolate::new_from_name(sharp::AttrAsStr(options, "affineInterpolator").data());
1246
1316
 
1247
1317
  baton->removeAlpha = sharp::AttrAsBool(options, "removeAlpha");
1248
1318
  baton->ensureAlpha = sharp::AttrAsBool(options, "ensureAlpha");
@@ -1282,6 +1352,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1282
1352
  baton->fileOut = sharp::AttrAsStr(options, "fileOut");
1283
1353
  baton->withMetadata = sharp::AttrAsBool(options, "withMetadata");
1284
1354
  baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
1355
+ baton->withMetadataIcc = sharp::AttrAsStr(options, "withMetadataIcc");
1285
1356
  // Format-specific
1286
1357
  baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
1287
1358
  baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
@@ -1306,7 +1377,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1306
1377
  baton->webpReductionEffort = sharp::AttrAsUint32(options, "webpReductionEffort");
1307
1378
  baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
1308
1379
  baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid");
1309
- baton->tiffSquash = sharp::AttrAsBool(options, "tiffSquash");
1380
+ baton->tiffBitdepth = sharp::AttrAsUint32(options, "tiffBitdepth");
1310
1381
  baton->tiffTile = sharp::AttrAsBool(options, "tiffTile");
1311
1382
  baton->tiffTileWidth = sharp::AttrAsUint32(options, "tiffTileWidth");
1312
1383
  baton->tiffTileHeight = sharp::AttrAsUint32(options, "tiffTileHeight");
@@ -1324,11 +1395,23 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1324
1395
  baton->heifCompression = static_cast<VipsForeignHeifCompression>(
1325
1396
  vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_HEIF_COMPRESSION,
1326
1397
  sharp::AttrAsStr(options, "heifCompression").data()));
1398
+
1399
+ // Animated output
1400
+ if (sharp::HasAttr(options, "pageHeight")) {
1401
+ baton->pageHeight = sharp::AttrAsUint32(options, "pageHeight");
1402
+ }
1403
+ if (sharp::HasAttr(options, "loop")) {
1404
+ baton->loop = sharp::AttrAsUint32(options, "loop");
1405
+ }
1406
+ if (sharp::HasAttr(options, "delay")) {
1407
+ baton->delay = sharp::AttrAsInt32Vector(options, "delay");
1408
+ }
1409
+
1327
1410
  // Tile output
1328
1411
  baton->tileSize = sharp::AttrAsUint32(options, "tileSize");
1329
1412
  baton->tileOverlap = sharp::AttrAsUint32(options, "tileOverlap");
1330
1413
  baton->tileAngle = sharp::AttrAsInt32(options, "tileAngle");
1331
- baton->tileBackground = sharp::AttrAsRgba(options, "tileBackground");
1414
+ baton->tileBackground = sharp::AttrAsVectorOfDouble(options, "tileBackground");
1332
1415
  baton->tileSkipBlanks = sharp::AttrAsInt32(options, "tileSkipBlanks");
1333
1416
  baton->tileContainer = static_cast<VipsForeignDzContainer>(
1334
1417
  vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_CONTAINER,
@@ -1340,6 +1423,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1340
1423
  baton->tileDepth = static_cast<VipsForeignDzDepth>(
1341
1424
  vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_DEPTH,
1342
1425
  sharp::AttrAsStr(options, "tileDepth").data()));
1426
+ baton->tileCentre = sharp::AttrAsBool(options, "tileCentre");
1343
1427
 
1344
1428
  // Force random access for certain operations
1345
1429
  if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
package/src/pipeline.h CHANGED
@@ -79,6 +79,7 @@ struct PipelineBaton {
79
79
  int cropOffsetLeft;
80
80
  int cropOffsetTop;
81
81
  bool premultiplied;
82
+ bool tileCentre;
82
83
  std::string kernel;
83
84
  bool fastShrinkOnLoad;
84
85
  double tintA;
@@ -118,6 +119,13 @@ struct PipelineBaton {
118
119
  int extendRight;
119
120
  std::vector<double> extendBackground;
120
121
  bool withoutEnlargement;
122
+ std::vector<double> affineMatrix;
123
+ std::vector<double> affineBackground;
124
+ double affineIdx;
125
+ double affineIdy;
126
+ double affineOdx;
127
+ double affineOdy;
128
+ vips::VInterpolate affineInterpolator;
121
129
  int jpegQuality;
122
130
  bool jpegProgressive;
123
131
  std::string jpegChromaSubsampling;
@@ -143,7 +151,7 @@ struct PipelineBaton {
143
151
  VipsForeignTiffCompression tiffCompression;
144
152
  VipsForeignTiffPredictor tiffPredictor;
145
153
  bool tiffPyramid;
146
- bool tiffSquash;
154
+ int tiffBitdepth;
147
155
  bool tiffTile;
148
156
  int tiffTileHeight;
149
157
  int tiffTileWidth;
@@ -155,6 +163,7 @@ struct PipelineBaton {
155
163
  std::string err;
156
164
  bool withMetadata;
157
165
  int withMetadataOrientation;
166
+ std::string withMetadataIcc;
158
167
  std::unique_ptr<double[]> convKernel;
159
168
  int convKernelWidth;
160
169
  int convKernelHeight;
@@ -167,6 +176,9 @@ struct PipelineBaton {
167
176
  bool removeAlpha;
168
177
  bool ensureAlpha;
169
178
  VipsInterpretation colourspace;
179
+ int pageHeight;
180
+ std::vector<int> delay;
181
+ int loop;
170
182
  int tileSize;
171
183
  int tileOverlap;
172
184
  VipsForeignDzContainer tileContainer;
@@ -226,6 +238,13 @@ struct PipelineBaton {
226
238
  extendRight(0),
227
239
  extendBackground{ 0.0, 0.0, 0.0, 255.0 },
228
240
  withoutEnlargement(false),
241
+ affineMatrix{ 1.0, 0.0, 0.0, 1.0 },
242
+ affineBackground{ 0.0, 0.0, 0.0, 255.0 },
243
+ affineIdx(0),
244
+ affineIdy(0),
245
+ affineOdx(0),
246
+ affineOdy(0),
247
+ affineInterpolator(vips::VInterpolate::new_from_name("bicubic")),
229
248
  jpegQuality(80),
230
249
  jpegProgressive(false),
231
250
  jpegChromaSubsampling("4:2:0"),
@@ -251,7 +270,7 @@ struct PipelineBaton {
251
270
  tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
252
271
  tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
253
272
  tiffPyramid(false),
254
- tiffSquash(false),
273
+ tiffBitdepth(8),
255
274
  tiffTile(false),
256
275
  tiffTileHeight(256),
257
276
  tiffTileWidth(256),
@@ -273,6 +292,9 @@ struct PipelineBaton {
273
292
  removeAlpha(false),
274
293
  ensureAlpha(false),
275
294
  colourspace(VIPS_INTERPRETATION_LAST),
295
+ pageHeight(0),
296
+ delay{-1},
297
+ loop(-1),
276
298
  tileSize(256),
277
299
  tileOverlap(0),
278
300
  tileContainer(VIPS_FOREIGN_DZ_CONTAINER_FS),
package/src/stats.cc CHANGED
@@ -80,12 +80,26 @@ class StatsWorker : public Napi::AsyncWorker {
80
80
  // Estimate entropy via histogram of greyscale value frequency
81
81
  baton->entropy = std::abs(greyscale.hist_find().hist_entropy());
82
82
  // Estimate sharpness via standard deviation of greyscale laplacian
83
- VImage laplacian = VImage::new_matrixv(3, 3,
84
- 0.0, 1.0, 0.0,
85
- 1.0, -4.0, 1.0,
86
- 0.0, 1.0, 0.0);
87
- laplacian.set("scale", 9.0);
88
- baton->sharpness = greyscale.conv(laplacian).deviate();
83
+ if (image.width() > 1 || image.height() > 1) {
84
+ VImage laplacian = VImage::new_matrixv(3, 3,
85
+ 0.0, 1.0, 0.0,
86
+ 1.0, -4.0, 1.0,
87
+ 0.0, 1.0, 0.0);
88
+ laplacian.set("scale", 9.0);
89
+ baton->sharpness = greyscale.conv(laplacian).deviate();
90
+ }
91
+ // Most dominant sRGB colour via 4096-bin 3D histogram
92
+ vips::VImage hist = sharp::RemoveAlpha(image)
93
+ .colourspace(VIPS_INTERPRETATION_sRGB)
94
+ .hist_find_ndim(VImage::option()->set("bins", 16));
95
+ std::complex<double> maxpos = hist.maxpos();
96
+ int const dx = static_cast<int>(std::real(maxpos));
97
+ int const dy = static_cast<int>(std::imag(maxpos));
98
+ std::vector<double> pel = hist(dx, dy);
99
+ int const dz = std::distance(pel.begin(), std::find(pel.begin(), pel.end(), hist.max()));
100
+ baton->dominantRed = dx * 16 + 8;
101
+ baton->dominantGreen = dy * 16 + 8;
102
+ baton->dominantBlue = dz * 16 + 8;
89
103
  } catch (vips::VError const &err) {
90
104
  (baton->err).append(err.what());
91
105
  }
@@ -133,6 +147,11 @@ class StatsWorker : public Napi::AsyncWorker {
133
147
  info.Set("isOpaque", baton->isOpaque);
134
148
  info.Set("entropy", baton->entropy);
135
149
  info.Set("sharpness", baton->sharpness);
150
+ Napi::Object dominant = Napi::Object::New(env);
151
+ dominant.Set("r", baton->dominantRed);
152
+ dominant.Set("g", baton->dominantGreen);
153
+ dominant.Set("b", baton->dominantBlue);
154
+ info.Set("dominant", dominant);
136
155
  Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
137
156
  } else {
138
157
  Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, baton->err).Value() });
package/src/stats.h CHANGED
@@ -48,6 +48,9 @@ struct StatsBaton {
48
48
  bool isOpaque;
49
49
  double entropy;
50
50
  double sharpness;
51
+ int dominantRed;
52
+ int dominantGreen;
53
+ int dominantBlue;
51
54
 
52
55
  std::string err;
53
56
 
@@ -55,7 +58,10 @@ struct StatsBaton {
55
58
  input(nullptr),
56
59
  isOpaque(true),
57
60
  entropy(0.0),
58
- sharpness(0.0)
61
+ sharpness(0.0),
62
+ dominantRed(0),
63
+ dominantGreen(0),
64
+ dominantBlue(0)
59
65
  {}
60
66
  };
61
67