sharp 0.33.5 → 0.34.0-rc.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/lib/channel.js +2 -1
- package/lib/colour.js +3 -2
- package/lib/composite.js +4 -2
- package/lib/constructor.js +33 -2
- package/lib/index.d.ts +166 -55
- package/lib/input.js +92 -16
- package/lib/libvips.js +3 -1
- package/lib/operation.js +92 -25
- package/lib/output.js +11 -9
- package/lib/resize.js +5 -2
- package/lib/sharp.js +10 -2
- package/lib/utility.js +1 -0
- package/package.json +39 -39
- package/src/binding.gyp +15 -8
- package/src/common.cc +42 -15
- package/src/common.h +26 -19
- package/src/metadata.cc +26 -8
- package/src/metadata.h +4 -2
- package/src/operations.cc +31 -9
- package/src/operations.h +9 -0
- package/src/pipeline.cc +109 -45
- package/src/pipeline.h +8 -3
- package/src/sharp.cc +1 -0
- package/src/stats.cc +1 -1
- package/src/utilities.cc +20 -3
- package/src/utilities.h +1 -0
package/src/pipeline.cc
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
#include <algorithm>
|
|
5
5
|
#include <cmath>
|
|
6
|
+
#include <filesystem>
|
|
6
7
|
#include <map>
|
|
7
8
|
#include <memory>
|
|
8
9
|
#include <numeric>
|
|
@@ -20,17 +21,6 @@
|
|
|
20
21
|
#include "operations.h"
|
|
21
22
|
#include "pipeline.h"
|
|
22
23
|
|
|
23
|
-
#ifdef _WIN32
|
|
24
|
-
#define STAT64_STRUCT __stat64
|
|
25
|
-
#define STAT64_FUNCTION _stat64
|
|
26
|
-
#elif defined(_LARGEFILE64_SOURCE)
|
|
27
|
-
#define STAT64_STRUCT stat64
|
|
28
|
-
#define STAT64_FUNCTION stat64
|
|
29
|
-
#else
|
|
30
|
-
#define STAT64_STRUCT stat
|
|
31
|
-
#define STAT64_FUNCTION stat
|
|
32
|
-
#endif
|
|
33
|
-
|
|
34
24
|
class PipelineWorker : public Napi::AsyncWorker {
|
|
35
25
|
public:
|
|
36
26
|
PipelineWorker(Napi::Function callback, PipelineBaton *baton,
|
|
@@ -52,7 +42,39 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
52
42
|
// Open input
|
|
53
43
|
vips::VImage image;
|
|
54
44
|
sharp::ImageType inputImageType;
|
|
55
|
-
|
|
45
|
+
if (baton->join.empty()) {
|
|
46
|
+
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
|
|
47
|
+
} else {
|
|
48
|
+
std::vector<VImage> images;
|
|
49
|
+
bool hasAlpha = false;
|
|
50
|
+
for (auto &join : baton->join) {
|
|
51
|
+
std::tie(image, inputImageType) = sharp::OpenInput(join);
|
|
52
|
+
image = sharp::EnsureColourspace(image, baton->colourspacePipeline);
|
|
53
|
+
images.push_back(image);
|
|
54
|
+
hasAlpha |= image.has_alpha();
|
|
55
|
+
}
|
|
56
|
+
if (hasAlpha) {
|
|
57
|
+
for (auto &image : images) {
|
|
58
|
+
if (!image.has_alpha()) {
|
|
59
|
+
image = sharp::EnsureAlpha(image, 1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
baton->input->joinBackground.pop_back();
|
|
64
|
+
}
|
|
65
|
+
inputImageType = sharp::ImageType::PNG;
|
|
66
|
+
image = VImage::arrayjoin(images, VImage::option()
|
|
67
|
+
->set("across", baton->input->joinAcross)
|
|
68
|
+
->set("shim", baton->input->joinShim)
|
|
69
|
+
->set("background", baton->input->joinBackground)
|
|
70
|
+
->set("halign", baton->input->joinHalign)
|
|
71
|
+
->set("valign", baton->input->joinValign));
|
|
72
|
+
if (baton->input->joinAnimated) {
|
|
73
|
+
image = image.copy();
|
|
74
|
+
image.set(VIPS_META_N_PAGES, static_cast<int>(images.size()));
|
|
75
|
+
image.set(VIPS_META_PAGE_HEIGHT, static_cast<int>(image.height() / images.size()));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
56
78
|
VipsAccess access = baton->input->access;
|
|
57
79
|
image = sharp::EnsureColourspace(image, baton->colourspacePipeline);
|
|
58
80
|
|
|
@@ -73,14 +95,14 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
73
95
|
bool autoFlip = false;
|
|
74
96
|
bool autoFlop = false;
|
|
75
97
|
|
|
76
|
-
if (baton->
|
|
98
|
+
if (baton->input->autoOrient) {
|
|
77
99
|
// Rotate and flip image according to Exif orientation
|
|
78
100
|
std::tie(autoRotation, autoFlip, autoFlop) = CalculateExifRotationAndFlip(sharp::ExifOrientation(image));
|
|
79
101
|
image = sharp::RemoveExifOrientation(image);
|
|
80
|
-
} else {
|
|
81
|
-
rotation = CalculateAngleRotation(baton->angle);
|
|
82
102
|
}
|
|
83
103
|
|
|
104
|
+
rotation = CalculateAngleRotation(baton->angle);
|
|
105
|
+
|
|
84
106
|
// Rotate pre-extract
|
|
85
107
|
bool const shouldRotateBefore = baton->rotateBeforePreExtract &&
|
|
86
108
|
(rotation != VIPS_ANGLE_D0 || autoRotation != VIPS_ANGLE_D0 ||
|
|
@@ -102,18 +124,14 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
102
124
|
image = image.rot(autoRotation);
|
|
103
125
|
autoRotation = VIPS_ANGLE_D0;
|
|
104
126
|
}
|
|
105
|
-
if (autoFlip) {
|
|
127
|
+
if (autoFlip != baton->flip) {
|
|
106
128
|
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
107
129
|
autoFlip = false;
|
|
108
|
-
} else if (baton->flip) {
|
|
109
|
-
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
110
130
|
baton->flip = false;
|
|
111
131
|
}
|
|
112
|
-
if (autoFlop) {
|
|
132
|
+
if (autoFlop != baton->flop) {
|
|
113
133
|
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
114
134
|
autoFlop = false;
|
|
115
|
-
} else if (baton->flop) {
|
|
116
|
-
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
117
135
|
baton->flop = false;
|
|
118
136
|
}
|
|
119
137
|
if (rotation != VIPS_ANGLE_D0) {
|
|
@@ -354,7 +372,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
354
372
|
}
|
|
355
373
|
|
|
356
374
|
// Flatten image to remove alpha channel
|
|
357
|
-
if (baton->flatten &&
|
|
375
|
+
if (baton->flatten && image.has_alpha()) {
|
|
358
376
|
image = sharp::Flatten(image, baton->flattenBackground);
|
|
359
377
|
}
|
|
360
378
|
|
|
@@ -374,12 +392,12 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
374
392
|
bool const shouldSharpen = baton->sharpenSigma != 0.0;
|
|
375
393
|
bool const shouldComposite = !baton->composite.empty();
|
|
376
394
|
|
|
377
|
-
if (shouldComposite && !
|
|
395
|
+
if (shouldComposite && !image.has_alpha()) {
|
|
378
396
|
image = sharp::EnsureAlpha(image, 1);
|
|
379
397
|
}
|
|
380
398
|
|
|
381
399
|
VipsBandFormat premultiplyFormat = image.format();
|
|
382
|
-
bool const shouldPremultiplyAlpha =
|
|
400
|
+
bool const shouldPremultiplyAlpha = image.has_alpha() &&
|
|
383
401
|
(shouldResize || shouldBlur || shouldConv || shouldSharpen);
|
|
384
402
|
|
|
385
403
|
if (shouldPremultiplyAlpha) {
|
|
@@ -406,11 +424,11 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
406
424
|
image = image.rot(autoRotation);
|
|
407
425
|
}
|
|
408
426
|
// Mirror vertically (up-down) about the x-axis
|
|
409
|
-
if (baton->flip
|
|
427
|
+
if (baton->flip != autoFlip) {
|
|
410
428
|
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
411
429
|
}
|
|
412
430
|
// Mirror horizontally (left-right) about the y-axis
|
|
413
|
-
if (baton->flop
|
|
431
|
+
if (baton->flop != autoFlop) {
|
|
414
432
|
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
415
433
|
}
|
|
416
434
|
// Rotate post-extract 90-angle
|
|
@@ -591,6 +609,16 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
591
609
|
image = sharp::Threshold(image, baton->threshold, baton->thresholdGrayscale);
|
|
592
610
|
}
|
|
593
611
|
|
|
612
|
+
// Dilate - must happen before blurring, due to the utility of dilating after thresholding
|
|
613
|
+
if (baton->dilateWidth != 0) {
|
|
614
|
+
image = sharp::Dilate(image, baton->dilateWidth);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Erode - must happen before blurring, due to the utility of eroding after thresholding
|
|
618
|
+
if (baton->erodeWidth != 0) {
|
|
619
|
+
image = sharp::Erode(image, baton->erodeWidth);
|
|
620
|
+
}
|
|
621
|
+
|
|
594
622
|
// Blur
|
|
595
623
|
if (shouldBlur) {
|
|
596
624
|
image = sharp::Blur(image, baton->blurSigma, baton->precision, baton->minAmpl);
|
|
@@ -641,6 +669,30 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
641
669
|
composite->input->access = access;
|
|
642
670
|
std::tie(compositeImage, compositeImageType) = sharp::OpenInput(composite->input);
|
|
643
671
|
compositeImage = sharp::EnsureColourspace(compositeImage, baton->colourspacePipeline);
|
|
672
|
+
|
|
673
|
+
if (composite->input->autoOrient) {
|
|
674
|
+
// Respect EXIF Orientation
|
|
675
|
+
VipsAngle compositeAutoRotation = VIPS_ANGLE_D0;
|
|
676
|
+
bool compositeAutoFlip = false;
|
|
677
|
+
bool compositeAutoFlop = false;
|
|
678
|
+
std::tie(compositeAutoRotation, compositeAutoFlip, compositeAutoFlop) =
|
|
679
|
+
CalculateExifRotationAndFlip(sharp::ExifOrientation(compositeImage));
|
|
680
|
+
|
|
681
|
+
compositeImage = sharp::RemoveExifOrientation(compositeImage);
|
|
682
|
+
compositeImage = sharp::StaySequential(compositeImage,
|
|
683
|
+
compositeAutoRotation != VIPS_ANGLE_D0 || compositeAutoFlip);
|
|
684
|
+
|
|
685
|
+
if (compositeAutoRotation != VIPS_ANGLE_D0) {
|
|
686
|
+
compositeImage = compositeImage.rot(compositeAutoRotation);
|
|
687
|
+
}
|
|
688
|
+
if (compositeAutoFlip) {
|
|
689
|
+
compositeImage = compositeImage.flip(VIPS_DIRECTION_VERTICAL);
|
|
690
|
+
}
|
|
691
|
+
if (compositeAutoFlop) {
|
|
692
|
+
compositeImage = compositeImage.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
644
696
|
// Verify within current dimensions
|
|
645
697
|
if (compositeImage.width() > image.width() || compositeImage.height() > image.height()) {
|
|
646
698
|
throw vips::VError("Image to composite must have same dimensions or smaller");
|
|
@@ -683,9 +735,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
683
735
|
}
|
|
684
736
|
// Ensure image to composite is sRGB with unpremultiplied alpha
|
|
685
737
|
compositeImage = compositeImage.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
686
|
-
|
|
687
|
-
compositeImage = sharp::EnsureAlpha(compositeImage, 1);
|
|
688
|
-
}
|
|
738
|
+
compositeImage = sharp::EnsureAlpha(compositeImage, 1);
|
|
689
739
|
if (composite->premultiplied) compositeImage = compositeImage.unpremultiply();
|
|
690
740
|
// Calculate position
|
|
691
741
|
int left;
|
|
@@ -786,7 +836,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
786
836
|
// Extract channel
|
|
787
837
|
if (baton->extractChannel > -1) {
|
|
788
838
|
if (baton->extractChannel >= image.bands()) {
|
|
789
|
-
if (baton->extractChannel == 3 &&
|
|
839
|
+
if (baton->extractChannel == 3 && image.has_alpha()) {
|
|
790
840
|
baton->extractChannel = image.bands() - 1;
|
|
791
841
|
} else {
|
|
792
842
|
(baton->err)
|
|
@@ -929,6 +979,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
929
979
|
->set("lossless", baton->webpLossless)
|
|
930
980
|
->set("near_lossless", baton->webpNearLossless)
|
|
931
981
|
->set("smart_subsample", baton->webpSmartSubsample)
|
|
982
|
+
->set("smart_deblock", baton->webpSmartDeblock)
|
|
932
983
|
->set("preset", baton->webpPreset)
|
|
933
984
|
->set("effort", baton->webpEffort)
|
|
934
985
|
->set("min_size", baton->webpMinSize)
|
|
@@ -991,7 +1042,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
991
1042
|
(baton->formatOut == "input" && inputImageType == sharp::ImageType::HEIF)) {
|
|
992
1043
|
// Write HEIF to buffer
|
|
993
1044
|
sharp::AssertImageTypeDimensions(image, sharp::ImageType::HEIF);
|
|
994
|
-
image = sharp::RemoveAnimationProperties(image)
|
|
1045
|
+
image = sharp::RemoveAnimationProperties(image);
|
|
995
1046
|
VipsArea *area = reinterpret_cast<VipsArea*>(image.heifsave_buffer(VImage::option()
|
|
996
1047
|
->set("keep", baton->keepMetadata)
|
|
997
1048
|
->set("Q", baton->heifQuality)
|
|
@@ -1009,7 +1060,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1009
1060
|
} else if (baton->formatOut == "dz") {
|
|
1010
1061
|
// Write DZ to buffer
|
|
1011
1062
|
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
|
1012
|
-
if (!
|
|
1063
|
+
if (!image.has_alpha()) {
|
|
1013
1064
|
baton->tileBackground.pop_back();
|
|
1014
1065
|
}
|
|
1015
1066
|
image = sharp::StaySequential(image, baton->tileAngle != 0);
|
|
@@ -1058,6 +1109,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1058
1109
|
// Unsupported output format
|
|
1059
1110
|
(baton->err).append("Unsupported output format ");
|
|
1060
1111
|
if (baton->formatOut == "input") {
|
|
1112
|
+
(baton->err).append("when trying to match input format of ");
|
|
1061
1113
|
(baton->err).append(ImageTypeId(inputImageType));
|
|
1062
1114
|
} else {
|
|
1063
1115
|
(baton->err).append(baton->formatOut);
|
|
@@ -1136,6 +1188,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1136
1188
|
->set("lossless", baton->webpLossless)
|
|
1137
1189
|
->set("near_lossless", baton->webpNearLossless)
|
|
1138
1190
|
->set("smart_subsample", baton->webpSmartSubsample)
|
|
1191
|
+
->set("smart_deblock", baton->webpSmartDeblock)
|
|
1139
1192
|
->set("preset", baton->webpPreset)
|
|
1140
1193
|
->set("effort", baton->webpEffort)
|
|
1141
1194
|
->set("min_size", baton->webpMinSize)
|
|
@@ -1184,7 +1237,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1184
1237
|
(willMatchInput && inputImageType == sharp::ImageType::HEIF)) {
|
|
1185
1238
|
// Write HEIF to file
|
|
1186
1239
|
sharp::AssertImageTypeDimensions(image, sharp::ImageType::HEIF);
|
|
1187
|
-
image = sharp::RemoveAnimationProperties(image)
|
|
1240
|
+
image = sharp::RemoveAnimationProperties(image);
|
|
1188
1241
|
image.heifsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
1189
1242
|
->set("keep", baton->keepMetadata)
|
|
1190
1243
|
->set("Q", baton->heifQuality)
|
|
@@ -1211,7 +1264,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1211
1264
|
if (isDzZip) {
|
|
1212
1265
|
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
|
1213
1266
|
}
|
|
1214
|
-
if (!
|
|
1267
|
+
if (!image.has_alpha()) {
|
|
1215
1268
|
baton->tileBackground.pop_back();
|
|
1216
1269
|
}
|
|
1217
1270
|
image = sharp::StaySequential(image, baton->tileAngle != 0);
|
|
@@ -1304,9 +1357,11 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1304
1357
|
Callback().Call(Receiver().Value(), { env.Null(), data, info });
|
|
1305
1358
|
} else {
|
|
1306
1359
|
// Add file size to info
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1360
|
+
if (baton->formatOut != "dz" || sharp::IsDzZip(baton->fileOut)) {
|
|
1361
|
+
try {
|
|
1362
|
+
uint32_t const size = static_cast<uint32_t>(std::filesystem::file_size(baton->fileOut));
|
|
1363
|
+
info.Set("size", size);
|
|
1364
|
+
} catch (...) {}
|
|
1310
1365
|
}
|
|
1311
1366
|
Callback().Call(Receiver().Value(), { env.Null(), info });
|
|
1312
1367
|
}
|
|
@@ -1324,6 +1379,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1324
1379
|
for (sharp::InputDescriptor *input : baton->joinChannelIn) {
|
|
1325
1380
|
delete input;
|
|
1326
1381
|
}
|
|
1382
|
+
for (sharp::InputDescriptor *input : baton->join) {
|
|
1383
|
+
delete input;
|
|
1384
|
+
}
|
|
1327
1385
|
delete baton;
|
|
1328
1386
|
|
|
1329
1387
|
// Decrement processing task counter
|
|
@@ -1419,6 +1477,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1419
1477
|
{"lossless", baton->webpLossless ? "true" : "false"},
|
|
1420
1478
|
{"near_lossless", baton->webpNearLossless ? "true" : "false"},
|
|
1421
1479
|
{"smart_subsample", baton->webpSmartSubsample ? "true" : "false"},
|
|
1480
|
+
{"smart_deblock", baton->webpSmartDeblock ? "true" : "false"},
|
|
1422
1481
|
{"preset", vips_enum_nick(VIPS_TYPE_FOREIGN_WEBP_PRESET, baton->webpPreset)},
|
|
1423
1482
|
{"min_size", baton->webpMinSize ? "true" : "false"},
|
|
1424
1483
|
{"mixed", baton->webpMixed ? "true" : "false"},
|
|
@@ -1480,6 +1539,14 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1480
1539
|
|
|
1481
1540
|
// Input
|
|
1482
1541
|
baton->input = sharp::CreateInputDescriptor(options.Get("input").As<Napi::Object>());
|
|
1542
|
+
// Join images together
|
|
1543
|
+
if (sharp::HasAttr(options, "join")) {
|
|
1544
|
+
Napi::Array join = options.Get("join").As<Napi::Array>();
|
|
1545
|
+
for (unsigned int i = 0; i < join.Length(); i++) {
|
|
1546
|
+
baton->join.push_back(
|
|
1547
|
+
sharp::CreateInputDescriptor(join.Get(i).As<Napi::Object>()));
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1483
1550
|
// Extract image options
|
|
1484
1551
|
baton->topOffsetPre = sharp::AttrAsInt32(options, "topOffsetPre");
|
|
1485
1552
|
baton->leftOffsetPre = sharp::AttrAsInt32(options, "leftOffsetPre");
|
|
@@ -1564,6 +1631,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1564
1631
|
baton->gammaOut = sharp::AttrAsDouble(options, "gammaOut");
|
|
1565
1632
|
baton->linearA = sharp::AttrAsVectorOfDouble(options, "linearA");
|
|
1566
1633
|
baton->linearB = sharp::AttrAsVectorOfDouble(options, "linearB");
|
|
1634
|
+
baton->dilateWidth = sharp::AttrAsUint32(options, "dilateWidth");
|
|
1635
|
+
baton->erodeWidth = sharp::AttrAsUint32(options, "erodeWidth");
|
|
1567
1636
|
baton->greyscale = sharp::AttrAsBool(options, "greyscale");
|
|
1568
1637
|
baton->normalise = sharp::AttrAsBool(options, "normalise");
|
|
1569
1638
|
baton->normaliseLower = sharp::AttrAsUint32(options, "normaliseLower");
|
|
@@ -1572,7 +1641,6 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1572
1641
|
baton->claheWidth = sharp::AttrAsUint32(options, "claheWidth");
|
|
1573
1642
|
baton->claheHeight = sharp::AttrAsUint32(options, "claheHeight");
|
|
1574
1643
|
baton->claheMaxSlope = sharp::AttrAsUint32(options, "claheMaxSlope");
|
|
1575
|
-
baton->useExifOrientation = sharp::AttrAsBool(options, "useExifOrientation");
|
|
1576
1644
|
baton->angle = sharp::AttrAsInt32(options, "angle");
|
|
1577
1645
|
baton->rotationAngle = sharp::AttrAsDouble(options, "rotationAngle");
|
|
1578
1646
|
baton->rotationBackground = sharp::AttrAsVectorOfDouble(options, "rotationBackground");
|
|
@@ -1649,6 +1717,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1649
1717
|
}
|
|
1650
1718
|
baton->withExifMerge = sharp::AttrAsBool(options, "withExifMerge");
|
|
1651
1719
|
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
|
|
1720
|
+
baton->loop = sharp::AttrAsUint32(options, "loop");
|
|
1721
|
+
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
|
1652
1722
|
// Format-specific
|
|
1653
1723
|
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
|
|
1654
1724
|
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
|
|
@@ -1676,6 +1746,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1676
1746
|
baton->webpLossless = sharp::AttrAsBool(options, "webpLossless");
|
|
1677
1747
|
baton->webpNearLossless = sharp::AttrAsBool(options, "webpNearLossless");
|
|
1678
1748
|
baton->webpSmartSubsample = sharp::AttrAsBool(options, "webpSmartSubsample");
|
|
1749
|
+
baton->webpSmartDeblock = sharp::AttrAsBool(options, "webpSmartDeblock");
|
|
1679
1750
|
baton->webpPreset = sharp::AttrAsEnum<VipsForeignWebpPreset>(options, "webpPreset", VIPS_TYPE_FOREIGN_WEBP_PRESET);
|
|
1680
1751
|
baton->webpEffort = sharp::AttrAsUint32(options, "webpEffort");
|
|
1681
1752
|
baton->webpMinSize = sharp::AttrAsBool(options, "webpMinSize");
|
|
@@ -1717,13 +1788,6 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1717
1788
|
baton->jxlEffort = sharp::AttrAsUint32(options, "jxlEffort");
|
|
1718
1789
|
baton->jxlLossless = sharp::AttrAsBool(options, "jxlLossless");
|
|
1719
1790
|
baton->rawDepth = sharp::AttrAsEnum<VipsBandFormat>(options, "rawDepth", VIPS_TYPE_BAND_FORMAT);
|
|
1720
|
-
// Animated output properties
|
|
1721
|
-
if (sharp::HasAttr(options, "loop")) {
|
|
1722
|
-
baton->loop = sharp::AttrAsUint32(options, "loop");
|
|
1723
|
-
}
|
|
1724
|
-
if (sharp::HasAttr(options, "delay")) {
|
|
1725
|
-
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
|
1726
|
-
}
|
|
1727
1791
|
baton->tileSize = sharp::AttrAsUint32(options, "tileSize");
|
|
1728
1792
|
baton->tileOverlap = sharp::AttrAsUint32(options, "tileOverlap");
|
|
1729
1793
|
baton->tileAngle = sharp::AttrAsInt32(options, "tileAngle");
|
package/src/pipeline.h
CHANGED
|
@@ -39,6 +39,7 @@ struct Composite {
|
|
|
39
39
|
|
|
40
40
|
struct PipelineBaton {
|
|
41
41
|
sharp::InputDescriptor *input;
|
|
42
|
+
std::vector<sharp::InputDescriptor *> join;
|
|
42
43
|
std::string formatOut;
|
|
43
44
|
std::string fileOut;
|
|
44
45
|
void *bufferOut;
|
|
@@ -100,6 +101,8 @@ struct PipelineBaton {
|
|
|
100
101
|
int trimOffsetTop;
|
|
101
102
|
std::vector<double> linearA;
|
|
102
103
|
std::vector<double> linearB;
|
|
104
|
+
int dilateWidth;
|
|
105
|
+
int erodeWidth;
|
|
103
106
|
double gamma;
|
|
104
107
|
double gammaOut;
|
|
105
108
|
bool greyscale;
|
|
@@ -109,7 +112,6 @@ struct PipelineBaton {
|
|
|
109
112
|
int claheWidth;
|
|
110
113
|
int claheHeight;
|
|
111
114
|
int claheMaxSlope;
|
|
112
|
-
bool useExifOrientation;
|
|
113
115
|
int angle;
|
|
114
116
|
double rotationAngle;
|
|
115
117
|
std::vector<double> rotationBackground;
|
|
@@ -157,6 +159,7 @@ struct PipelineBaton {
|
|
|
157
159
|
bool webpNearLossless;
|
|
158
160
|
bool webpLossless;
|
|
159
161
|
bool webpSmartSubsample;
|
|
162
|
+
bool webpSmartDeblock;
|
|
160
163
|
VipsForeignWebpPreset webpPreset;
|
|
161
164
|
int webpEffort;
|
|
162
165
|
bool webpMinSize;
|
|
@@ -273,6 +276,8 @@ struct PipelineBaton {
|
|
|
273
276
|
trimOffsetTop(0),
|
|
274
277
|
linearA{},
|
|
275
278
|
linearB{},
|
|
279
|
+
dilateWidth(0),
|
|
280
|
+
erodeWidth(0),
|
|
276
281
|
gamma(0.0),
|
|
277
282
|
greyscale(false),
|
|
278
283
|
normalise(false),
|
|
@@ -281,7 +286,6 @@ struct PipelineBaton {
|
|
|
281
286
|
claheWidth(0),
|
|
282
287
|
claheHeight(0),
|
|
283
288
|
claheMaxSlope(3),
|
|
284
|
-
useExifOrientation(false),
|
|
285
289
|
angle(0),
|
|
286
290
|
rotationAngle(0.0),
|
|
287
291
|
rotationBackground{ 0.0, 0.0, 0.0, 255.0 },
|
|
@@ -328,6 +332,7 @@ struct PipelineBaton {
|
|
|
328
332
|
webpNearLossless(false),
|
|
329
333
|
webpLossless(false),
|
|
330
334
|
webpSmartSubsample(false),
|
|
335
|
+
webpSmartDeblock(false),
|
|
331
336
|
webpPreset(VIPS_FOREIGN_WEBP_PRESET_DEFAULT),
|
|
332
337
|
webpEffort(4),
|
|
333
338
|
webpMinSize(false),
|
|
@@ -379,7 +384,7 @@ struct PipelineBaton {
|
|
|
379
384
|
ensureAlpha(-1.0),
|
|
380
385
|
colourspacePipeline(VIPS_INTERPRETATION_LAST),
|
|
381
386
|
colourspace(VIPS_INTERPRETATION_LAST),
|
|
382
|
-
loop(
|
|
387
|
+
loop(1),
|
|
383
388
|
tileSize(256),
|
|
384
389
|
tileOverlap(0),
|
|
385
390
|
tileContainer(VIPS_FOREIGN_DZ_CONTAINER_FS),
|
package/src/sharp.cc
CHANGED
|
@@ -33,6 +33,7 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
|
|
|
33
33
|
exports.Set("block", Napi::Function::New(env, block));
|
|
34
34
|
exports.Set("_maxColourDistance", Napi::Function::New(env, _maxColourDistance));
|
|
35
35
|
exports.Set("_isUsingJemalloc", Napi::Function::New(env, _isUsingJemalloc));
|
|
36
|
+
exports.Set("_isUsingX64V2", Napi::Function::New(env, _isUsingX64V2));
|
|
36
37
|
exports.Set("stats", Napi::Function::New(env, stats));
|
|
37
38
|
return exports;
|
|
38
39
|
}
|
package/src/stats.cc
CHANGED
|
@@ -58,7 +58,7 @@ class StatsWorker : public Napi::AsyncWorker {
|
|
|
58
58
|
baton->channelStats.push_back(cStats);
|
|
59
59
|
}
|
|
60
60
|
// Image is not opaque when alpha layer is present and contains a non-mamixa value
|
|
61
|
-
if (
|
|
61
|
+
if (image.has_alpha()) {
|
|
62
62
|
double const minAlpha = static_cast<double>(stats.getpoint(STAT_MIN_INDEX, bands).front());
|
|
63
63
|
if (minAlpha != sharp::MaximumImageAlpha(image.interpretation())) {
|
|
64
64
|
baton->isOpaque = false;
|
package/src/utilities.cc
CHANGED
|
@@ -119,7 +119,7 @@ Napi::Value format(const Napi::CallbackInfo& info) {
|
|
|
119
119
|
Napi::Object format = Napi::Object::New(env);
|
|
120
120
|
for (std::string const f : {
|
|
121
121
|
"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz",
|
|
122
|
-
"ppm", "fits", "gif", "svg", "heif", "pdf", "vips", "jp2k", "jxl"
|
|
122
|
+
"ppm", "fits", "gif", "svg", "heif", "pdf", "vips", "jp2k", "jxl", "rad"
|
|
123
123
|
}) {
|
|
124
124
|
// Input
|
|
125
125
|
const VipsObjectClass *oc = vips_class_find("VipsOperation", (f + "load").c_str());
|
|
@@ -233,10 +233,10 @@ Napi::Value _maxColourDistance(const Napi::CallbackInfo& info) {
|
|
|
233
233
|
double maxColourDistance;
|
|
234
234
|
try {
|
|
235
235
|
// Premultiply and remove alpha
|
|
236
|
-
if (
|
|
236
|
+
if (image1.has_alpha()) {
|
|
237
237
|
image1 = image1.premultiply().extract_band(1, VImage::option()->set("n", image1.bands() - 1));
|
|
238
238
|
}
|
|
239
|
-
if (
|
|
239
|
+
if (image2.has_alpha()) {
|
|
240
240
|
image2 = image2.premultiply().extract_band(1, VImage::option()->set("n", image2.bands() - 1));
|
|
241
241
|
}
|
|
242
242
|
// Calculate colour distance
|
|
@@ -267,3 +267,20 @@ Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
|
|
|
267
267
|
return Napi::Boolean::New(env, false);
|
|
268
268
|
}
|
|
269
269
|
#endif
|
|
270
|
+
|
|
271
|
+
#if defined(__GNUC__) && defined(__x86_64__)
|
|
272
|
+
// Are SSE 4.2 intrinsics available at runtime?
|
|
273
|
+
Napi::Value _isUsingX64V2(const Napi::CallbackInfo& info) {
|
|
274
|
+
Napi::Env env = info.Env();
|
|
275
|
+
unsigned int eax, ebx, ecx, edx;
|
|
276
|
+
__asm__ __volatile__("cpuid"
|
|
277
|
+
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
|
|
278
|
+
: "a"(1));
|
|
279
|
+
return Napi::Boolean::New(env, (ecx & 1U << 20) != 0);
|
|
280
|
+
}
|
|
281
|
+
#else
|
|
282
|
+
Napi::Value _isUsingX64V2(const Napi::CallbackInfo& info) {
|
|
283
|
+
Napi::Env env = info.Env();
|
|
284
|
+
return Napi::Boolean::New(env, false);
|
|
285
|
+
}
|
|
286
|
+
#endif
|
package/src/utilities.h
CHANGED
|
@@ -15,5 +15,6 @@ Napi::Value format(const Napi::CallbackInfo& info);
|
|
|
15
15
|
void block(const Napi::CallbackInfo& info);
|
|
16
16
|
Napi::Value _maxColourDistance(const Napi::CallbackInfo& info);
|
|
17
17
|
Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info);
|
|
18
|
+
Napi::Value _isUsingX64V2(const Napi::CallbackInfo& info);
|
|
18
19
|
|
|
19
20
|
#endif // SRC_UTILITIES_H_
|