sharp 0.24.0 → 0.25.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -6
- package/binding.gyp +18 -3
- package/install/libvips.js +10 -8
- package/lib/channel.js +3 -2
- package/lib/composite.js +1 -2
- package/lib/constructor.js +8 -1
- package/lib/input.js +19 -37
- package/lib/libvips.js +10 -8
- package/lib/output.js +15 -4
- package/lib/resize.js +15 -3
- package/package.json +18 -12
- package/src/common.cc +46 -39
- package/src/common.h +15 -21
- package/src/metadata.cc +57 -94
- package/src/metadata.h +2 -2
- package/src/pipeline.cc +238 -294
- package/src/pipeline.h +4 -4
- package/src/sharp.cc +14 -24
- package/src/stats.cc +58 -85
- package/src/stats.h +4 -8
- package/src/utilities.cc +100 -145
- package/src/utilities.h +8 -8
package/src/pipeline.cc
CHANGED
|
@@ -25,8 +25,7 @@
|
|
|
25
25
|
#include <sys/stat.h>
|
|
26
26
|
|
|
27
27
|
#include <vips/vips8>
|
|
28
|
-
#include <
|
|
29
|
-
#include <nan.h>
|
|
28
|
+
#include <napi.h>
|
|
30
29
|
|
|
31
30
|
#include "common.h"
|
|
32
31
|
#include "operations.h"
|
|
@@ -46,28 +45,18 @@
|
|
|
46
45
|
#define STAT64_FUNCTION stat64
|
|
47
46
|
#endif
|
|
48
47
|
|
|
49
|
-
class PipelineWorker : public
|
|
48
|
+
class PipelineWorker : public Napi::AsyncWorker {
|
|
50
49
|
public:
|
|
51
|
-
PipelineWorker(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// Protect Buffer objects from GC, keyed on index
|
|
58
|
-
std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0,
|
|
59
|
-
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
|
|
60
|
-
SaveToPersistent(index, buffer);
|
|
61
|
-
return index + 1;
|
|
62
|
-
});
|
|
63
|
-
}
|
|
50
|
+
PipelineWorker(Napi::Function callback, PipelineBaton *baton,
|
|
51
|
+
Napi::Function debuglog, Napi::Function queueListener) :
|
|
52
|
+
Napi::AsyncWorker(callback),
|
|
53
|
+
baton(baton),
|
|
54
|
+
debuglog(Napi::Persistent(debuglog)),
|
|
55
|
+
queueListener(Napi::Persistent(queueListener)) {}
|
|
64
56
|
~PipelineWorker() {}
|
|
65
57
|
|
|
66
58
|
// libuv worker
|
|
67
59
|
void Execute() {
|
|
68
|
-
using sharp::HasAlpha;
|
|
69
|
-
using sharp::ImageType;
|
|
70
|
-
|
|
71
60
|
// Decrement queued task counter
|
|
72
61
|
g_atomic_int_dec_and_test(&sharp::counterQueue);
|
|
73
62
|
// Increment processing task counter
|
|
@@ -76,7 +65,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
76
65
|
try {
|
|
77
66
|
// Open input
|
|
78
67
|
vips::VImage image;
|
|
79
|
-
ImageType inputImageType;
|
|
68
|
+
sharp::ImageType inputImageType;
|
|
80
69
|
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
|
|
81
70
|
|
|
82
71
|
// Calculate angle of rotation
|
|
@@ -236,7 +225,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
236
225
|
}
|
|
237
226
|
if (
|
|
238
227
|
xshrink == yshrink && xshrink >= 2 * shrink_on_load_factor &&
|
|
239
|
-
(inputImageType == ImageType::JPEG || inputImageType == ImageType::WEBP) &&
|
|
228
|
+
(inputImageType == sharp::ImageType::JPEG || inputImageType == sharp::ImageType::WEBP) &&
|
|
240
229
|
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0
|
|
241
230
|
) {
|
|
242
231
|
if (xshrink >= 8 * shrink_on_load_factor) {
|
|
@@ -267,7 +256,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
267
256
|
->set("fail", baton->input->failOnError);
|
|
268
257
|
if (baton->input->buffer != nullptr) {
|
|
269
258
|
VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength);
|
|
270
|
-
if (inputImageType == ImageType::JPEG) {
|
|
259
|
+
if (inputImageType == sharp::ImageType::JPEG) {
|
|
271
260
|
// Reload JPEG buffer
|
|
272
261
|
image = VImage::jpegload_buffer(blob, option);
|
|
273
262
|
} else {
|
|
@@ -276,7 +265,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
276
265
|
}
|
|
277
266
|
vips_area_unref(reinterpret_cast<VipsArea*>(blob));
|
|
278
267
|
} else {
|
|
279
|
-
if (inputImageType == ImageType::JPEG) {
|
|
268
|
+
if (inputImageType == sharp::ImageType::JPEG) {
|
|
280
269
|
// Reload JPEG file
|
|
281
270
|
image = VImage::jpegload(const_cast<char*>(baton->input->file.data()), option);
|
|
282
271
|
} else {
|
|
@@ -320,7 +309,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
320
309
|
}
|
|
321
310
|
|
|
322
311
|
// Flatten image to remove alpha channel
|
|
323
|
-
if (baton->flatten && HasAlpha(image)) {
|
|
312
|
+
if (baton->flatten && sharp::HasAlpha(image)) {
|
|
324
313
|
// Scale up 8-bit values to match 16-bit input image
|
|
325
314
|
double const multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0;
|
|
326
315
|
// Background colour
|
|
@@ -356,11 +345,11 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
356
345
|
bool const shouldComposite = !baton->composite.empty();
|
|
357
346
|
bool const shouldModulate = baton->brightness != 1.0 || baton->saturation != 1.0 || baton->hue != 0.0;
|
|
358
347
|
|
|
359
|
-
if (shouldComposite && !HasAlpha(image)) {
|
|
348
|
+
if (shouldComposite && !sharp::HasAlpha(image)) {
|
|
360
349
|
image = sharp::EnsureAlpha(image);
|
|
361
350
|
}
|
|
362
351
|
|
|
363
|
-
bool const shouldPremultiplyAlpha = HasAlpha(image) &&
|
|
352
|
+
bool const shouldPremultiplyAlpha = sharp::HasAlpha(image) &&
|
|
364
353
|
(shouldResize || shouldBlur || shouldConv || shouldSharpen || shouldComposite);
|
|
365
354
|
|
|
366
355
|
// Premultiply image alpha channel before all transformations to avoid
|
|
@@ -416,7 +405,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
416
405
|
// Join additional color channels to the image
|
|
417
406
|
if (baton->joinChannelIn.size() > 0) {
|
|
418
407
|
VImage joinImage;
|
|
419
|
-
ImageType joinImageType = ImageType::UNKNOWN;
|
|
408
|
+
sharp::ImageType joinImageType = sharp::ImageType::UNKNOWN;
|
|
420
409
|
|
|
421
410
|
for (unsigned int i = 0; i < baton->joinChannelIn.size(); i++) {
|
|
422
411
|
std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i]);
|
|
@@ -548,7 +537,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
548
537
|
if (shouldComposite) {
|
|
549
538
|
for (Composite *composite : baton->composite) {
|
|
550
539
|
VImage compositeImage;
|
|
551
|
-
ImageType compositeImageType = ImageType::UNKNOWN;
|
|
540
|
+
sharp::ImageType compositeImageType = sharp::ImageType::UNKNOWN;
|
|
552
541
|
std::tie(compositeImage, compositeImageType) = OpenInput(composite->input);
|
|
553
542
|
// Verify within current dimensions
|
|
554
543
|
if (compositeImage.width() > image.width() || compositeImage.height() > image.height()) {
|
|
@@ -584,7 +573,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
584
573
|
}
|
|
585
574
|
// Ensure image to composite is sRGB with premultiplied alpha
|
|
586
575
|
compositeImage = compositeImage.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
587
|
-
if (!HasAlpha(compositeImage)) {
|
|
576
|
+
if (!sharp::HasAlpha(compositeImage)) {
|
|
588
577
|
compositeImage = sharp::EnsureAlpha(compositeImage);
|
|
589
578
|
}
|
|
590
579
|
if (!composite->premultiplied) compositeImage = compositeImage.premultiply();
|
|
@@ -638,7 +627,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
638
627
|
// Apply bitwise boolean operation between images
|
|
639
628
|
if (baton->boolean != nullptr) {
|
|
640
629
|
VImage booleanImage;
|
|
641
|
-
ImageType booleanImageType = ImageType::UNKNOWN;
|
|
630
|
+
sharp::ImageType booleanImageType = sharp::ImageType::UNKNOWN;
|
|
642
631
|
std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean);
|
|
643
632
|
image = sharp::Boolean(image, booleanImage, baton->booleanOp);
|
|
644
633
|
}
|
|
@@ -703,9 +692,9 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
703
692
|
// Output
|
|
704
693
|
if (baton->fileOut.empty()) {
|
|
705
694
|
// Buffer output
|
|
706
|
-
if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == ImageType::JPEG)) {
|
|
695
|
+
if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == sharp::ImageType::JPEG)) {
|
|
707
696
|
// Write JPEG to buffer
|
|
708
|
-
sharp::AssertImageTypeDimensions(image, ImageType::JPEG);
|
|
697
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
|
|
709
698
|
VipsArea *area = VIPS_AREA(image.jpegsave_buffer(VImage::option()
|
|
710
699
|
->set("strip", !baton->withMetadata)
|
|
711
700
|
->set("Q", baton->jpegQuality)
|
|
@@ -727,9 +716,10 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
727
716
|
baton->channels = std::min(baton->channels, 3);
|
|
728
717
|
}
|
|
729
718
|
} else if (baton->formatOut == "png" || (baton->formatOut == "input" &&
|
|
730
|
-
(inputImageType == ImageType::PNG || inputImageType == ImageType::GIF ||
|
|
719
|
+
(inputImageType == sharp::ImageType::PNG || inputImageType == sharp::ImageType::GIF ||
|
|
720
|
+
inputImageType == sharp::ImageType::SVG))) {
|
|
731
721
|
// Write PNG to buffer
|
|
732
|
-
sharp::AssertImageTypeDimensions(image, ImageType::PNG);
|
|
722
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::PNG);
|
|
733
723
|
VipsArea *area = VIPS_AREA(image.pngsave_buffer(VImage::option()
|
|
734
724
|
->set("strip", !baton->withMetadata)
|
|
735
725
|
->set("interlace", baton->pngProgressive)
|
|
@@ -744,9 +734,10 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
744
734
|
area->free_fn = nullptr;
|
|
745
735
|
vips_area_unref(area);
|
|
746
736
|
baton->formatOut = "png";
|
|
747
|
-
} else if (baton->formatOut == "webp" ||
|
|
737
|
+
} else if (baton->formatOut == "webp" ||
|
|
738
|
+
(baton->formatOut == "input" && inputImageType == sharp::ImageType::WEBP)) {
|
|
748
739
|
// Write WEBP to buffer
|
|
749
|
-
sharp::AssertImageTypeDimensions(image, ImageType::WEBP);
|
|
740
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::WEBP);
|
|
750
741
|
VipsArea *area = VIPS_AREA(image.webpsave_buffer(VImage::option()
|
|
751
742
|
->set("strip", !baton->withMetadata)
|
|
752
743
|
->set("Q", baton->webpQuality)
|
|
@@ -760,10 +751,12 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
760
751
|
area->free_fn = nullptr;
|
|
761
752
|
vips_area_unref(area);
|
|
762
753
|
baton->formatOut = "webp";
|
|
763
|
-
} else if (baton->formatOut == "tiff" ||
|
|
754
|
+
} else if (baton->formatOut == "tiff" ||
|
|
755
|
+
(baton->formatOut == "input" && inputImageType == sharp::ImageType::TIFF)) {
|
|
764
756
|
// Write TIFF to buffer
|
|
765
757
|
if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) {
|
|
766
|
-
sharp::AssertImageTypeDimensions(image, ImageType::JPEG);
|
|
758
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
|
|
759
|
+
baton->channels = std::min(baton->channels, 3);
|
|
767
760
|
}
|
|
768
761
|
// Cast pixel values to float, if required
|
|
769
762
|
if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) {
|
|
@@ -786,8 +779,8 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
786
779
|
area->free_fn = nullptr;
|
|
787
780
|
vips_area_unref(area);
|
|
788
781
|
baton->formatOut = "tiff";
|
|
789
|
-
|
|
790
|
-
|
|
782
|
+
} else if (baton->formatOut == "heif" ||
|
|
783
|
+
(baton->formatOut == "input" && inputImageType == sharp::ImageType::HEIF)) {
|
|
791
784
|
// Write HEIF to buffer
|
|
792
785
|
VipsArea *area = VIPS_AREA(image.heifsave_buffer(VImage::option()
|
|
793
786
|
->set("strip", !baton->withMetadata)
|
|
@@ -799,7 +792,8 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
799
792
|
area->free_fn = nullptr;
|
|
800
793
|
vips_area_unref(area);
|
|
801
794
|
baton->formatOut = "heif";
|
|
802
|
-
} else if (baton->formatOut == "raw" ||
|
|
795
|
+
} else if (baton->formatOut == "raw" ||
|
|
796
|
+
(baton->formatOut == "input" && inputImageType == sharp::ImageType::RAW)) {
|
|
803
797
|
// Write raw, uncompressed image data to buffer
|
|
804
798
|
if (baton->greyscale || image.interpretation() == VIPS_INTERPRETATION_B_W) {
|
|
805
799
|
// Extract first band for greyscale image
|
|
@@ -840,9 +834,9 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
840
834
|
bool const mightMatchInput = baton->formatOut == "input";
|
|
841
835
|
bool const willMatchInput = mightMatchInput && !(isJpeg || isPng || isWebp || isTiff || isDz || isDzZip || isV);
|
|
842
836
|
if (baton->formatOut == "jpeg" || (mightMatchInput && isJpeg) ||
|
|
843
|
-
(willMatchInput && inputImageType == ImageType::JPEG)) {
|
|
837
|
+
(willMatchInput && inputImageType == sharp::ImageType::JPEG)) {
|
|
844
838
|
// Write JPEG to file
|
|
845
|
-
sharp::AssertImageTypeDimensions(image, ImageType::JPEG);
|
|
839
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
|
|
846
840
|
image.jpegsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
847
841
|
->set("strip", !baton->withMetadata)
|
|
848
842
|
->set("Q", baton->jpegQuality)
|
|
@@ -856,9 +850,10 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
856
850
|
baton->formatOut = "jpeg";
|
|
857
851
|
baton->channels = std::min(baton->channels, 3);
|
|
858
852
|
} else if (baton->formatOut == "png" || (mightMatchInput && isPng) || (willMatchInput &&
|
|
859
|
-
(inputImageType == ImageType::PNG || inputImageType == ImageType::GIF ||
|
|
853
|
+
(inputImageType == sharp::ImageType::PNG || inputImageType == sharp::ImageType::GIF ||
|
|
854
|
+
inputImageType == sharp::ImageType::SVG))) {
|
|
860
855
|
// Write PNG to file
|
|
861
|
-
sharp::AssertImageTypeDimensions(image, ImageType::PNG);
|
|
856
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::PNG);
|
|
862
857
|
image.pngsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
863
858
|
->set("strip", !baton->withMetadata)
|
|
864
859
|
->set("interlace", baton->pngProgressive)
|
|
@@ -870,9 +865,9 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
870
865
|
->set("dither", baton->pngDither));
|
|
871
866
|
baton->formatOut = "png";
|
|
872
867
|
} else if (baton->formatOut == "webp" || (mightMatchInput && isWebp) ||
|
|
873
|
-
(willMatchInput && inputImageType == ImageType::WEBP)) {
|
|
868
|
+
(willMatchInput && inputImageType == sharp::ImageType::WEBP)) {
|
|
874
869
|
// Write WEBP to file
|
|
875
|
-
sharp::AssertImageTypeDimensions(image, ImageType::WEBP);
|
|
870
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::WEBP);
|
|
876
871
|
image.webpsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
877
872
|
->set("strip", !baton->withMetadata)
|
|
878
873
|
->set("Q", baton->webpQuality)
|
|
@@ -883,10 +878,11 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
883
878
|
->set("alpha_q", baton->webpAlphaQuality));
|
|
884
879
|
baton->formatOut = "webp";
|
|
885
880
|
} else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
|
|
886
|
-
(willMatchInput && inputImageType == ImageType::TIFF)) {
|
|
881
|
+
(willMatchInput && inputImageType == sharp::ImageType::TIFF)) {
|
|
887
882
|
// Write TIFF to file
|
|
888
883
|
if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) {
|
|
889
|
-
sharp::AssertImageTypeDimensions(image, ImageType::JPEG);
|
|
884
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
|
|
885
|
+
baton->channels = std::min(baton->channels, 3);
|
|
890
886
|
}
|
|
891
887
|
image.tiffsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
892
888
|
->set("strip", !baton->withMetadata)
|
|
@@ -901,9 +897,8 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
901
897
|
->set("xres", baton->tiffXres)
|
|
902
898
|
->set("yres", baton->tiffYres));
|
|
903
899
|
baton->formatOut = "tiff";
|
|
904
|
-
baton->channels = std::min(baton->channels, 3);
|
|
905
900
|
} else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) ||
|
|
906
|
-
(willMatchInput && inputImageType == ImageType::HEIF)) {
|
|
901
|
+
(willMatchInput && inputImageType == sharp::ImageType::HEIF)) {
|
|
907
902
|
// Write HEIF to file
|
|
908
903
|
if (sharp::IsAvif(baton->fileOut)) {
|
|
909
904
|
baton->heifCompression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1;
|
|
@@ -938,9 +933,6 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
938
933
|
};
|
|
939
934
|
suffix = AssembleSuffixString(".webp", options);
|
|
940
935
|
} else {
|
|
941
|
-
std::string extname = baton->tileLayout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE
|
|
942
|
-
|| baton->tileLayout == VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY
|
|
943
|
-
? ".jpg" : ".jpeg";
|
|
944
936
|
std::vector<std::pair<std::string, std::string>> options {
|
|
945
937
|
{"Q", std::to_string(baton->jpegQuality)},
|
|
946
938
|
{"interlace", baton->jpegProgressive ? "TRUE" : "FALSE"},
|
|
@@ -951,10 +943,11 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
951
943
|
{"optimize_scans", baton->jpegOptimiseScans ? "TRUE": "FALSE"},
|
|
952
944
|
{"optimize_coding", baton->jpegOptimiseCoding ? "TRUE": "FALSE"}
|
|
953
945
|
};
|
|
946
|
+
std::string extname = baton->tileLayout == VIPS_FOREIGN_DZ_LAYOUT_DZ ? ".jpeg" : ".jpg";
|
|
954
947
|
suffix = AssembleSuffixString(extname, options);
|
|
955
948
|
}
|
|
956
949
|
// Remove alpha channel from tile background if image does not contain an alpha channel
|
|
957
|
-
if (!HasAlpha(image)) {
|
|
950
|
+
if (!sharp::HasAlpha(image)) {
|
|
958
951
|
baton->tileBackground.pop_back();
|
|
959
952
|
}
|
|
960
953
|
// Write DZ to file
|
|
@@ -976,7 +969,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
976
969
|
image.dzsave(const_cast<char*>(baton->fileOut.data()), options);
|
|
977
970
|
baton->formatOut = "dz";
|
|
978
971
|
} else if (baton->formatOut == "v" || (mightMatchInput && isV) ||
|
|
979
|
-
(willMatchInput && inputImageType == ImageType::VIPS)) {
|
|
972
|
+
(willMatchInput && inputImageType == sharp::ImageType::VIPS)) {
|
|
980
973
|
// Write V to file
|
|
981
974
|
image.vipssave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
982
975
|
->set("strip", !baton->withMetadata));
|
|
@@ -1000,16 +993,18 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
1000
993
|
vips_thread_shutdown();
|
|
1001
994
|
}
|
|
1002
995
|
|
|
1003
|
-
void
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
Nan::HandleScope();
|
|
996
|
+
void OnOK() {
|
|
997
|
+
Napi::Env env = Env();
|
|
998
|
+
Napi::HandleScope scope(env);
|
|
1007
999
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1000
|
+
// Handle warnings
|
|
1001
|
+
std::string warning = sharp::VipsWarningPop();
|
|
1002
|
+
while (!warning.empty()) {
|
|
1003
|
+
debuglog.Call({ Napi::String::New(env, warning) });
|
|
1004
|
+
warning = sharp::VipsWarningPop();
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
if (baton->err.empty()) {
|
|
1013
1008
|
int width = baton->width;
|
|
1014
1009
|
int height = baton->height;
|
|
1015
1010
|
if (baton->topOffsetPre != -1 && (baton->width == -1 || baton->height == -1)) {
|
|
@@ -1021,50 +1016,40 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
1021
1016
|
height = baton->heightPost;
|
|
1022
1017
|
}
|
|
1023
1018
|
// Info Object
|
|
1024
|
-
|
|
1025
|
-
Set(
|
|
1026
|
-
Set(
|
|
1027
|
-
Set(
|
|
1028
|
-
Set(
|
|
1029
|
-
Set(
|
|
1019
|
+
Napi::Object info = Napi::Object::New(env);
|
|
1020
|
+
info.Set("format", baton->formatOut);
|
|
1021
|
+
info.Set("width", static_cast<uint32_t>(width));
|
|
1022
|
+
info.Set("height", static_cast<uint32_t>(height));
|
|
1023
|
+
info.Set("channels", static_cast<uint32_t>(baton->channels));
|
|
1024
|
+
info.Set("premultiplied", baton->premultiplied);
|
|
1030
1025
|
if (baton->hasCropOffset) {
|
|
1031
|
-
Set(
|
|
1032
|
-
|
|
1033
|
-
Set(info, New("cropOffsetTop").ToLocalChecked(),
|
|
1034
|
-
New<v8::Int32>(static_cast<int32_t>(baton->cropOffsetTop)));
|
|
1026
|
+
info.Set("cropOffsetLeft", static_cast<int32_t>(baton->cropOffsetLeft));
|
|
1027
|
+
info.Set("cropOffsetTop", static_cast<int32_t>(baton->cropOffsetTop));
|
|
1035
1028
|
}
|
|
1036
1029
|
if (baton->trimThreshold > 0.0) {
|
|
1037
|
-
Set(
|
|
1038
|
-
|
|
1039
|
-
Set(info, New("trimOffsetTop").ToLocalChecked(),
|
|
1040
|
-
New<v8::Int32>(static_cast<int32_t>(baton->trimOffsetTop)));
|
|
1030
|
+
info.Set("trimOffsetLeft", static_cast<int32_t>(baton->trimOffsetLeft));
|
|
1031
|
+
info.Set("trimOffsetTop", static_cast<int32_t>(baton->trimOffsetTop));
|
|
1041
1032
|
}
|
|
1042
1033
|
|
|
1043
1034
|
if (baton->bufferOutLength > 0) {
|
|
1044
|
-
// Pass ownership of output data to Buffer instance
|
|
1045
|
-
argv[1] = Nan::NewBuffer(
|
|
1046
|
-
static_cast<char*>(baton->bufferOut), baton->bufferOutLength, sharp::FreeCallback, nullptr)
|
|
1047
|
-
.ToLocalChecked();
|
|
1048
1035
|
// Add buffer size to info
|
|
1049
|
-
Set(
|
|
1050
|
-
|
|
1036
|
+
info.Set("size", static_cast<uint32_t>(baton->bufferOutLength));
|
|
1037
|
+
// Pass ownership of output data to Buffer instance
|
|
1038
|
+
Napi::Buffer<char> data = Napi::Buffer<char>::New(env, static_cast<char*>(baton->bufferOut),
|
|
1039
|
+
baton->bufferOutLength, sharp::FreeCallback);
|
|
1040
|
+
Callback().MakeCallback(Receiver().Value(), { env.Null(), data, info });
|
|
1051
1041
|
} else {
|
|
1052
1042
|
// Add file size to info
|
|
1053
1043
|
struct STAT64_STRUCT st;
|
|
1054
1044
|
if (STAT64_FUNCTION(baton->fileOut.data(), &st) == 0) {
|
|
1055
|
-
Set(
|
|
1045
|
+
info.Set("size", static_cast<uint32_t>(st.st_size));
|
|
1056
1046
|
}
|
|
1057
|
-
|
|
1047
|
+
Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
|
|
1058
1048
|
}
|
|
1049
|
+
} else {
|
|
1050
|
+
Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, baton->err).Value() });
|
|
1059
1051
|
}
|
|
1060
1052
|
|
|
1061
|
-
// Dispose of Persistent wrapper around input Buffers so they can be garbage collected
|
|
1062
|
-
std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0,
|
|
1063
|
-
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
|
|
1064
|
-
GetFromPersistent(index);
|
|
1065
|
-
return index + 1;
|
|
1066
|
-
});
|
|
1067
|
-
|
|
1068
1053
|
// Delete baton
|
|
1069
1054
|
delete baton->input;
|
|
1070
1055
|
delete baton->boolean;
|
|
@@ -1077,29 +1062,16 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
1077
1062
|
}
|
|
1078
1063
|
delete baton;
|
|
1079
1064
|
|
|
1080
|
-
// Handle warnings
|
|
1081
|
-
std::string warning = sharp::VipsWarningPop();
|
|
1082
|
-
while (!warning.empty()) {
|
|
1083
|
-
v8::Local<v8::Value> message[1] = { New(warning).ToLocalChecked() };
|
|
1084
|
-
debuglog->Call(1, message, async_resource);
|
|
1085
|
-
warning = sharp::VipsWarningPop();
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
1065
|
// Decrement processing task counter
|
|
1089
1066
|
g_atomic_int_dec_and_test(&sharp::counterProcess);
|
|
1090
|
-
|
|
1091
|
-
queueListener
|
|
1092
|
-
delete queueListener;
|
|
1093
|
-
|
|
1094
|
-
// Return to JavaScript
|
|
1095
|
-
callback->Call(3, argv, async_resource);
|
|
1067
|
+
Napi::Number queueLength = Napi::Number::New(env, static_cast<double>(sharp::counterQueue));
|
|
1068
|
+
queueListener.Call(Receiver().Value(), { queueLength });
|
|
1096
1069
|
}
|
|
1097
1070
|
|
|
1098
1071
|
private:
|
|
1099
1072
|
PipelineBaton *baton;
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
std::vector<v8::Local<v8::Object>> buffersToPersist;
|
|
1073
|
+
Napi::FunctionReference debuglog;
|
|
1074
|
+
Napi::FunctionReference queueListener;
|
|
1103
1075
|
|
|
1104
1076
|
/*
|
|
1105
1077
|
Calculate the angle of rotation and need-to-flip for the given Exif orientation
|
|
@@ -1169,37 +1141,27 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
1169
1141
|
/*
|
|
1170
1142
|
pipeline(options, output, callback)
|
|
1171
1143
|
*/
|
|
1172
|
-
|
|
1173
|
-
using sharp::HasAttr;
|
|
1174
|
-
using sharp::AttrTo;
|
|
1175
|
-
using sharp::AttrAs;
|
|
1176
|
-
using sharp::AttrAsStr;
|
|
1177
|
-
using sharp::AttrAsRgba;
|
|
1178
|
-
using sharp::CreateInputDescriptor;
|
|
1179
|
-
|
|
1180
|
-
// Input Buffers must not undergo GC compaction during processing
|
|
1181
|
-
std::vector<v8::Local<v8::Object>> buffersToPersist;
|
|
1182
|
-
|
|
1144
|
+
Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
1183
1145
|
// V8 objects are converted to non-V8 types held in the baton struct
|
|
1184
1146
|
PipelineBaton *baton = new PipelineBaton;
|
|
1185
|
-
|
|
1147
|
+
Napi::Object options = info[0].As<Napi::Object>();
|
|
1186
1148
|
|
|
1187
1149
|
// Input
|
|
1188
|
-
baton->input = CreateInputDescriptor(
|
|
1150
|
+
baton->input = sharp::CreateInputDescriptor(options.Get("input").As<Napi::Object>());
|
|
1189
1151
|
// Extract image options
|
|
1190
|
-
baton->topOffsetPre =
|
|
1191
|
-
baton->leftOffsetPre =
|
|
1192
|
-
baton->widthPre =
|
|
1193
|
-
baton->heightPre =
|
|
1194
|
-
baton->topOffsetPost =
|
|
1195
|
-
baton->leftOffsetPost =
|
|
1196
|
-
baton->widthPost =
|
|
1197
|
-
baton->heightPost =
|
|
1152
|
+
baton->topOffsetPre = sharp::AttrAsInt32(options, "topOffsetPre");
|
|
1153
|
+
baton->leftOffsetPre = sharp::AttrAsInt32(options, "leftOffsetPre");
|
|
1154
|
+
baton->widthPre = sharp::AttrAsInt32(options, "widthPre");
|
|
1155
|
+
baton->heightPre = sharp::AttrAsInt32(options, "heightPre");
|
|
1156
|
+
baton->topOffsetPost = sharp::AttrAsInt32(options, "topOffsetPost");
|
|
1157
|
+
baton->leftOffsetPost = sharp::AttrAsInt32(options, "leftOffsetPost");
|
|
1158
|
+
baton->widthPost = sharp::AttrAsInt32(options, "widthPost");
|
|
1159
|
+
baton->heightPost = sharp::AttrAsInt32(options, "heightPost");
|
|
1198
1160
|
// Output image dimensions
|
|
1199
|
-
baton->width =
|
|
1200
|
-
baton->height =
|
|
1161
|
+
baton->width = sharp::AttrAsInt32(options, "width");
|
|
1162
|
+
baton->height = sharp::AttrAsInt32(options, "height");
|
|
1201
1163
|
// Canvas option
|
|
1202
|
-
std::string canvas = AttrAsStr(options, "canvas");
|
|
1164
|
+
std::string canvas = sharp::AttrAsStr(options, "canvas");
|
|
1203
1165
|
if (canvas == "crop") {
|
|
1204
1166
|
baton->canvas = Canvas::CROP;
|
|
1205
1167
|
} else if (canvas == "embed") {
|
|
@@ -1212,191 +1174,168 @@ NAN_METHOD(pipeline) {
|
|
|
1212
1174
|
baton->canvas = Canvas::IGNORE_ASPECT;
|
|
1213
1175
|
}
|
|
1214
1176
|
// Tint chroma
|
|
1215
|
-
baton->tintA =
|
|
1216
|
-
baton->tintB =
|
|
1177
|
+
baton->tintA = sharp::AttrAsDouble(options, "tintA");
|
|
1178
|
+
baton->tintB = sharp::AttrAsDouble(options, "tintB");
|
|
1217
1179
|
// Composite
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
for (int i = 0; i < compositeArrayLength; i++) {
|
|
1222
|
-
v8::Local<v8::Object> compositeObject = Nan::Get(compositeArray, i).ToLocalChecked().As<v8::Object>();
|
|
1180
|
+
Napi::Array compositeArray = options.Get("composite").As<Napi::Array>();
|
|
1181
|
+
for (unsigned int i = 0; i < compositeArray.Length(); i++) {
|
|
1182
|
+
Napi::Object compositeObject = compositeArray.Get(i).As<Napi::Object>();
|
|
1223
1183
|
Composite *composite = new Composite;
|
|
1224
|
-
composite->input = CreateInputDescriptor(
|
|
1184
|
+
composite->input = sharp::CreateInputDescriptor(compositeObject.Get("input").As<Napi::Object>());
|
|
1225
1185
|
composite->mode = static_cast<VipsBlendMode>(
|
|
1226
|
-
vips_enum_from_nick(nullptr, VIPS_TYPE_BLEND_MODE, AttrAsStr(compositeObject, "blend").data()));
|
|
1227
|
-
composite->gravity =
|
|
1228
|
-
composite->left =
|
|
1229
|
-
composite->top =
|
|
1230
|
-
composite->tile =
|
|
1231
|
-
composite->premultiplied =
|
|
1186
|
+
vips_enum_from_nick(nullptr, VIPS_TYPE_BLEND_MODE, sharp::AttrAsStr(compositeObject, "blend").data()));
|
|
1187
|
+
composite->gravity = sharp::AttrAsUint32(compositeObject, "gravity");
|
|
1188
|
+
composite->left = sharp::AttrAsInt32(compositeObject, "left");
|
|
1189
|
+
composite->top = sharp::AttrAsInt32(compositeObject, "top");
|
|
1190
|
+
composite->tile = sharp::AttrAsBool(compositeObject, "tile");
|
|
1191
|
+
composite->premultiplied = sharp::AttrAsBool(compositeObject, "premultiplied");
|
|
1232
1192
|
baton->composite.push_back(composite);
|
|
1233
1193
|
}
|
|
1234
1194
|
// Resize options
|
|
1235
|
-
baton->withoutEnlargement =
|
|
1236
|
-
baton->position =
|
|
1237
|
-
baton->resizeBackground = AttrAsRgba(options, "resizeBackground");
|
|
1238
|
-
baton->kernel = AttrAsStr(options, "kernel");
|
|
1239
|
-
baton->fastShrinkOnLoad =
|
|
1195
|
+
baton->withoutEnlargement = sharp::AttrAsBool(options, "withoutEnlargement");
|
|
1196
|
+
baton->position = sharp::AttrAsInt32(options, "position");
|
|
1197
|
+
baton->resizeBackground = sharp::AttrAsRgba(options, "resizeBackground");
|
|
1198
|
+
baton->kernel = sharp::AttrAsStr(options, "kernel");
|
|
1199
|
+
baton->fastShrinkOnLoad = sharp::AttrAsBool(options, "fastShrinkOnLoad");
|
|
1240
1200
|
// Join Channel Options
|
|
1241
|
-
if (
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
v8::Local<v8::Array> joinChannelArray = joinChannelObject.As<v8::Array>();
|
|
1245
|
-
int joinChannelArrayLength = AttrTo<int32_t>(joinChannelObject, "length");
|
|
1246
|
-
for (int i = 0; i < joinChannelArrayLength; i++) {
|
|
1201
|
+
if (options.Has("joinChannelIn")) {
|
|
1202
|
+
Napi::Array joinChannelArray = options.Get("joinChannelIn").As<Napi::Array>();
|
|
1203
|
+
for (unsigned int i = 0; i < joinChannelArray.Length(); i++) {
|
|
1247
1204
|
baton->joinChannelIn.push_back(
|
|
1248
|
-
CreateInputDescriptor(
|
|
1249
|
-
Nan::Get(joinChannelArray, i).ToLocalChecked().As<v8::Object>(),
|
|
1250
|
-
buffersToPersist));
|
|
1205
|
+
sharp::CreateInputDescriptor(joinChannelArray.Get(i).As<Napi::Object>()));
|
|
1251
1206
|
}
|
|
1252
1207
|
}
|
|
1253
1208
|
// Operators
|
|
1254
|
-
baton->flatten =
|
|
1255
|
-
baton->flattenBackground = AttrAsRgba(options, "flattenBackground");
|
|
1256
|
-
baton->negate =
|
|
1257
|
-
baton->blurSigma =
|
|
1258
|
-
baton->brightness =
|
|
1259
|
-
baton->saturation =
|
|
1260
|
-
baton->hue =
|
|
1261
|
-
baton->medianSize =
|
|
1262
|
-
baton->sharpenSigma =
|
|
1263
|
-
baton->sharpenFlat =
|
|
1264
|
-
baton->sharpenJagged =
|
|
1265
|
-
baton->threshold =
|
|
1266
|
-
baton->thresholdGrayscale =
|
|
1267
|
-
baton->trimThreshold =
|
|
1268
|
-
baton->gamma =
|
|
1269
|
-
baton->gammaOut =
|
|
1270
|
-
baton->linearA =
|
|
1271
|
-
baton->linearB =
|
|
1272
|
-
baton->greyscale =
|
|
1273
|
-
baton->normalise =
|
|
1274
|
-
baton->useExifOrientation =
|
|
1275
|
-
baton->angle =
|
|
1276
|
-
baton->rotationAngle =
|
|
1277
|
-
baton->rotationBackground = AttrAsRgba(options, "rotationBackground");
|
|
1278
|
-
baton->rotateBeforePreExtract =
|
|
1279
|
-
baton->flip =
|
|
1280
|
-
baton->flop =
|
|
1281
|
-
baton->extendTop =
|
|
1282
|
-
baton->extendBottom =
|
|
1283
|
-
baton->extendLeft =
|
|
1284
|
-
baton->extendRight =
|
|
1285
|
-
baton->extendBackground = AttrAsRgba(options, "extendBackground");
|
|
1286
|
-
baton->extractChannel =
|
|
1287
|
-
|
|
1288
|
-
baton->removeAlpha =
|
|
1289
|
-
baton->ensureAlpha =
|
|
1290
|
-
if (
|
|
1291
|
-
baton->boolean = CreateInputDescriptor(
|
|
1292
|
-
baton->booleanOp = sharp::GetBooleanOperation(AttrAsStr(options, "booleanOp"));
|
|
1209
|
+
baton->flatten = sharp::AttrAsBool(options, "flatten");
|
|
1210
|
+
baton->flattenBackground = sharp::AttrAsRgba(options, "flattenBackground");
|
|
1211
|
+
baton->negate = sharp::AttrAsBool(options, "negate");
|
|
1212
|
+
baton->blurSigma = sharp::AttrAsDouble(options, "blurSigma");
|
|
1213
|
+
baton->brightness = sharp::AttrAsDouble(options, "brightness");
|
|
1214
|
+
baton->saturation = sharp::AttrAsDouble(options, "saturation");
|
|
1215
|
+
baton->hue = sharp::AttrAsInt32(options, "hue");
|
|
1216
|
+
baton->medianSize = sharp::AttrAsUint32(options, "medianSize");
|
|
1217
|
+
baton->sharpenSigma = sharp::AttrAsDouble(options, "sharpenSigma");
|
|
1218
|
+
baton->sharpenFlat = sharp::AttrAsDouble(options, "sharpenFlat");
|
|
1219
|
+
baton->sharpenJagged = sharp::AttrAsDouble(options, "sharpenJagged");
|
|
1220
|
+
baton->threshold = sharp::AttrAsInt32(options, "threshold");
|
|
1221
|
+
baton->thresholdGrayscale = sharp::AttrAsBool(options, "thresholdGrayscale");
|
|
1222
|
+
baton->trimThreshold = sharp::AttrAsDouble(options, "trimThreshold");
|
|
1223
|
+
baton->gamma = sharp::AttrAsDouble(options, "gamma");
|
|
1224
|
+
baton->gammaOut = sharp::AttrAsDouble(options, "gammaOut");
|
|
1225
|
+
baton->linearA = sharp::AttrAsDouble(options, "linearA");
|
|
1226
|
+
baton->linearB = sharp::AttrAsDouble(options, "linearB");
|
|
1227
|
+
baton->greyscale = sharp::AttrAsBool(options, "greyscale");
|
|
1228
|
+
baton->normalise = sharp::AttrAsBool(options, "normalise");
|
|
1229
|
+
baton->useExifOrientation = sharp::AttrAsBool(options, "useExifOrientation");
|
|
1230
|
+
baton->angle = sharp::AttrAsInt32(options, "angle");
|
|
1231
|
+
baton->rotationAngle = sharp::AttrAsDouble(options, "rotationAngle");
|
|
1232
|
+
baton->rotationBackground = sharp::AttrAsRgba(options, "rotationBackground");
|
|
1233
|
+
baton->rotateBeforePreExtract = sharp::AttrAsBool(options, "rotateBeforePreExtract");
|
|
1234
|
+
baton->flip = sharp::AttrAsBool(options, "flip");
|
|
1235
|
+
baton->flop = sharp::AttrAsBool(options, "flop");
|
|
1236
|
+
baton->extendTop = sharp::AttrAsInt32(options, "extendTop");
|
|
1237
|
+
baton->extendBottom = sharp::AttrAsInt32(options, "extendBottom");
|
|
1238
|
+
baton->extendLeft = sharp::AttrAsInt32(options, "extendLeft");
|
|
1239
|
+
baton->extendRight = sharp::AttrAsInt32(options, "extendRight");
|
|
1240
|
+
baton->extendBackground = sharp::AttrAsRgba(options, "extendBackground");
|
|
1241
|
+
baton->extractChannel = sharp::AttrAsInt32(options, "extractChannel");
|
|
1242
|
+
|
|
1243
|
+
baton->removeAlpha = sharp::AttrAsBool(options, "removeAlpha");
|
|
1244
|
+
baton->ensureAlpha = sharp::AttrAsBool(options, "ensureAlpha");
|
|
1245
|
+
if (options.Has("boolean")) {
|
|
1246
|
+
baton->boolean = sharp::CreateInputDescriptor(options.Get("boolean").As<Napi::Object>());
|
|
1247
|
+
baton->booleanOp = sharp::GetBooleanOperation(sharp::AttrAsStr(options, "booleanOp"));
|
|
1293
1248
|
}
|
|
1294
|
-
if (
|
|
1295
|
-
baton->bandBoolOp = sharp::GetBooleanOperation(AttrAsStr(options, "bandBoolOp"));
|
|
1249
|
+
if (options.Has("bandBoolOp")) {
|
|
1250
|
+
baton->bandBoolOp = sharp::GetBooleanOperation(sharp::AttrAsStr(options, "bandBoolOp"));
|
|
1296
1251
|
}
|
|
1297
|
-
if (
|
|
1298
|
-
|
|
1299
|
-
baton->convKernelWidth =
|
|
1300
|
-
baton->convKernelHeight =
|
|
1301
|
-
baton->convKernelScale =
|
|
1302
|
-
baton->convKernelOffset =
|
|
1252
|
+
if (options.Has("convKernel")) {
|
|
1253
|
+
Napi::Object kernel = options.Get("convKernel").As<Napi::Object>();
|
|
1254
|
+
baton->convKernelWidth = sharp::AttrAsUint32(kernel, "width");
|
|
1255
|
+
baton->convKernelHeight = sharp::AttrAsUint32(kernel, "height");
|
|
1256
|
+
baton->convKernelScale = sharp::AttrAsDouble(kernel, "scale");
|
|
1257
|
+
baton->convKernelOffset = sharp::AttrAsDouble(kernel, "offset");
|
|
1303
1258
|
size_t const kernelSize = static_cast<size_t>(baton->convKernelWidth * baton->convKernelHeight);
|
|
1304
1259
|
baton->convKernel = std::unique_ptr<double[]>(new double[kernelSize]);
|
|
1305
|
-
|
|
1260
|
+
Napi::Array kdata = kernel.Get("kernel").As<Napi::Array>();
|
|
1306
1261
|
for (unsigned int i = 0; i < kernelSize; i++) {
|
|
1307
|
-
baton->convKernel[i] =
|
|
1262
|
+
baton->convKernel[i] = sharp::AttrAsDouble(kdata, i);
|
|
1308
1263
|
}
|
|
1309
1264
|
}
|
|
1310
|
-
if (
|
|
1265
|
+
if (options.Has("recombMatrix")) {
|
|
1311
1266
|
baton->recombMatrix = std::unique_ptr<double[]>(new double[9]);
|
|
1312
|
-
|
|
1267
|
+
Napi::Array recombMatrix = options.Get("recombMatrix").As<Napi::Array>();
|
|
1313
1268
|
for (unsigned int i = 0; i < 9; i++) {
|
|
1314
|
-
baton->recombMatrix[i] =
|
|
1269
|
+
baton->recombMatrix[i] = sharp::AttrAsDouble(recombMatrix, i);
|
|
1315
1270
|
}
|
|
1316
1271
|
}
|
|
1317
|
-
baton->colourspace = sharp::GetInterpretation(AttrAsStr(options, "colourspace"));
|
|
1272
|
+
baton->colourspace = sharp::GetInterpretation(sharp::AttrAsStr(options, "colourspace"));
|
|
1318
1273
|
if (baton->colourspace == VIPS_INTERPRETATION_ERROR) {
|
|
1319
1274
|
baton->colourspace = VIPS_INTERPRETATION_sRGB;
|
|
1320
1275
|
}
|
|
1321
1276
|
// Output
|
|
1322
|
-
baton->formatOut = AttrAsStr(options, "formatOut");
|
|
1323
|
-
baton->fileOut = AttrAsStr(options, "fileOut");
|
|
1324
|
-
baton->withMetadata =
|
|
1325
|
-
baton->withMetadataOrientation =
|
|
1277
|
+
baton->formatOut = sharp::AttrAsStr(options, "formatOut");
|
|
1278
|
+
baton->fileOut = sharp::AttrAsStr(options, "fileOut");
|
|
1279
|
+
baton->withMetadata = sharp::AttrAsBool(options, "withMetadata");
|
|
1280
|
+
baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
|
|
1326
1281
|
// Format-specific
|
|
1327
|
-
baton->jpegQuality =
|
|
1328
|
-
baton->jpegProgressive =
|
|
1329
|
-
baton->jpegChromaSubsampling = AttrAsStr(options, "jpegChromaSubsampling");
|
|
1330
|
-
baton->jpegTrellisQuantisation =
|
|
1331
|
-
baton->jpegQuantisationTable =
|
|
1332
|
-
baton->jpegOvershootDeringing =
|
|
1333
|
-
baton->jpegOptimiseScans =
|
|
1334
|
-
baton->jpegOptimiseCoding =
|
|
1335
|
-
baton->pngProgressive =
|
|
1336
|
-
baton->pngCompressionLevel =
|
|
1337
|
-
baton->pngAdaptiveFiltering =
|
|
1338
|
-
baton->pngPalette =
|
|
1339
|
-
baton->pngQuality =
|
|
1340
|
-
baton->pngColours =
|
|
1341
|
-
baton->pngDither =
|
|
1342
|
-
baton->webpQuality =
|
|
1343
|
-
baton->webpAlphaQuality =
|
|
1344
|
-
baton->webpLossless =
|
|
1345
|
-
baton->webpNearLossless =
|
|
1346
|
-
baton->webpSmartSubsample =
|
|
1347
|
-
baton->webpReductionEffort =
|
|
1348
|
-
baton->tiffQuality =
|
|
1349
|
-
baton->tiffPyramid =
|
|
1350
|
-
baton->tiffSquash =
|
|
1351
|
-
baton->tiffTile =
|
|
1352
|
-
baton->tiffTileWidth =
|
|
1353
|
-
baton->tiffTileHeight =
|
|
1354
|
-
baton->tiffXres =
|
|
1355
|
-
baton->tiffYres =
|
|
1282
|
+
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
|
|
1283
|
+
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
|
|
1284
|
+
baton->jpegChromaSubsampling = sharp::AttrAsStr(options, "jpegChromaSubsampling");
|
|
1285
|
+
baton->jpegTrellisQuantisation = sharp::AttrAsBool(options, "jpegTrellisQuantisation");
|
|
1286
|
+
baton->jpegQuantisationTable = sharp::AttrAsUint32(options, "jpegQuantisationTable");
|
|
1287
|
+
baton->jpegOvershootDeringing = sharp::AttrAsBool(options, "jpegOvershootDeringing");
|
|
1288
|
+
baton->jpegOptimiseScans = sharp::AttrAsBool(options, "jpegOptimiseScans");
|
|
1289
|
+
baton->jpegOptimiseCoding = sharp::AttrAsBool(options, "jpegOptimiseCoding");
|
|
1290
|
+
baton->pngProgressive = sharp::AttrAsBool(options, "pngProgressive");
|
|
1291
|
+
baton->pngCompressionLevel = sharp::AttrAsUint32(options, "pngCompressionLevel");
|
|
1292
|
+
baton->pngAdaptiveFiltering = sharp::AttrAsBool(options, "pngAdaptiveFiltering");
|
|
1293
|
+
baton->pngPalette = sharp::AttrAsBool(options, "pngPalette");
|
|
1294
|
+
baton->pngQuality = sharp::AttrAsUint32(options, "pngQuality");
|
|
1295
|
+
baton->pngColours = sharp::AttrAsUint32(options, "pngColours");
|
|
1296
|
+
baton->pngDither = sharp::AttrAsDouble(options, "pngDither");
|
|
1297
|
+
baton->webpQuality = sharp::AttrAsUint32(options, "webpQuality");
|
|
1298
|
+
baton->webpAlphaQuality = sharp::AttrAsUint32(options, "webpAlphaQuality");
|
|
1299
|
+
baton->webpLossless = sharp::AttrAsBool(options, "webpLossless");
|
|
1300
|
+
baton->webpNearLossless = sharp::AttrAsBool(options, "webpNearLossless");
|
|
1301
|
+
baton->webpSmartSubsample = sharp::AttrAsBool(options, "webpSmartSubsample");
|
|
1302
|
+
baton->webpReductionEffort = sharp::AttrAsUint32(options, "webpReductionEffort");
|
|
1303
|
+
baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
|
|
1304
|
+
baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid");
|
|
1305
|
+
baton->tiffSquash = sharp::AttrAsBool(options, "tiffSquash");
|
|
1306
|
+
baton->tiffTile = sharp::AttrAsBool(options, "tiffTile");
|
|
1307
|
+
baton->tiffTileWidth = sharp::AttrAsUint32(options, "tiffTileWidth");
|
|
1308
|
+
baton->tiffTileHeight = sharp::AttrAsUint32(options, "tiffTileHeight");
|
|
1309
|
+
baton->tiffXres = sharp::AttrAsDouble(options, "tiffXres");
|
|
1310
|
+
baton->tiffYres = sharp::AttrAsDouble(options, "tiffYres");
|
|
1356
1311
|
// tiff compression options
|
|
1357
1312
|
baton->tiffCompression = static_cast<VipsForeignTiffCompression>(
|
|
1358
1313
|
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_TIFF_COMPRESSION,
|
|
1359
|
-
AttrAsStr(options, "tiffCompression").data()));
|
|
1314
|
+
sharp::AttrAsStr(options, "tiffCompression").data()));
|
|
1360
1315
|
baton->tiffPredictor = static_cast<VipsForeignTiffPredictor>(
|
|
1361
1316
|
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_TIFF_PREDICTOR,
|
|
1362
|
-
AttrAsStr(options, "tiffPredictor").data()));
|
|
1363
|
-
baton->heifQuality =
|
|
1364
|
-
baton->heifLossless =
|
|
1317
|
+
sharp::AttrAsStr(options, "tiffPredictor").data()));
|
|
1318
|
+
baton->heifQuality = sharp::AttrAsUint32(options, "heifQuality");
|
|
1319
|
+
baton->heifLossless = sharp::AttrAsBool(options, "heifLossless");
|
|
1365
1320
|
baton->heifCompression = static_cast<VipsForeignHeifCompression>(
|
|
1366
|
-
|
|
1367
|
-
AttrAsStr(options, "heifCompression").data()));
|
|
1321
|
+
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_HEIF_COMPRESSION,
|
|
1322
|
+
sharp::AttrAsStr(options, "heifCompression").data()));
|
|
1368
1323
|
// Tile output
|
|
1369
|
-
baton->tileSize =
|
|
1370
|
-
baton->tileOverlap =
|
|
1371
|
-
|
|
1372
|
-
baton->
|
|
1373
|
-
baton->
|
|
1374
|
-
baton->
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
baton->tileLayout = VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY;
|
|
1385
|
-
} else {
|
|
1386
|
-
baton->tileLayout = VIPS_FOREIGN_DZ_LAYOUT_DZ;
|
|
1387
|
-
}
|
|
1388
|
-
baton->tileFormat = AttrAsStr(options, "tileFormat");
|
|
1389
|
-
std::string tileDepth = AttrAsStr(options, "tileDepth");
|
|
1390
|
-
if (tileDepth == "onetile") {
|
|
1391
|
-
baton->tileDepth = VIPS_FOREIGN_DZ_DEPTH_ONETILE;
|
|
1392
|
-
} else if (tileDepth == "one") {
|
|
1393
|
-
baton->tileDepth = VIPS_FOREIGN_DZ_DEPTH_ONE;
|
|
1394
|
-
} else if (tileDepth == "onepixel") {
|
|
1395
|
-
baton->tileDepth = VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL;
|
|
1396
|
-
} else {
|
|
1397
|
-
// signal that we do not want to pass any value to dzSave
|
|
1398
|
-
baton->tileDepth = VIPS_FOREIGN_DZ_DEPTH_LAST;
|
|
1399
|
-
}
|
|
1324
|
+
baton->tileSize = sharp::AttrAsUint32(options, "tileSize");
|
|
1325
|
+
baton->tileOverlap = sharp::AttrAsUint32(options, "tileOverlap");
|
|
1326
|
+
baton->tileAngle = sharp::AttrAsInt32(options, "tileAngle");
|
|
1327
|
+
baton->tileBackground = sharp::AttrAsRgba(options, "tileBackground");
|
|
1328
|
+
baton->tileSkipBlanks = sharp::AttrAsInt32(options, "tileSkipBlanks");
|
|
1329
|
+
baton->tileContainer = static_cast<VipsForeignDzContainer>(
|
|
1330
|
+
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_CONTAINER,
|
|
1331
|
+
sharp::AttrAsStr(options, "tileContainer").data()));
|
|
1332
|
+
baton->tileLayout = static_cast<VipsForeignDzLayout>(
|
|
1333
|
+
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_LAYOUT,
|
|
1334
|
+
sharp::AttrAsStr(options, "tileLayout").data()));
|
|
1335
|
+
baton->tileFormat = sharp::AttrAsStr(options, "tileFormat");
|
|
1336
|
+
baton->tileDepth = static_cast<VipsForeignDzDepth>(
|
|
1337
|
+
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_DEPTH,
|
|
1338
|
+
sharp::AttrAsStr(options, "tileDepth").data()));
|
|
1400
1339
|
|
|
1401
1340
|
// Force random access for certain operations
|
|
1402
1341
|
if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
|
|
@@ -1404,25 +1343,30 @@ NAN_METHOD(pipeline) {
|
|
|
1404
1343
|
baton->trimThreshold > 0.0 ||
|
|
1405
1344
|
baton->normalise ||
|
|
1406
1345
|
baton->position == 16 || baton->position == 17 ||
|
|
1407
|
-
baton->angle != 0 ||
|
|
1346
|
+
baton->angle % 360 != 0 ||
|
|
1347
|
+
fmod(baton->rotationAngle, 360.0) != 0.0 ||
|
|
1348
|
+
baton->useExifOrientation
|
|
1408
1349
|
) {
|
|
1409
1350
|
baton->input->access = VIPS_ACCESS_RANDOM;
|
|
1410
1351
|
}
|
|
1411
1352
|
}
|
|
1412
1353
|
|
|
1413
1354
|
// Function to notify of libvips warnings
|
|
1414
|
-
|
|
1355
|
+
Napi::Function debuglog = options.Get("debuglog").As<Napi::Function>();
|
|
1415
1356
|
|
|
1416
1357
|
// Function to notify of queue length changes
|
|
1417
|
-
|
|
1358
|
+
Napi::Function queueListener = options.Get("queueListener").As<Napi::Function>();
|
|
1418
1359
|
|
|
1419
1360
|
// Join queue for worker thread
|
|
1420
|
-
|
|
1421
|
-
|
|
1361
|
+
Napi::Function callback = info[1].As<Napi::Function>();
|
|
1362
|
+
PipelineWorker *worker = new PipelineWorker(callback, baton, debuglog, queueListener);
|
|
1363
|
+
worker->Receiver().Set("options", options);
|
|
1364
|
+
worker->Queue();
|
|
1422
1365
|
|
|
1423
1366
|
// Increment queued task counter
|
|
1424
1367
|
g_atomic_int_inc(&sharp::counterQueue);
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1368
|
+
Napi::Number queueLength = Napi::Number::New(info.Env(), static_cast<double>(sharp::counterQueue));
|
|
1369
|
+
queueListener.Call(info.This(), { queueLength });
|
|
1370
|
+
|
|
1371
|
+
return info.Env().Undefined();
|
|
1428
1372
|
}
|