sharp 0.27.1 → 0.28.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 +14 -13
- package/binding.gyp +3 -5
- package/install/dll-copy.js +4 -4
- package/install/libvips.js +85 -38
- package/lib/agent.js +1 -1
- package/lib/channel.js +25 -7
- package/lib/constructor.js +10 -6
- package/lib/input.js +19 -3
- package/lib/libvips.js +27 -4
- package/lib/operation.js +9 -4
- package/lib/output.js +129 -43
- package/lib/resize.js +42 -15
- package/lib/utility.js +17 -10
- package/package.json +14 -13
- package/src/common.cc +25 -11
- package/src/common.h +8 -3
- package/src/metadata.cc +6 -0
- package/src/metadata.h +2 -0
- package/src/operations.cc +1 -1
- package/src/pipeline.cc +42 -9
- package/src/pipeline.h +8 -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
|
@@ -149,8 +149,8 @@ namespace sharp {
|
|
|
149
149
|
*/
|
|
150
150
|
VImage Recomb(VImage image, std::unique_ptr<double[]> const &matrix) {
|
|
151
151
|
double *m = matrix.get();
|
|
152
|
+
image = image.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
152
153
|
return image
|
|
153
|
-
.colourspace(VIPS_INTERPRETATION_sRGB)
|
|
154
154
|
.recomb(image.bands() == 3
|
|
155
155
|
? VImage::new_from_memory(
|
|
156
156
|
m, 9 * sizeof(double), 3, 3, 1, VIPS_FORMAT_DOUBLE
|
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
|
|
230
231
|
) {
|
|
231
232
|
if (xshrink >= 8 * shrink_on_load_factor) {
|
|
232
233
|
xfactor = xfactor / 8;
|
|
@@ -346,7 +347,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
346
347
|
bool const shouldModulate = baton->brightness != 1.0 || baton->saturation != 1.0 || baton->hue != 0.0;
|
|
347
348
|
|
|
348
349
|
if (shouldComposite && !sharp::HasAlpha(image)) {
|
|
349
|
-
image = sharp::EnsureAlpha(image);
|
|
350
|
+
image = sharp::EnsureAlpha(image, 1);
|
|
350
351
|
}
|
|
351
352
|
|
|
352
353
|
bool const shouldPremultiplyAlpha = sharp::HasAlpha(image) &&
|
|
@@ -562,9 +563,17 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
562
563
|
// Use gravity in overlay
|
|
563
564
|
if (compositeImage.width() <= baton->width) {
|
|
564
565
|
across = static_cast<int>(ceil(static_cast<double>(image.width()) / compositeImage.width()));
|
|
566
|
+
// Ensure odd number of tiles across when gravity is centre, north or south
|
|
567
|
+
if (composite->gravity == 0 || composite->gravity == 1 || composite->gravity == 3) {
|
|
568
|
+
across |= 1;
|
|
569
|
+
}
|
|
565
570
|
}
|
|
566
571
|
if (compositeImage.height() <= baton->height) {
|
|
567
572
|
down = static_cast<int>(ceil(static_cast<double>(image.height()) / compositeImage.height()));
|
|
573
|
+
// Ensure odd number of tiles down when gravity is centre, east or west
|
|
574
|
+
if (composite->gravity == 0 || composite->gravity == 2 || composite->gravity == 4) {
|
|
575
|
+
down |= 1;
|
|
576
|
+
}
|
|
568
577
|
}
|
|
569
578
|
if (across != 0 || down != 0) {
|
|
570
579
|
int left;
|
|
@@ -586,7 +595,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
586
595
|
// Ensure image to composite is sRGB with premultiplied alpha
|
|
587
596
|
compositeImage = compositeImage.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
588
597
|
if (!sharp::HasAlpha(compositeImage)) {
|
|
589
|
-
compositeImage = sharp::EnsureAlpha(compositeImage);
|
|
598
|
+
compositeImage = sharp::EnsureAlpha(compositeImage, 1);
|
|
590
599
|
}
|
|
591
600
|
if (!composite->premultiplied) compositeImage = compositeImage.premultiply();
|
|
592
601
|
// Calculate position
|
|
@@ -594,8 +603,13 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
594
603
|
int top;
|
|
595
604
|
if (composite->hasOffset) {
|
|
596
605
|
// Composite image at given offsets
|
|
597
|
-
|
|
598
|
-
|
|
606
|
+
if (composite->tile) {
|
|
607
|
+
std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
|
|
608
|
+
compositeImage.width(), compositeImage.height(), composite->left, composite->top);
|
|
609
|
+
} else {
|
|
610
|
+
left = composite->left;
|
|
611
|
+
top = composite->top;
|
|
612
|
+
}
|
|
599
613
|
} else {
|
|
600
614
|
// Composite image with given gravity
|
|
601
615
|
std::tie(left, top) = sharp::CalculateCrop(image.width(), image.height(),
|
|
@@ -678,8 +692,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
678
692
|
}
|
|
679
693
|
|
|
680
694
|
// Ensure alpha channel, if missing
|
|
681
|
-
if (baton->ensureAlpha) {
|
|
682
|
-
image = sharp::EnsureAlpha(image);
|
|
695
|
+
if (baton->ensureAlpha != -1) {
|
|
696
|
+
image = sharp::EnsureAlpha(image, baton->ensureAlpha);
|
|
683
697
|
}
|
|
684
698
|
|
|
685
699
|
// Convert image to sRGB, if not already
|
|
@@ -704,11 +718,21 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
704
718
|
->set("input_profile", "srgb")
|
|
705
719
|
->set("intent", VIPS_INTENT_PERCEPTUAL));
|
|
706
720
|
}
|
|
707
|
-
|
|
708
721
|
// Override EXIF Orientation tag
|
|
709
722
|
if (baton->withMetadata && baton->withMetadataOrientation != -1) {
|
|
710
723
|
image = sharp::SetExifOrientation(image, baton->withMetadataOrientation);
|
|
711
724
|
}
|
|
725
|
+
// Override pixel density
|
|
726
|
+
if (baton->withMetadataDensity > 0) {
|
|
727
|
+
image = sharp::SetDensity(image, baton->withMetadataDensity);
|
|
728
|
+
}
|
|
729
|
+
// Metadata key/value pairs, e.g. EXIF
|
|
730
|
+
if (!baton->withMetadataStrs.empty()) {
|
|
731
|
+
image = image.copy();
|
|
732
|
+
for (const auto& s : baton->withMetadataStrs) {
|
|
733
|
+
image.set(s.first.data(), s.second.data());
|
|
734
|
+
}
|
|
735
|
+
}
|
|
712
736
|
|
|
713
737
|
// Number of channels used in output image
|
|
714
738
|
baton->channels = image.bands();
|
|
@@ -1038,6 +1062,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1038
1062
|
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
|
1039
1063
|
->set("background", baton->tileBackground)
|
|
1040
1064
|
->set("centre", baton->tileCentre)
|
|
1065
|
+
->set("id", const_cast<char*>(baton->tileId.data()))
|
|
1041
1066
|
->set("skip_blanks", baton->tileSkipBlanks);
|
|
1042
1067
|
// libvips chooses a default depth based on layout. Instead of replicating that logic here by
|
|
1043
1068
|
// not passing anything - libvips will handle choice
|
|
@@ -1327,7 +1352,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1327
1352
|
baton->affineInterpolator = vips::VInterpolate::new_from_name(sharp::AttrAsStr(options, "affineInterpolator").data());
|
|
1328
1353
|
|
|
1329
1354
|
baton->removeAlpha = sharp::AttrAsBool(options, "removeAlpha");
|
|
1330
|
-
baton->ensureAlpha = sharp::
|
|
1355
|
+
baton->ensureAlpha = sharp::AttrAsDouble(options, "ensureAlpha");
|
|
1331
1356
|
if (options.Has("boolean")) {
|
|
1332
1357
|
baton->boolean = sharp::CreateInputDescriptor(options.Get("boolean").As<Napi::Object>());
|
|
1333
1358
|
baton->booleanOp = sharp::GetBooleanOperation(sharp::AttrAsStr(options, "booleanOp"));
|
|
@@ -1364,7 +1389,14 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1364
1389
|
baton->fileOut = sharp::AttrAsStr(options, "fileOut");
|
|
1365
1390
|
baton->withMetadata = sharp::AttrAsBool(options, "withMetadata");
|
|
1366
1391
|
baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
|
|
1392
|
+
baton->withMetadataDensity = sharp::AttrAsDouble(options, "withMetadataDensity");
|
|
1367
1393
|
baton->withMetadataIcc = sharp::AttrAsStr(options, "withMetadataIcc");
|
|
1394
|
+
Napi::Object mdStrs = options.Get("withMetadataStrs").As<Napi::Object>();
|
|
1395
|
+
Napi::Array mdStrKeys = mdStrs.GetPropertyNames();
|
|
1396
|
+
for (unsigned int i = 0; i < mdStrKeys.Length(); i++) {
|
|
1397
|
+
std::string k = sharp::AttrAsStr(mdStrKeys, i);
|
|
1398
|
+
baton->withMetadataStrs.insert(std::make_pair(k, sharp::AttrAsStr(mdStrs, k)));
|
|
1399
|
+
}
|
|
1368
1400
|
// Format-specific
|
|
1369
1401
|
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
|
|
1370
1402
|
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
|
|
@@ -1438,6 +1470,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1438
1470
|
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_DEPTH,
|
|
1439
1471
|
sharp::AttrAsStr(options, "tileDepth").data()));
|
|
1440
1472
|
baton->tileCentre = sharp::AttrAsBool(options, "tileCentre");
|
|
1473
|
+
baton->tileId = sharp::AttrAsStr(options, "tileId");
|
|
1441
1474
|
|
|
1442
1475
|
// Force random access for certain operations
|
|
1443
1476
|
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>
|
|
@@ -167,7 +168,9 @@ struct PipelineBaton {
|
|
|
167
168
|
std::string err;
|
|
168
169
|
bool withMetadata;
|
|
169
170
|
int withMetadataOrientation;
|
|
171
|
+
double withMetadataDensity;
|
|
170
172
|
std::string withMetadataIcc;
|
|
173
|
+
std::unordered_map<std::string, std::string> withMetadataStrs;
|
|
171
174
|
std::unique_ptr<double[]> convKernel;
|
|
172
175
|
int convKernelWidth;
|
|
173
176
|
int convKernelHeight;
|
|
@@ -178,7 +181,7 @@ struct PipelineBaton {
|
|
|
178
181
|
VipsOperationBoolean bandBoolOp;
|
|
179
182
|
int extractChannel;
|
|
180
183
|
bool removeAlpha;
|
|
181
|
-
|
|
184
|
+
double ensureAlpha;
|
|
182
185
|
VipsInterpretation colourspace;
|
|
183
186
|
int pageHeight;
|
|
184
187
|
std::vector<int> delay;
|
|
@@ -192,6 +195,7 @@ struct PipelineBaton {
|
|
|
192
195
|
std::vector<double> tileBackground;
|
|
193
196
|
int tileSkipBlanks;
|
|
194
197
|
VipsForeignDzDepth tileDepth;
|
|
198
|
+
std::string tileId;
|
|
195
199
|
std::unique_ptr<double[]> recombMatrix;
|
|
196
200
|
|
|
197
201
|
PipelineBaton():
|
|
@@ -258,7 +262,7 @@ struct PipelineBaton {
|
|
|
258
262
|
jpegOptimiseScans(false),
|
|
259
263
|
jpegOptimiseCoding(true),
|
|
260
264
|
pngProgressive(false),
|
|
261
|
-
pngCompressionLevel(
|
|
265
|
+
pngCompressionLevel(6),
|
|
262
266
|
pngAdaptiveFiltering(false),
|
|
263
267
|
pngPalette(false),
|
|
264
268
|
pngQuality(100),
|
|
@@ -287,6 +291,7 @@ struct PipelineBaton {
|
|
|
287
291
|
heifLossless(false),
|
|
288
292
|
withMetadata(false),
|
|
289
293
|
withMetadataOrientation(-1),
|
|
294
|
+
withMetadataDensity(0.0),
|
|
290
295
|
convKernelWidth(0),
|
|
291
296
|
convKernelHeight(0),
|
|
292
297
|
convKernelScale(0.0),
|
|
@@ -296,7 +301,7 @@ struct PipelineBaton {
|
|
|
296
301
|
bandBoolOp(VIPS_OPERATION_BOOLEAN_LAST),
|
|
297
302
|
extractChannel(-1),
|
|
298
303
|
removeAlpha(false),
|
|
299
|
-
ensureAlpha(
|
|
304
|
+
ensureAlpha(-1.0),
|
|
300
305
|
colourspace(VIPS_INTERPRETATION_LAST),
|
|
301
306
|
pageHeight(0),
|
|
302
307
|
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_
|