sharp 0.31.3 → 0.32.1

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/operations.h CHANGED
@@ -1,16 +1,5 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #ifndef SRC_OPERATIONS_H_
16
5
  #define SRC_OPERATIONS_H_
@@ -33,7 +22,7 @@ namespace sharp {
33
22
  /*
34
23
  * Stretch luminance to cover full dynamic range.
35
24
  */
36
- VImage Normalise(VImage image);
25
+ VImage Normalise(VImage image, int const lower, int const upper);
37
26
 
38
27
  /*
39
28
  * Contrast limiting adapative histogram equalization (CLAHE)
@@ -97,6 +86,11 @@ namespace sharp {
97
86
  */
98
87
  VImage Linear(VImage image, std::vector<double> const a, std::vector<double> const b);
99
88
 
89
+ /*
90
+ * Unflatten
91
+ */
92
+ VImage Unflatten(VImage image);
93
+
100
94
  /*
101
95
  * Recomb with a Matrix of the given bands/channel size.
102
96
  * Eg. RGB will be a 3x3 matrix.
@@ -124,7 +118,7 @@ namespace sharp {
124
118
  * Split into frames, embed each frame, reassemble, and update pageHeight.
125
119
  */
126
120
  VImage EmbedMultiPage(VImage image, int left, int top, int width, int height,
127
- std::vector<double> background, int nPages, int *pageHeight);
121
+ VipsExtend extendWith, std::vector<double> background, int nPages, int *pageHeight);
128
122
 
129
123
  } // namespace sharp
130
124
 
package/src/pipeline.cc CHANGED
@@ -1,16 +1,5 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #include <algorithm>
16
5
  #include <cmath>
@@ -85,6 +74,7 @@ class PipelineWorker : public Napi::AsyncWorker {
85
74
  VipsAngle autoRotation = VIPS_ANGLE_D0;
86
75
  bool autoFlip = FALSE;
87
76
  bool autoFlop = FALSE;
77
+
88
78
  if (baton->useExifOrientation) {
89
79
  // Rotate and flip image according to Exif orientation
90
80
  std::tie(autoRotation, autoFlip, autoFlop) = CalculateExifRotationAndFlip(sharp::ExifOrientation(image));
@@ -205,7 +195,7 @@ class PipelineWorker : public Napi::AsyncWorker {
205
195
  if (jpegShrinkOnLoad > 1 && static_cast<int>(shrink) == jpegShrinkOnLoad) {
206
196
  jpegShrinkOnLoad /= 2;
207
197
  }
208
- } else if (inputImageType == sharp::ImageType::WEBP && shrink > 1.0) {
198
+ } else if (inputImageType == sharp::ImageType::WEBP && baton->fastShrinkOnLoad && shrink > 1.0) {
209
199
  // Avoid upscaling via webp
210
200
  scale = 1.0 / shrink;
211
201
  } else if (inputImageType == sharp::ImageType::SVG ||
@@ -320,7 +310,8 @@ class PipelineWorker : public Napi::AsyncWorker {
320
310
  if (
321
311
  sharp::HasProfile(image) &&
322
312
  image.interpretation() != VIPS_INTERPRETATION_LABS &&
323
- image.interpretation() != VIPS_INTERPRETATION_GREY16
313
+ image.interpretation() != VIPS_INTERPRETATION_GREY16 &&
314
+ !baton->input->ignoreIcc
324
315
  ) {
325
316
  // Convert to sRGB/P3 using embedded profile
326
317
  try {
@@ -329,9 +320,12 @@ class PipelineWorker : public Napi::AsyncWorker {
329
320
  ->set("depth", image.interpretation() == VIPS_INTERPRETATION_RGB16 ? 16 : 8)
330
321
  ->set("intent", VIPS_INTENT_PERCEPTUAL));
331
322
  } catch(...) {
332
- // Ignore failure of embedded profile
323
+ sharp::VipsWarningCallback(nullptr, G_LOG_LEVEL_WARNING, "Invalid embedded profile", nullptr);
333
324
  }
334
- } else if (image.interpretation() == VIPS_INTERPRETATION_CMYK) {
325
+ } else if (
326
+ image.interpretation() == VIPS_INTERPRETATION_CMYK &&
327
+ baton->colourspaceInput != VIPS_INTERPRETATION_CMYK
328
+ ) {
335
329
  image = image.icc_transform(processingProfile, VImage::option()
336
330
  ->set("input_profile", "cmyk")
337
331
  ->set("intent", VIPS_INTENT_PERCEPTUAL));
@@ -367,11 +361,12 @@ class PipelineWorker : public Napi::AsyncWorker {
367
361
  image = sharp::EnsureAlpha(image, 1);
368
362
  }
369
363
 
364
+ VipsBandFormat premultiplyFormat = image.format();
370
365
  bool const shouldPremultiplyAlpha = sharp::HasAlpha(image) &&
371
366
  (shouldResize || shouldBlur || shouldConv || shouldSharpen);
372
367
 
373
368
  if (shouldPremultiplyAlpha) {
374
- image = image.premultiply();
369
+ image = image.premultiply().cast(premultiplyFormat);
375
370
  }
376
371
 
377
372
  // Resize
@@ -399,7 +394,7 @@ class PipelineWorker : public Napi::AsyncWorker {
399
394
  }
400
395
 
401
396
  // Join additional color channels to the image
402
- if (baton->joinChannelIn.size() > 0) {
397
+ if (!baton->joinChannelIn.empty()) {
403
398
  VImage joinImage;
404
399
  sharp::ImageType joinImageType = sharp::ImageType::UNKNOWN;
405
400
 
@@ -409,6 +404,7 @@ class PipelineWorker : public Napi::AsyncWorker {
409
404
  image = image.bandjoin(joinImage);
410
405
  }
411
406
  image = image.copy(VImage::option()->set("interpretation", baton->colourspace));
407
+ image = sharp::RemoveGifPalette(image);
412
408
  }
413
409
 
414
410
  inputWidth = image.width();
@@ -438,7 +434,7 @@ class PipelineWorker : public Napi::AsyncWorker {
438
434
 
439
435
  image = nPages > 1
440
436
  ? sharp::EmbedMultiPage(image,
441
- left, top, width, height, background, nPages, &targetPageHeight)
437
+ left, top, width, height, VIPS_EXTEND_BACKGROUND, background, nPages, &targetPageHeight)
442
438
  : image.embed(left, top, width, height, VImage::option()
443
439
  ->set("extend", VIPS_EXTEND_BACKGROUND)
444
440
  ->set("background", background));
@@ -455,6 +451,7 @@ class PipelineWorker : public Napi::AsyncWorker {
455
451
  // Gravity-based crop
456
452
  int left;
457
453
  int top;
454
+
458
455
  std::tie(left, top) = sharp::CalculateCrop(
459
456
  inputWidth, inputHeight, baton->width, baton->height, baton->position);
460
457
  int width = std::min(inputWidth, baton->width);
@@ -465,16 +462,26 @@ class PipelineWorker : public Napi::AsyncWorker {
465
462
  left, top, width, height, nPages, &targetPageHeight)
466
463
  : image.extract_area(left, top, width, height);
467
464
  } else {
465
+ int attention_x;
466
+ int attention_y;
467
+
468
468
  // Attention-based or Entropy-based crop
469
469
  MultiPageUnsupported(nPages, "Resize strategy");
470
470
  image = image.tilecache(VImage::option()
471
471
  ->set("access", VIPS_ACCESS_RANDOM)
472
472
  ->set("threaded", TRUE));
473
+
473
474
  image = image.smartcrop(baton->width, baton->height, VImage::option()
474
- ->set("interesting", baton->position == 16 ? VIPS_INTERESTING_ENTROPY : VIPS_INTERESTING_ATTENTION));
475
+ ->set("interesting", baton->position == 16 ? VIPS_INTERESTING_ENTROPY : VIPS_INTERESTING_ATTENTION)
476
+ ->set("premultiplied", shouldPremultiplyAlpha)
477
+ ->set("attention_x", &attention_x)
478
+ ->set("attention_y", &attention_y));
475
479
  baton->hasCropOffset = true;
476
480
  baton->cropOffsetLeft = static_cast<int>(image.xoffset());
477
481
  baton->cropOffsetTop = static_cast<int>(image.yoffset());
482
+ baton->hasAttentionCenter = true;
483
+ baton->attentionX = static_cast<int>(attention_x * jpegShrinkOnLoad / scale);
484
+ baton->attentionY = static_cast<int>(attention_y * jpegShrinkOnLoad / scale);
478
485
  }
479
486
  }
480
487
  }
@@ -503,7 +510,7 @@ class PipelineWorker : public Napi::AsyncWorker {
503
510
  }
504
511
 
505
512
  // Affine transform
506
- if (baton->affineMatrix.size() > 0) {
513
+ if (!baton->affineMatrix.empty()) {
507
514
  MultiPageUnsupported(nPages, "Affine");
508
515
  std::vector<double> background;
509
516
  std::tie(image, background) = sharp::ApplyAlpha(image, baton->affineBackground, shouldPremultiplyAlpha);
@@ -519,24 +526,37 @@ class PipelineWorker : public Napi::AsyncWorker {
519
526
 
520
527
  // Extend edges
521
528
  if (baton->extendTop > 0 || baton->extendBottom > 0 || baton->extendLeft > 0 || baton->extendRight > 0) {
522
- std::vector<double> background;
523
- std::tie(image, background) = sharp::ApplyAlpha(image, baton->extendBackground, shouldPremultiplyAlpha);
524
-
525
529
  // Embed
526
530
  baton->width = image.width() + baton->extendLeft + baton->extendRight;
527
531
  baton->height = (nPages > 1 ? targetPageHeight : image.height()) + baton->extendTop + baton->extendBottom;
528
532
 
529
- image = nPages > 1
530
- ? sharp::EmbedMultiPage(image,
531
- baton->extendLeft, baton->extendTop, baton->width, baton->height, background, nPages, &targetPageHeight)
532
- : image.embed(baton->extendLeft, baton->extendTop, baton->width, baton->height,
533
- VImage::option()->set("extend", VIPS_EXTEND_BACKGROUND)->set("background", background));
533
+ if (baton->extendWith == VIPS_EXTEND_BACKGROUND) {
534
+ std::vector<double> background;
535
+ std::tie(image, background) = sharp::ApplyAlpha(image, baton->extendBackground, shouldPremultiplyAlpha);
536
+
537
+ image = nPages > 1
538
+ ? sharp::EmbedMultiPage(image,
539
+ baton->extendLeft, baton->extendTop, baton->width, baton->height,
540
+ baton->extendWith, background, nPages, &targetPageHeight)
541
+ : image.embed(baton->extendLeft, baton->extendTop, baton->width, baton->height,
542
+ VImage::option()->set("extend", baton->extendWith)->set("background", background));
543
+ } else {
544
+ std::vector<double> ignoredBackground(1);
545
+ image = nPages > 1
546
+ ? sharp::EmbedMultiPage(image,
547
+ baton->extendLeft, baton->extendTop, baton->width, baton->height,
548
+ baton->extendWith, ignoredBackground, nPages, &targetPageHeight)
549
+ : image.embed(baton->extendLeft, baton->extendTop, baton->width, baton->height,
550
+ VImage::option()->set("extend", baton->extendWith));
551
+ }
534
552
  }
535
553
  // Median - must happen before blurring, due to the utility of blurring after thresholding
536
554
  if (baton->medianSize > 0) {
537
555
  image = image.median(baton->medianSize);
538
556
  }
557
+
539
558
  // Threshold - must happen before blurring, due to the utility of blurring after thresholding
559
+ // Threshold - must happen before unflatten to enable non-white unflattening
540
560
  if (baton->threshold != 0) {
541
561
  image = sharp::Threshold(image, baton->threshold, baton->thresholdGrayscale);
542
562
  }
@@ -546,6 +566,11 @@ class PipelineWorker : public Napi::AsyncWorker {
546
566
  image = sharp::Blur(image, baton->blurSigma);
547
567
  }
548
568
 
569
+ // Unflatten the image
570
+ if (baton->unflatten) {
571
+ image = sharp::Unflatten(image);
572
+ }
573
+
549
574
  // Convolve
550
575
  if (shouldConv) {
551
576
  image = sharp::Convolve(image,
@@ -572,13 +597,7 @@ class PipelineWorker : public Napi::AsyncWorker {
572
597
 
573
598
  // Reverse premultiplication after all transformations
574
599
  if (shouldPremultiplyAlpha) {
575
- image = image.unpremultiply();
576
- // Cast pixel values to integer
577
- if (sharp::Is16Bit(image.interpretation())) {
578
- image = image.cast(VIPS_FORMAT_USHORT);
579
- } else {
580
- image = image.cast(VIPS_FORMAT_UCHAR);
581
- }
600
+ image = image.unpremultiply().cast(premultiplyFormat);
582
601
  }
583
602
  baton->premultiplied = shouldPremultiplyAlpha;
584
603
 
@@ -660,6 +679,7 @@ class PipelineWorker : public Napi::AsyncWorker {
660
679
  ys.push_back(top);
661
680
  }
662
681
  image = VImage::composite(images, modes, VImage::option()->set("x", xs)->set("y", ys));
682
+ image = sharp::RemoveGifPalette(image);
663
683
  }
664
684
 
665
685
  // Gamma decoding (brighten)
@@ -674,7 +694,7 @@ class PipelineWorker : public Napi::AsyncWorker {
674
694
 
675
695
  // Apply normalisation - stretch luminance to cover full dynamic range
676
696
  if (baton->normalise) {
677
- image = sharp::Normalise(image);
697
+ image = sharp::Normalise(image, baton->normaliseLower, baton->normaliseUpper);
678
698
  }
679
699
 
680
700
  // Apply contrast limiting adaptive histogram equalization (CLAHE)
@@ -689,6 +709,7 @@ class PipelineWorker : public Napi::AsyncWorker {
689
709
  std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean);
690
710
  booleanImage = sharp::EnsureColourspace(booleanImage, baton->colourspaceInput);
691
711
  image = sharp::Boolean(image, booleanImage, baton->booleanOp);
712
+ image = sharp::RemoveGifPalette(image);
692
713
  }
693
714
 
694
715
  // Apply per-channel Bandbool bitwise operations after all other operations
@@ -870,7 +891,8 @@ class PipelineWorker : public Napi::AsyncWorker {
870
891
  ->set("strip", !baton->withMetadata)
871
892
  ->set("bitdepth", baton->gifBitdepth)
872
893
  ->set("effort", baton->gifEffort)
873
- ->set("reoptimise", baton->gifReoptimise)
894
+ ->set("reuse", baton->gifReuse)
895
+ ->set("interlace", baton->gifProgressive)
874
896
  ->set("interframe_maxerror", baton->gifInterFrameMaxError)
875
897
  ->set("interpalette_maxerror", baton->gifInterPaletteMaxError)
876
898
  ->set("dither", baton->gifDither)));
@@ -1068,7 +1090,8 @@ class PipelineWorker : public Napi::AsyncWorker {
1068
1090
  ->set("strip", !baton->withMetadata)
1069
1091
  ->set("bitdepth", baton->gifBitdepth)
1070
1092
  ->set("effort", baton->gifEffort)
1071
- ->set("reoptimise", baton->gifReoptimise)
1093
+ ->set("reuse", baton->gifReuse)
1094
+ ->set("interlace", baton->gifProgressive)
1072
1095
  ->set("dither", baton->gifDither));
1073
1096
  baton->formatOut = "gif";
1074
1097
  } else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
@@ -1164,7 +1187,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1164
1187
  // Handle warnings
1165
1188
  std::string warning = sharp::VipsWarningPop();
1166
1189
  while (!warning.empty()) {
1167
- debuglog.Call({ Napi::String::New(env, warning) });
1190
+ debuglog.MakeCallback(Receiver().Value(), { Napi::String::New(env, warning) });
1168
1191
  warning = sharp::VipsWarningPop();
1169
1192
  }
1170
1193
 
@@ -1193,6 +1216,10 @@ class PipelineWorker : public Napi::AsyncWorker {
1193
1216
  info.Set("cropOffsetLeft", static_cast<int32_t>(baton->cropOffsetLeft));
1194
1217
  info.Set("cropOffsetTop", static_cast<int32_t>(baton->cropOffsetTop));
1195
1218
  }
1219
+ if (baton->hasAttentionCenter) {
1220
+ info.Set("attentionX", static_cast<int32_t>(baton->attentionX));
1221
+ info.Set("attentionY", static_cast<int32_t>(baton->attentionY));
1222
+ }
1196
1223
  if (baton->trimThreshold > 0.0) {
1197
1224
  info.Set("trimOffsetLeft", static_cast<int32_t>(baton->trimOffsetLeft));
1198
1225
  info.Set("trimOffsetTop", static_cast<int32_t>(baton->trimOffsetTop));
@@ -1206,8 +1233,8 @@ class PipelineWorker : public Napi::AsyncWorker {
1206
1233
  // Add buffer size to info
1207
1234
  info.Set("size", static_cast<uint32_t>(baton->bufferOutLength));
1208
1235
  // Pass ownership of output data to Buffer instance
1209
- Napi::Buffer<char> data = sharp::NewOrCopyBuffer(env, static_cast<char*>(baton->bufferOut),
1210
- baton->bufferOutLength);
1236
+ Napi::Buffer<char> data = Napi::Buffer<char>::NewOrCopy(env, static_cast<char*>(baton->bufferOut),
1237
+ baton->bufferOutLength, sharp::FreeCallback);
1211
1238
  Callback().MakeCallback(Receiver().Value(), { env.Null(), data, info });
1212
1239
  } else {
1213
1240
  // Add file size to info
@@ -1218,7 +1245,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1218
1245
  Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
1219
1246
  }
1220
1247
  } else {
1221
- Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, baton->err).Value() });
1248
+ Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
1222
1249
  }
1223
1250
 
1224
1251
  // Delete baton
@@ -1236,7 +1263,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1236
1263
  // Decrement processing task counter
1237
1264
  g_atomic_int_dec_and_test(&sharp::counterProcess);
1238
1265
  Napi::Number queueLength = Napi::Number::New(env, static_cast<double>(sharp::counterQueue));
1239
- queueListener.Call(Receiver().Value(), { queueLength });
1266
+ queueListener.MakeCallback(Receiver().Value(), { queueLength });
1240
1267
  }
1241
1268
 
1242
1269
  private:
@@ -1382,7 +1409,7 @@ class PipelineWorker : public Napi::AsyncWorker {
1382
1409
  Napi::Value pipeline(const Napi::CallbackInfo& info) {
1383
1410
  // V8 objects are converted to non-V8 types held in the baton struct
1384
1411
  PipelineBaton *baton = new PipelineBaton;
1385
- Napi::Object options = info[0].As<Napi::Object>();
1412
+ Napi::Object options = info[size_t(0)].As<Napi::Object>();
1386
1413
 
1387
1414
  // Input
1388
1415
  baton->input = sharp::CreateInputDescriptor(options.Get("input").As<Napi::Object>());
@@ -1444,6 +1471,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1444
1471
  // Operators
1445
1472
  baton->flatten = sharp::AttrAsBool(options, "flatten");
1446
1473
  baton->flattenBackground = sharp::AttrAsVectorOfDouble(options, "flattenBackground");
1474
+ baton->unflatten = sharp::AttrAsBool(options, "unflatten");
1447
1475
  baton->negate = sharp::AttrAsBool(options, "negate");
1448
1476
  baton->negateAlpha = sharp::AttrAsBool(options, "negateAlpha");
1449
1477
  baton->blurSigma = sharp::AttrAsDouble(options, "blurSigma");
@@ -1468,6 +1496,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1468
1496
  baton->linearB = sharp::AttrAsVectorOfDouble(options, "linearB");
1469
1497
  baton->greyscale = sharp::AttrAsBool(options, "greyscale");
1470
1498
  baton->normalise = sharp::AttrAsBool(options, "normalise");
1499
+ baton->normaliseLower = sharp::AttrAsUint32(options, "normaliseLower");
1500
+ baton->normaliseUpper = sharp::AttrAsUint32(options, "normaliseUpper");
1471
1501
  baton->tintA = sharp::AttrAsDouble(options, "tintA");
1472
1502
  baton->tintB = sharp::AttrAsDouble(options, "tintB");
1473
1503
  baton->claheWidth = sharp::AttrAsUint32(options, "claheWidth");
@@ -1485,6 +1515,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1485
1515
  baton->extendLeft = sharp::AttrAsInt32(options, "extendLeft");
1486
1516
  baton->extendRight = sharp::AttrAsInt32(options, "extendRight");
1487
1517
  baton->extendBackground = sharp::AttrAsVectorOfDouble(options, "extendBackground");
1518
+ baton->extendWith = sharp::AttrAsEnum<VipsExtend>(options, "extendWith", VIPS_TYPE_EXTEND);
1488
1519
  baton->extractChannel = sharp::AttrAsInt32(options, "extractChannel");
1489
1520
  baton->affineMatrix = sharp::AttrAsVectorOfDouble(options, "affineMatrix");
1490
1521
  baton->affineBackground = sharp::AttrAsVectorOfDouble(options, "affineBackground");
@@ -1582,7 +1613,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1582
1613
  baton->gifDither = sharp::AttrAsDouble(options, "gifDither");
1583
1614
  baton->gifInterFrameMaxError = sharp::AttrAsDouble(options, "gifInterFrameMaxError");
1584
1615
  baton->gifInterPaletteMaxError = sharp::AttrAsDouble(options, "gifInterPaletteMaxError");
1585
- baton->gifReoptimise = sharp::AttrAsBool(options, "gifReoptimise");
1616
+ baton->gifReuse = sharp::AttrAsBool(options, "gifReuse");
1617
+ baton->gifProgressive = sharp::AttrAsBool(options, "gifProgressive");
1586
1618
  baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
1587
1619
  baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid");
1588
1620
  baton->tiffBitdepth = sharp::AttrAsUint32(options, "tiffBitdepth");
@@ -1638,9 +1670,13 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1638
1670
  baton->trimThreshold > 0.0 ||
1639
1671
  baton->normalise ||
1640
1672
  baton->position == 16 || baton->position == 17 ||
1641
- baton->angle % 360 != 0 ||
1642
- fmod(baton->rotationAngle, 360.0) != 0.0 ||
1643
- baton->useExifOrientation
1673
+ baton->angle != 0 ||
1674
+ baton->rotationAngle != 0.0 ||
1675
+ baton->tileAngle != 0 ||
1676
+ baton->useExifOrientation ||
1677
+ baton->flip ||
1678
+ baton->claheWidth != 0 ||
1679
+ !baton->affineMatrix.empty()
1644
1680
  ) {
1645
1681
  baton->input->access = VIPS_ACCESS_RANDOM;
1646
1682
  }
@@ -1653,7 +1689,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1653
1689
  Napi::Function queueListener = options.Get("queueListener").As<Napi::Function>();
1654
1690
 
1655
1691
  // Join queue for worker thread
1656
- Napi::Function callback = info[1].As<Napi::Function>();
1692
+ Napi::Function callback = info[size_t(1)].As<Napi::Function>();
1657
1693
  PipelineWorker *worker = new PipelineWorker(callback, baton, debuglog, queueListener);
1658
1694
  worker->Receiver().Set("options", options);
1659
1695
  worker->Queue();
@@ -1661,7 +1697,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
1661
1697
  // Increment queued task counter
1662
1698
  g_atomic_int_inc(&sharp::counterQueue);
1663
1699
  Napi::Number queueLength = Napi::Number::New(info.Env(), static_cast<double>(sharp::counterQueue));
1664
- queueListener.Call(info.This(), { queueLength });
1700
+ queueListener.MakeCallback(info.This(), { queueLength });
1665
1701
 
1666
1702
  return info.Env().Undefined();
1667
1703
  }
package/src/pipeline.h CHANGED
@@ -1,16 +1,5 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #ifndef SRC_PIPELINE_H_
16
5
  #define SRC_PIPELINE_H_
@@ -74,6 +63,9 @@ struct PipelineBaton {
74
63
  bool hasCropOffset;
75
64
  int cropOffsetLeft;
76
65
  int cropOffsetTop;
66
+ bool hasAttentionCenter;
67
+ int attentionX;
68
+ int attentionY;
77
69
  bool premultiplied;
78
70
  bool tileCentre;
79
71
  bool fastShrinkOnLoad;
@@ -81,6 +73,7 @@ struct PipelineBaton {
81
73
  double tintB;
82
74
  bool flatten;
83
75
  std::vector<double> flattenBackground;
76
+ bool unflatten;
84
77
  bool negate;
85
78
  bool negateAlpha;
86
79
  double blurSigma;
@@ -107,6 +100,8 @@ struct PipelineBaton {
107
100
  double gammaOut;
108
101
  bool greyscale;
109
102
  bool normalise;
103
+ int normaliseLower;
104
+ int normaliseUpper;
110
105
  int claheWidth;
111
106
  int claheHeight;
112
107
  int claheMaxSlope;
@@ -122,6 +117,7 @@ struct PipelineBaton {
122
117
  int extendLeft;
123
118
  int extendRight;
124
119
  std::vector<double> extendBackground;
120
+ VipsExtend extendWith;
125
121
  bool withoutEnlargement;
126
122
  bool withoutReduction;
127
123
  std::vector<double> affineMatrix;
@@ -165,7 +161,8 @@ struct PipelineBaton {
165
161
  double gifDither;
166
162
  double gifInterFrameMaxError;
167
163
  double gifInterPaletteMaxError;
168
- bool gifReoptimise;
164
+ bool gifReuse;
165
+ bool gifProgressive;
169
166
  int tiffQuality;
170
167
  VipsForeignTiffCompression tiffCompression;
171
168
  VipsForeignTiffPredictor tiffPredictor;
@@ -235,11 +232,15 @@ struct PipelineBaton {
235
232
  hasCropOffset(false),
236
233
  cropOffsetLeft(0),
237
234
  cropOffsetTop(0),
235
+ hasAttentionCenter(false),
236
+ attentionX(0),
237
+ attentionY(0),
238
238
  premultiplied(false),
239
239
  tintA(128.0),
240
240
  tintB(128.0),
241
241
  flatten(false),
242
242
  flattenBackground{ 0.0, 0.0, 0.0 },
243
+ unflatten(false),
243
244
  negate(false),
244
245
  negateAlpha(true),
245
246
  blurSigma(0.0),
@@ -265,6 +266,8 @@ struct PipelineBaton {
265
266
  gamma(0.0),
266
267
  greyscale(false),
267
268
  normalise(false),
269
+ normaliseLower(1),
270
+ normaliseUpper(99),
268
271
  claheWidth(0),
269
272
  claheHeight(0),
270
273
  claheMaxSlope(3),
@@ -279,6 +282,7 @@ struct PipelineBaton {
279
282
  extendLeft(0),
280
283
  extendRight(0),
281
284
  extendBackground{ 0.0, 0.0, 0.0, 255.0 },
285
+ extendWith(VIPS_EXTEND_BACKGROUND),
282
286
  withoutEnlargement(false),
283
287
  withoutReduction(false),
284
288
  affineMatrix{ 1.0, 0.0, 0.0, 1.0 },
@@ -322,7 +326,8 @@ struct PipelineBaton {
322
326
  gifDither(1.0),
323
327
  gifInterFrameMaxError(0.0),
324
328
  gifInterPaletteMaxError(3.0),
325
- gifReoptimise(false),
329
+ gifReuse(true),
330
+ gifProgressive(false),
326
331
  tiffQuality(80),
327
332
  tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
328
333
  tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
package/src/sharp.cc CHANGED
@@ -1,16 +1,5 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #include <napi.h>
16
5
  #include <vips/vips8>
package/src/stats.cc CHANGED
@@ -1,16 +1,5 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #include <numeric>
16
5
  #include <vector>
@@ -117,7 +106,7 @@ class StatsWorker : public Napi::AsyncWorker {
117
106
  // Handle warnings
118
107
  std::string warning = sharp::VipsWarningPop();
119
108
  while (!warning.empty()) {
120
- debuglog.Call({ Napi::String::New(env, warning) });
109
+ debuglog.MakeCallback(Receiver().Value(), { Napi::String::New(env, warning) });
121
110
  warning = sharp::VipsWarningPop();
122
111
  }
123
112
 
@@ -154,7 +143,7 @@ class StatsWorker : public Napi::AsyncWorker {
154
143
  info.Set("dominant", dominant);
155
144
  Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
156
145
  } else {
157
- Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, baton->err).Value() });
146
+ Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
158
147
  }
159
148
 
160
149
  delete baton->input;
@@ -172,7 +161,7 @@ class StatsWorker : public Napi::AsyncWorker {
172
161
  Napi::Value stats(const Napi::CallbackInfo& info) {
173
162
  // V8 objects are converted to non-V8 types held in the baton struct
174
163
  StatsBaton *baton = new StatsBaton;
175
- Napi::Object options = info[0].As<Napi::Object>();
164
+ Napi::Object options = info[size_t(0)].As<Napi::Object>();
176
165
 
177
166
  // Input
178
167
  baton->input = sharp::CreateInputDescriptor(options.Get("input").As<Napi::Object>());
@@ -182,7 +171,7 @@ Napi::Value stats(const Napi::CallbackInfo& info) {
182
171
  Napi::Function debuglog = options.Get("debuglog").As<Napi::Function>();
183
172
 
184
173
  // Join queue for worker thread
185
- Napi::Function callback = info[1].As<Napi::Function>();
174
+ Napi::Function callback = info[size_t(1)].As<Napi::Function>();
186
175
  StatsWorker *worker = new StatsWorker(callback, baton, debuglog);
187
176
  worker->Receiver().Set("options", options);
188
177
  worker->Queue();
package/src/stats.h CHANGED
@@ -1,16 +1,5 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #ifndef SRC_STATS_H_
16
5
  #define SRC_STATS_H_