sharp 0.27.2 → 0.28.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -13
- package/binding.gyp +3 -5
- package/install/can-compile.js +11 -0
- package/install/dll-copy.js +4 -4
- package/install/libvips.js +78 -40
- package/lib/agent.js +1 -1
- package/lib/channel.js +27 -7
- package/lib/composite.js +2 -0
- package/lib/constructor.js +12 -5
- package/lib/input.js +19 -3
- package/lib/libvips.js +14 -3
- package/lib/operation.js +54 -5
- package/lib/output.js +111 -25
- package/lib/resize.js +42 -15
- package/lib/utility.js +13 -2
- package/package.json +17 -15
- package/src/common.cc +24 -5
- package/src/common.h +8 -3
- package/src/metadata.cc +6 -0
- package/src/metadata.h +2 -0
- package/src/operations.cc +7 -0
- package/src/operations.h +5 -0
- package/src/pipeline.cc +51 -9
- package/src/pipeline.h +14 -3
- package/src/sharp.cc +1 -0
- package/src/utilities.cc +16 -0
- package/src/utilities.h +1 -0
package/src/common.h
CHANGED
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
|
|
27
27
|
#if (VIPS_MAJOR_VERSION < 8) || \
|
|
28
28
|
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 10) || \
|
|
29
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 10 && VIPS_MICRO_VERSION <
|
|
30
|
-
#error "libvips version 8.10.
|
|
29
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 10 && VIPS_MICRO_VERSION < 6)
|
|
30
|
+
#error "libvips version 8.10.6+ is required - please see https://sharp.pixelplumbing.com/install"
|
|
31
31
|
#endif
|
|
32
32
|
|
|
33
33
|
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
|
@@ -57,9 +57,11 @@ namespace sharp {
|
|
|
57
57
|
int rawChannels;
|
|
58
58
|
int rawWidth;
|
|
59
59
|
int rawHeight;
|
|
60
|
+
bool rawPremultiplied;
|
|
60
61
|
int pages;
|
|
61
62
|
int page;
|
|
62
63
|
int level;
|
|
64
|
+
int subifd;
|
|
63
65
|
int createChannels;
|
|
64
66
|
int createWidth;
|
|
65
67
|
int createHeight;
|
|
@@ -79,9 +81,11 @@ namespace sharp {
|
|
|
79
81
|
rawChannels(0),
|
|
80
82
|
rawWidth(0),
|
|
81
83
|
rawHeight(0),
|
|
84
|
+
rawPremultiplied(false),
|
|
82
85
|
pages(1),
|
|
83
86
|
page(0),
|
|
84
87
|
level(0),
|
|
88
|
+
subifd(-1),
|
|
85
89
|
createChannels(0),
|
|
86
90
|
createWidth(0),
|
|
87
91
|
createHeight(0),
|
|
@@ -93,6 +97,7 @@ namespace sharp {
|
|
|
93
97
|
// Convenience methods to access the attributes of a Napi::Object
|
|
94
98
|
bool HasAttr(Napi::Object obj, std::string attr);
|
|
95
99
|
std::string AttrAsStr(Napi::Object obj, std::string attr);
|
|
100
|
+
std::string AttrAsStr(Napi::Object obj, unsigned int const attr);
|
|
96
101
|
uint32_t AttrAsUint32(Napi::Object obj, std::string attr);
|
|
97
102
|
int32_t AttrAsInt32(Napi::Object obj, std::string attr);
|
|
98
103
|
int32_t AttrAsInt32(Napi::Object obj, unsigned int const attr);
|
|
@@ -296,7 +301,7 @@ namespace sharp {
|
|
|
296
301
|
/*
|
|
297
302
|
Ensures alpha channel, if missing.
|
|
298
303
|
*/
|
|
299
|
-
VImage EnsureAlpha(VImage image);
|
|
304
|
+
VImage EnsureAlpha(VImage image, double const value);
|
|
300
305
|
|
|
301
306
|
} // namespace sharp
|
|
302
307
|
|
package/src/metadata.cc
CHANGED
|
@@ -86,6 +86,9 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
86
86
|
baton->levels.push_back(std::pair<int, int>(width, height));
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
if (image.get_typeof(VIPS_META_N_SUBIFDS) == G_TYPE_INT) {
|
|
90
|
+
baton->subifds = image.get_int(VIPS_META_N_SUBIFDS);
|
|
91
|
+
}
|
|
89
92
|
baton->hasProfile = sharp::HasProfile(image);
|
|
90
93
|
// Derived attributes
|
|
91
94
|
baton->hasAlpha = sharp::HasAlpha(image);
|
|
@@ -203,6 +206,9 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
203
206
|
}
|
|
204
207
|
info.Set("levels", levels);
|
|
205
208
|
}
|
|
209
|
+
if (baton->subifds > 0) {
|
|
210
|
+
info.Set("subifds", baton->subifds);
|
|
211
|
+
}
|
|
206
212
|
info.Set("hasProfile", baton->hasProfile);
|
|
207
213
|
info.Set("hasAlpha", baton->hasAlpha);
|
|
208
214
|
if (baton->orientation > 0) {
|
package/src/metadata.h
CHANGED
|
@@ -41,6 +41,7 @@ struct MetadataBaton {
|
|
|
41
41
|
int pagePrimary;
|
|
42
42
|
std::string compression;
|
|
43
43
|
std::vector<std::pair<int, int>> levels;
|
|
44
|
+
int subifds;
|
|
44
45
|
bool hasProfile;
|
|
45
46
|
bool hasAlpha;
|
|
46
47
|
int orientation;
|
|
@@ -68,6 +69,7 @@ struct MetadataBaton {
|
|
|
68
69
|
pageHeight(0),
|
|
69
70
|
loop(-1),
|
|
70
71
|
pagePrimary(-1),
|
|
72
|
+
subifds(0),
|
|
71
73
|
hasProfile(false),
|
|
72
74
|
hasAlpha(false),
|
|
73
75
|
orientation(0),
|
package/src/operations.cc
CHANGED
|
@@ -92,6 +92,13 @@ namespace sharp {
|
|
|
92
92
|
return image;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/*
|
|
96
|
+
* Contrast limiting adapative histogram equalization (CLAHE)
|
|
97
|
+
*/
|
|
98
|
+
VImage Clahe(VImage image, int const width, int const height, int const maxSlope) {
|
|
99
|
+
return image.hist_local(width, height, VImage::option()->set("max_slope", maxSlope));
|
|
100
|
+
}
|
|
101
|
+
|
|
95
102
|
/*
|
|
96
103
|
* Gamma encoding/decoding
|
|
97
104
|
*/
|
package/src/operations.h
CHANGED
|
@@ -35,6 +35,11 @@ namespace sharp {
|
|
|
35
35
|
*/
|
|
36
36
|
VImage Normalise(VImage image);
|
|
37
37
|
|
|
38
|
+
/*
|
|
39
|
+
* Contrast limiting adapative histogram equalization (CLAHE)
|
|
40
|
+
*/
|
|
41
|
+
VImage Clahe(VImage image, int const width, int const height, int const maxSlope);
|
|
42
|
+
|
|
38
43
|
/*
|
|
39
44
|
* Gamma encoding/decoding
|
|
40
45
|
*/
|
package/src/pipeline.cc
CHANGED
|
@@ -226,7 +226,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
226
226
|
if (
|
|
227
227
|
xshrink == yshrink && xshrink >= 2 * shrink_on_load_factor &&
|
|
228
228
|
(inputImageType == sharp::ImageType::JPEG || inputImageType == sharp::ImageType::WEBP) &&
|
|
229
|
-
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0
|
|
229
|
+
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0 &&
|
|
230
|
+
image.width() > 3 && image.height() > 3 && baton->input->pages == 1
|
|
230
231
|
) {
|
|
231
232
|
if (xshrink >= 8 * shrink_on_load_factor) {
|
|
232
233
|
xfactor = xfactor / 8;
|
|
@@ -344,9 +345,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
344
345
|
bool const shouldApplyMedian = baton->medianSize > 0;
|
|
345
346
|
bool const shouldComposite = !baton->composite.empty();
|
|
346
347
|
bool const shouldModulate = baton->brightness != 1.0 || baton->saturation != 1.0 || baton->hue != 0.0;
|
|
348
|
+
bool const shouldApplyClahe = baton->claheWidth != 0 && baton->claheHeight != 0;
|
|
347
349
|
|
|
348
350
|
if (shouldComposite && !sharp::HasAlpha(image)) {
|
|
349
|
-
image = sharp::EnsureAlpha(image);
|
|
351
|
+
image = sharp::EnsureAlpha(image, 1);
|
|
350
352
|
}
|
|
351
353
|
|
|
352
354
|
bool const shouldPremultiplyAlpha = sharp::HasAlpha(image) &&
|
|
@@ -562,9 +564,17 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
562
564
|
// Use gravity in overlay
|
|
563
565
|
if (compositeImage.width() <= baton->width) {
|
|
564
566
|
across = static_cast<int>(ceil(static_cast<double>(image.width()) / compositeImage.width()));
|
|
567
|
+
// Ensure odd number of tiles across when gravity is centre, north or south
|
|
568
|
+
if (composite->gravity == 0 || composite->gravity == 1 || composite->gravity == 3) {
|
|
569
|
+
across |= 1;
|
|
570
|
+
}
|
|
565
571
|
}
|
|
566
572
|
if (compositeImage.height() <= baton->height) {
|
|
567
573
|
down = static_cast<int>(ceil(static_cast<double>(image.height()) / compositeImage.height()));
|
|
574
|
+
// Ensure odd number of tiles down when gravity is centre, east or west
|
|
575
|
+
if (composite->gravity == 0 || composite->gravity == 2 || composite->gravity == 4) {
|
|
576
|
+
down |= 1;
|
|
577
|
+
}
|
|
568
578
|
}
|
|
569
579
|
if (across != 0 || down != 0) {
|
|
570
580
|
int left;
|
|
@@ -586,7 +596,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
586
596
|
// Ensure image to composite is sRGB with premultiplied alpha
|
|
587
597
|
compositeImage = compositeImage.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
588
598
|
if (!sharp::HasAlpha(compositeImage)) {
|
|
589
|
-
compositeImage = sharp::EnsureAlpha(compositeImage);
|
|
599
|
+
compositeImage = sharp::EnsureAlpha(compositeImage, 1);
|
|
590
600
|
}
|
|
591
601
|
if (!composite->premultiplied) compositeImage = compositeImage.premultiply();
|
|
592
602
|
// Calculate position
|
|
@@ -594,8 +604,13 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
594
604
|
int top;
|
|
595
605
|
if (composite->hasOffset) {
|
|
596
606
|
// Composite image at given offsets
|
|
597
|
-
|
|
598
|
-
|
|
607
|
+
if (composite->tile) {
|
|
608
|
+
std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
|
|
609
|
+
compositeImage.width(), compositeImage.height(), composite->left, composite->top);
|
|
610
|
+
} else {
|
|
611
|
+
left = composite->left;
|
|
612
|
+
top = composite->top;
|
|
613
|
+
}
|
|
599
614
|
} else {
|
|
600
615
|
// Composite image with given gravity
|
|
601
616
|
std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
|
|
@@ -636,6 +651,11 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
636
651
|
image = sharp::Normalise(image);
|
|
637
652
|
}
|
|
638
653
|
|
|
654
|
+
// Apply contrast limiting adaptive histogram equalization (CLAHE)
|
|
655
|
+
if (shouldApplyClahe) {
|
|
656
|
+
image = sharp::Clahe(image, baton->claheWidth, baton->claheHeight, baton->claheMaxSlope);
|
|
657
|
+
}
|
|
658
|
+
|
|
639
659
|
// Apply bitwise boolean operation between images
|
|
640
660
|
if (baton->boolean != nullptr) {
|
|
641
661
|
VImage booleanImage;
|
|
@@ -678,8 +698,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
678
698
|
}
|
|
679
699
|
|
|
680
700
|
// Ensure alpha channel, if missing
|
|
681
|
-
if (baton->ensureAlpha) {
|
|
682
|
-
image = sharp::EnsureAlpha(image);
|
|
701
|
+
if (baton->ensureAlpha != -1) {
|
|
702
|
+
image = sharp::EnsureAlpha(image, baton->ensureAlpha);
|
|
683
703
|
}
|
|
684
704
|
|
|
685
705
|
// Convert image to sRGB, if not already
|
|
@@ -704,11 +724,21 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
704
724
|
->set("input_profile", "srgb")
|
|
705
725
|
->set("intent", VIPS_INTENT_PERCEPTUAL));
|
|
706
726
|
}
|
|
707
|
-
|
|
708
727
|
// Override EXIF Orientation tag
|
|
709
728
|
if (baton->withMetadata && baton->withMetadataOrientation != -1) {
|
|
710
729
|
image = sharp::SetExifOrientation(image, baton->withMetadataOrientation);
|
|
711
730
|
}
|
|
731
|
+
// Override pixel density
|
|
732
|
+
if (baton->withMetadataDensity > 0) {
|
|
733
|
+
image = sharp::SetDensity(image, baton->withMetadataDensity);
|
|
734
|
+
}
|
|
735
|
+
// Metadata key/value pairs, e.g. EXIF
|
|
736
|
+
if (!baton->withMetadataStrs.empty()) {
|
|
737
|
+
image = image.copy();
|
|
738
|
+
for (const auto& s : baton->withMetadataStrs) {
|
|
739
|
+
image.set(s.first.data(), s.second.data());
|
|
740
|
+
}
|
|
741
|
+
}
|
|
712
742
|
|
|
713
743
|
// Number of channels used in output image
|
|
714
744
|
baton->channels = image.bands();
|
|
@@ -1038,6 +1068,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1038
1068
|
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
|
1039
1069
|
->set("background", baton->tileBackground)
|
|
1040
1070
|
->set("centre", baton->tileCentre)
|
|
1071
|
+
->set("id", const_cast<char*>(baton->tileId.data()))
|
|
1041
1072
|
->set("skip_blanks", baton->tileSkipBlanks);
|
|
1042
1073
|
// libvips chooses a default depth based on layout. Instead of replicating that logic here by
|
|
1043
1074
|
// not passing anything - libvips will handle choice
|
|
@@ -1305,6 +1336,9 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1305
1336
|
baton->linearB = sharp::AttrAsDouble(options, "linearB");
|
|
1306
1337
|
baton->greyscale = sharp::AttrAsBool(options, "greyscale");
|
|
1307
1338
|
baton->normalise = sharp::AttrAsBool(options, "normalise");
|
|
1339
|
+
baton->claheWidth = sharp::AttrAsUint32(options, "claheWidth");
|
|
1340
|
+
baton->claheHeight = sharp::AttrAsUint32(options, "claheHeight");
|
|
1341
|
+
baton->claheMaxSlope = sharp::AttrAsUint32(options, "claheMaxSlope");
|
|
1308
1342
|
baton->useExifOrientation = sharp::AttrAsBool(options, "useExifOrientation");
|
|
1309
1343
|
baton->angle = sharp::AttrAsInt32(options, "angle");
|
|
1310
1344
|
baton->rotationAngle = sharp::AttrAsDouble(options, "rotationAngle");
|
|
@@ -1327,7 +1361,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1327
1361
|
baton->affineInterpolator = vips::VInterpolate::new_from_name(sharp::AttrAsStr(options, "affineInterpolator").data());
|
|
1328
1362
|
|
|
1329
1363
|
baton->removeAlpha = sharp::AttrAsBool(options, "removeAlpha");
|
|
1330
|
-
baton->ensureAlpha = sharp::
|
|
1364
|
+
baton->ensureAlpha = sharp::AttrAsDouble(options, "ensureAlpha");
|
|
1331
1365
|
if (options.Has("boolean")) {
|
|
1332
1366
|
baton->boolean = sharp::CreateInputDescriptor(options.Get("boolean").As<Napi::Object>());
|
|
1333
1367
|
baton->booleanOp = sharp::GetBooleanOperation(sharp::AttrAsStr(options, "booleanOp"));
|
|
@@ -1364,7 +1398,14 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1364
1398
|
baton->fileOut = sharp::AttrAsStr(options, "fileOut");
|
|
1365
1399
|
baton->withMetadata = sharp::AttrAsBool(options, "withMetadata");
|
|
1366
1400
|
baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
|
|
1401
|
+
baton->withMetadataDensity = sharp::AttrAsDouble(options, "withMetadataDensity");
|
|
1367
1402
|
baton->withMetadataIcc = sharp::AttrAsStr(options, "withMetadataIcc");
|
|
1403
|
+
Napi::Object mdStrs = options.Get("withMetadataStrs").As<Napi::Object>();
|
|
1404
|
+
Napi::Array mdStrKeys = mdStrs.GetPropertyNames();
|
|
1405
|
+
for (unsigned int i = 0; i < mdStrKeys.Length(); i++) {
|
|
1406
|
+
std::string k = sharp::AttrAsStr(mdStrKeys, i);
|
|
1407
|
+
baton->withMetadataStrs.insert(std::make_pair(k, sharp::AttrAsStr(mdStrs, k)));
|
|
1408
|
+
}
|
|
1368
1409
|
// Format-specific
|
|
1369
1410
|
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
|
|
1370
1411
|
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
|
|
@@ -1438,6 +1479,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1438
1479
|
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_DEPTH,
|
|
1439
1480
|
sharp::AttrAsStr(options, "tileDepth").data()));
|
|
1440
1481
|
baton->tileCentre = sharp::AttrAsBool(options, "tileCentre");
|
|
1482
|
+
baton->tileId = sharp::AttrAsStr(options, "tileId");
|
|
1441
1483
|
|
|
1442
1484
|
// Force random access for certain operations
|
|
1443
1485
|
if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
|
package/src/pipeline.h
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
#include <memory>
|
|
19
19
|
#include <string>
|
|
20
20
|
#include <vector>
|
|
21
|
+
#include <unordered_map>
|
|
21
22
|
|
|
22
23
|
#include <napi.h>
|
|
23
24
|
#include <vips/vips8>
|
|
@@ -108,6 +109,9 @@ struct PipelineBaton {
|
|
|
108
109
|
double gammaOut;
|
|
109
110
|
bool greyscale;
|
|
110
111
|
bool normalise;
|
|
112
|
+
int claheWidth;
|
|
113
|
+
int claheHeight;
|
|
114
|
+
int claheMaxSlope;
|
|
111
115
|
bool useExifOrientation;
|
|
112
116
|
int angle;
|
|
113
117
|
double rotationAngle;
|
|
@@ -167,7 +171,9 @@ struct PipelineBaton {
|
|
|
167
171
|
std::string err;
|
|
168
172
|
bool withMetadata;
|
|
169
173
|
int withMetadataOrientation;
|
|
174
|
+
double withMetadataDensity;
|
|
170
175
|
std::string withMetadataIcc;
|
|
176
|
+
std::unordered_map<std::string, std::string> withMetadataStrs;
|
|
171
177
|
std::unique_ptr<double[]> convKernel;
|
|
172
178
|
int convKernelWidth;
|
|
173
179
|
int convKernelHeight;
|
|
@@ -178,7 +184,7 @@ struct PipelineBaton {
|
|
|
178
184
|
VipsOperationBoolean bandBoolOp;
|
|
179
185
|
int extractChannel;
|
|
180
186
|
bool removeAlpha;
|
|
181
|
-
|
|
187
|
+
double ensureAlpha;
|
|
182
188
|
VipsInterpretation colourspace;
|
|
183
189
|
int pageHeight;
|
|
184
190
|
std::vector<int> delay;
|
|
@@ -192,6 +198,7 @@ struct PipelineBaton {
|
|
|
192
198
|
std::vector<double> tileBackground;
|
|
193
199
|
int tileSkipBlanks;
|
|
194
200
|
VipsForeignDzDepth tileDepth;
|
|
201
|
+
std::string tileId;
|
|
195
202
|
std::unique_ptr<double[]> recombMatrix;
|
|
196
203
|
|
|
197
204
|
PipelineBaton():
|
|
@@ -230,6 +237,9 @@ struct PipelineBaton {
|
|
|
230
237
|
gamma(0.0),
|
|
231
238
|
greyscale(false),
|
|
232
239
|
normalise(false),
|
|
240
|
+
claheWidth(0),
|
|
241
|
+
claheHeight(0),
|
|
242
|
+
claheMaxSlope(3),
|
|
233
243
|
useExifOrientation(false),
|
|
234
244
|
angle(0),
|
|
235
245
|
rotationAngle(0.0),
|
|
@@ -258,7 +268,7 @@ struct PipelineBaton {
|
|
|
258
268
|
jpegOptimiseScans(false),
|
|
259
269
|
jpegOptimiseCoding(true),
|
|
260
270
|
pngProgressive(false),
|
|
261
|
-
pngCompressionLevel(
|
|
271
|
+
pngCompressionLevel(6),
|
|
262
272
|
pngAdaptiveFiltering(false),
|
|
263
273
|
pngPalette(false),
|
|
264
274
|
pngQuality(100),
|
|
@@ -287,6 +297,7 @@ struct PipelineBaton {
|
|
|
287
297
|
heifLossless(false),
|
|
288
298
|
withMetadata(false),
|
|
289
299
|
withMetadataOrientation(-1),
|
|
300
|
+
withMetadataDensity(0.0),
|
|
290
301
|
convKernelWidth(0),
|
|
291
302
|
convKernelHeight(0),
|
|
292
303
|
convKernelScale(0.0),
|
|
@@ -296,7 +307,7 @@ struct PipelineBaton {
|
|
|
296
307
|
bandBoolOp(VIPS_OPERATION_BOOLEAN_LAST),
|
|
297
308
|
extractChannel(-1),
|
|
298
309
|
removeAlpha(false),
|
|
299
|
-
ensureAlpha(
|
|
310
|
+
ensureAlpha(-1.0),
|
|
300
311
|
colourspace(VIPS_INTERPRETATION_LAST),
|
|
301
312
|
pageHeight(0),
|
|
302
313
|
delay{-1},
|
package/src/sharp.cc
CHANGED
|
@@ -44,6 +44,7 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
|
|
|
44
44
|
exports.Set("libvipsVersion", Napi::Function::New(env, libvipsVersion));
|
|
45
45
|
exports.Set("format", Napi::Function::New(env, format));
|
|
46
46
|
exports.Set("_maxColourDistance", Napi::Function::New(env, _maxColourDistance));
|
|
47
|
+
exports.Set("_isUsingJemalloc", Napi::Function::New(env, _isUsingJemalloc));
|
|
47
48
|
exports.Set("stats", Napi::Function::New(env, stats));
|
|
48
49
|
return exports;
|
|
49
50
|
}
|
package/src/utilities.cc
CHANGED
|
@@ -225,3 +225,19 @@ Napi::Value _maxColourDistance(const Napi::CallbackInfo& info) {
|
|
|
225
225
|
|
|
226
226
|
return Napi::Number::New(env, maxColourDistance);
|
|
227
227
|
}
|
|
228
|
+
|
|
229
|
+
#if defined(__GNUC__)
|
|
230
|
+
// mallctl will be resolved by the runtime linker when jemalloc is being used
|
|
231
|
+
extern "C" {
|
|
232
|
+
int mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) __attribute__((weak));
|
|
233
|
+
}
|
|
234
|
+
Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
|
|
235
|
+
Napi::Env env = info.Env();
|
|
236
|
+
return Napi::Boolean::New(env, mallctl != nullptr);
|
|
237
|
+
}
|
|
238
|
+
#else
|
|
239
|
+
Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
|
|
240
|
+
Napi::Env env = info.Env();
|
|
241
|
+
return Napi::Boolean::New(env, false);
|
|
242
|
+
}
|
|
243
|
+
#endif
|
package/src/utilities.h
CHANGED
|
@@ -24,5 +24,6 @@ Napi::Value simd(const Napi::CallbackInfo& info);
|
|
|
24
24
|
Napi::Value libvipsVersion(const Napi::CallbackInfo& info);
|
|
25
25
|
Napi::Value format(const Napi::CallbackInfo& info);
|
|
26
26
|
Napi::Value _maxColourDistance(const Napi::CallbackInfo& info);
|
|
27
|
+
Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info);
|
|
27
28
|
|
|
28
29
|
#endif // SRC_UTILITIES_H_
|