sharp 0.25.3 → 0.26.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 +1 -1
- package/binding.gyp +82 -71
- package/install/dll-copy.js +3 -1
- package/install/libvips.js +26 -14
- package/lib/channel.js +5 -8
- package/lib/constructor.js +34 -18
- package/lib/input.js +27 -5
- package/lib/is.js +4 -4
- package/lib/libvips.js +2 -8
- package/lib/output.js +130 -35
- package/lib/platform.js +2 -1
- package/lib/resize.js +2 -1
- package/lib/utility.js +1 -1
- package/package.json +22 -17
- package/src/common.cc +125 -50
- package/src/common.h +24 -2
- package/src/libvips/cplusplus/VImage.cpp +451 -450
- package/src/libvips/cplusplus/vips-operators.cpp +117 -1
- package/src/metadata.cc +20 -0
- package/src/metadata.h +1 -0
- package/src/operations.cc +0 -23
- package/src/operations.h +0 -10
- package/src/pipeline.cc +82 -13
- package/src/pipeline.h +10 -2
- package/src/stats.cc +30 -1
- package/src/stats.h +9 -1
package/src/common.cc
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
#include <string.h>
|
|
18
18
|
#include <vector>
|
|
19
19
|
#include <queue>
|
|
20
|
+
#include <map>
|
|
20
21
|
#include <mutex> // NOLINT(build/c++11)
|
|
21
22
|
|
|
22
23
|
#include <napi.h>
|
|
@@ -41,6 +42,9 @@ namespace sharp {
|
|
|
41
42
|
int32_t AttrAsInt32(Napi::Object obj, std::string attr) {
|
|
42
43
|
return obj.Get(attr).As<Napi::Number>().Int32Value();
|
|
43
44
|
}
|
|
45
|
+
int32_t AttrAsInt32(Napi::Object obj, unsigned int const attr) {
|
|
46
|
+
return obj.Get(attr).As<Napi::Number>().Int32Value();
|
|
47
|
+
}
|
|
44
48
|
double AttrAsDouble(Napi::Object obj, std::string attr) {
|
|
45
49
|
return obj.Get(attr).As<Napi::Number>().DoubleValue();
|
|
46
50
|
}
|
|
@@ -58,6 +62,14 @@ namespace sharp {
|
|
|
58
62
|
}
|
|
59
63
|
return rgba;
|
|
60
64
|
}
|
|
65
|
+
std::vector<int32_t> AttrAsInt32Vector(Napi::Object obj, std::string attr) {
|
|
66
|
+
Napi::Array array = obj.Get(attr).As<Napi::Array>();
|
|
67
|
+
std::vector<int32_t> vector(array.Length());
|
|
68
|
+
for (unsigned int i = 0; i < array.Length(); i++) {
|
|
69
|
+
vector[i] = AttrAsInt32(array, i);
|
|
70
|
+
}
|
|
71
|
+
return vector;
|
|
72
|
+
}
|
|
61
73
|
|
|
62
74
|
// Create an InputDescriptor instance from a Napi::Object describing an input image
|
|
63
75
|
InputDescriptor* CreateInputDescriptor(Napi::Object input) {
|
|
@@ -88,6 +100,10 @@ namespace sharp {
|
|
|
88
100
|
if (HasAttr(input, "page")) {
|
|
89
101
|
descriptor->page = AttrAsUint32(input, "page");
|
|
90
102
|
}
|
|
103
|
+
// Multi-level input (OpenSlide)
|
|
104
|
+
if (HasAttr(input, "level")) {
|
|
105
|
+
descriptor->level = AttrAsUint32(input, "level");
|
|
106
|
+
}
|
|
91
107
|
// Create new image
|
|
92
108
|
if (HasAttr(input, "createChannels")) {
|
|
93
109
|
descriptor->createChannels = AttrAsUint32(input, "createChannels");
|
|
@@ -121,6 +137,9 @@ namespace sharp {
|
|
|
121
137
|
bool IsWebp(std::string const &str) {
|
|
122
138
|
return EndsWith(str, ".webp") || EndsWith(str, ".WEBP");
|
|
123
139
|
}
|
|
140
|
+
bool IsGif(std::string const &str) {
|
|
141
|
+
return EndsWith(str, ".gif") || EndsWith(str, ".GIF");
|
|
142
|
+
}
|
|
124
143
|
bool IsTiff(std::string const &str) {
|
|
125
144
|
return EndsWith(str, ".tif") || EndsWith(str, ".tiff") || EndsWith(str, ".TIF") || EndsWith(str, ".TIFF");
|
|
126
145
|
}
|
|
@@ -161,6 +180,7 @@ namespace sharp {
|
|
|
161
180
|
case ImageType::OPENSLIDE: id = "openslide"; break;
|
|
162
181
|
case ImageType::PPM: id = "ppm"; break;
|
|
163
182
|
case ImageType::FITS: id = "fits"; break;
|
|
183
|
+
case ImageType::EXR: id = "exr"; break;
|
|
164
184
|
case ImageType::VIPS: id = "vips"; break;
|
|
165
185
|
case ImageType::RAW: id = "raw"; break;
|
|
166
186
|
case ImageType::UNKNOWN: id = "unknown"; break;
|
|
@@ -169,32 +189,43 @@ namespace sharp {
|
|
|
169
189
|
return id;
|
|
170
190
|
}
|
|
171
191
|
|
|
192
|
+
std::map<std::string, ImageType> loaderToType = {
|
|
193
|
+
{ "jpegload", ImageType::JPEG },
|
|
194
|
+
{ "jpegload_buffer", ImageType::JPEG },
|
|
195
|
+
{ "pngload", ImageType::PNG },
|
|
196
|
+
{ "pngload_buffer", ImageType::PNG },
|
|
197
|
+
{ "webpload", ImageType::WEBP },
|
|
198
|
+
{ "webpload_buffer", ImageType::WEBP },
|
|
199
|
+
{ "tiffload", ImageType::TIFF },
|
|
200
|
+
{ "tiffload_buffer", ImageType::TIFF },
|
|
201
|
+
{ "gifload", ImageType::GIF },
|
|
202
|
+
{ "gifload_buffer", ImageType::GIF },
|
|
203
|
+
{ "svgload", ImageType::SVG },
|
|
204
|
+
{ "svgload_buffer", ImageType::SVG },
|
|
205
|
+
{ "heifload", ImageType::HEIF },
|
|
206
|
+
{ "heifload_buffer", ImageType::HEIF },
|
|
207
|
+
{ "pdfload", ImageType::PDF },
|
|
208
|
+
{ "pdfload_buffer", ImageType::PDF },
|
|
209
|
+
{ "magickload", ImageType::MAGICK },
|
|
210
|
+
{ "magickload_buffer", ImageType::MAGICK },
|
|
211
|
+
{ "openslideload", ImageType::OPENSLIDE },
|
|
212
|
+
{ "ppmload", ImageType::PPM },
|
|
213
|
+
{ "fitsload", ImageType::FITS },
|
|
214
|
+
{ "openexrload", ImageType::EXR },
|
|
215
|
+
{ "vipsload", ImageType::VIPS },
|
|
216
|
+
{ "rawload", ImageType::RAW }
|
|
217
|
+
};
|
|
218
|
+
|
|
172
219
|
/*
|
|
173
220
|
Determine image format of a buffer.
|
|
174
221
|
*/
|
|
175
222
|
ImageType DetermineImageType(void *buffer, size_t const length) {
|
|
176
223
|
ImageType imageType = ImageType::UNKNOWN;
|
|
177
224
|
char const *load = vips_foreign_find_load_buffer(buffer, length);
|
|
178
|
-
if (load !=
|
|
179
|
-
|
|
180
|
-
if (
|
|
181
|
-
imageType =
|
|
182
|
-
} else if (EndsWith(loader, "PngBuffer")) {
|
|
183
|
-
imageType = ImageType::PNG;
|
|
184
|
-
} else if (EndsWith(loader, "WebpBuffer")) {
|
|
185
|
-
imageType = ImageType::WEBP;
|
|
186
|
-
} else if (EndsWith(loader, "TiffBuffer")) {
|
|
187
|
-
imageType = ImageType::TIFF;
|
|
188
|
-
} else if (EndsWith(loader, "GifBuffer")) {
|
|
189
|
-
imageType = ImageType::GIF;
|
|
190
|
-
} else if (EndsWith(loader, "SvgBuffer")) {
|
|
191
|
-
imageType = ImageType::SVG;
|
|
192
|
-
} else if (EndsWith(loader, "HeifBuffer")) {
|
|
193
|
-
imageType = ImageType::HEIF;
|
|
194
|
-
} else if (EndsWith(loader, "PdfBuffer")) {
|
|
195
|
-
imageType = ImageType::PDF;
|
|
196
|
-
} else if (EndsWith(loader, "MagickBuffer")) {
|
|
197
|
-
imageType = ImageType::MAGICK;
|
|
225
|
+
if (load != nullptr) {
|
|
226
|
+
auto it = loaderToType.find(vips_nickname_find(g_type_from_name(load)));
|
|
227
|
+
if (it != loaderToType.end()) {
|
|
228
|
+
imageType = it->second;
|
|
198
229
|
}
|
|
199
230
|
}
|
|
200
231
|
return imageType;
|
|
@@ -207,36 +238,12 @@ namespace sharp {
|
|
|
207
238
|
ImageType imageType = ImageType::UNKNOWN;
|
|
208
239
|
char const *load = vips_foreign_find_load(file);
|
|
209
240
|
if (load != nullptr) {
|
|
210
|
-
|
|
211
|
-
if (
|
|
212
|
-
imageType =
|
|
213
|
-
} else if (EndsWith(loader, "PngFile")) {
|
|
214
|
-
imageType = ImageType::PNG;
|
|
215
|
-
} else if (EndsWith(loader, "WebpFile")) {
|
|
216
|
-
imageType = ImageType::WEBP;
|
|
217
|
-
} else if (EndsWith(loader, "Openslide")) {
|
|
218
|
-
imageType = ImageType::OPENSLIDE;
|
|
219
|
-
} else if (EndsWith(loader, "TiffFile")) {
|
|
220
|
-
imageType = ImageType::TIFF;
|
|
221
|
-
} else if (EndsWith(loader, "GifFile")) {
|
|
222
|
-
imageType = ImageType::GIF;
|
|
223
|
-
} else if (EndsWith(loader, "SvgFile")) {
|
|
224
|
-
imageType = ImageType::SVG;
|
|
225
|
-
} else if (EndsWith(loader, "HeifFile")) {
|
|
226
|
-
imageType = ImageType::HEIF;
|
|
227
|
-
} else if (EndsWith(loader, "PdfFile")) {
|
|
228
|
-
imageType = ImageType::PDF;
|
|
229
|
-
} else if (EndsWith(loader, "Ppm")) {
|
|
230
|
-
imageType = ImageType::PPM;
|
|
231
|
-
} else if (EndsWith(loader, "Fits")) {
|
|
232
|
-
imageType = ImageType::FITS;
|
|
233
|
-
} else if (EndsWith(loader, "Vips")) {
|
|
234
|
-
imageType = ImageType::VIPS;
|
|
235
|
-
} else if (EndsWith(loader, "Magick") || EndsWith(loader, "MagickFile")) {
|
|
236
|
-
imageType = ImageType::MAGICK;
|
|
241
|
+
auto it = loaderToType.find(vips_nickname_find(g_type_from_name(load)));
|
|
242
|
+
if (it != loaderToType.end()) {
|
|
243
|
+
imageType = it->second;
|
|
237
244
|
}
|
|
238
245
|
} else {
|
|
239
|
-
if (EndsWith(vips::VError().what(), " not
|
|
246
|
+
if (EndsWith(vips::VError().what(), " does not exist\n")) {
|
|
240
247
|
imageType = ImageType::MISSING;
|
|
241
248
|
}
|
|
242
249
|
}
|
|
@@ -248,6 +255,8 @@ namespace sharp {
|
|
|
248
255
|
*/
|
|
249
256
|
bool ImageTypeSupportsPage(ImageType imageType) {
|
|
250
257
|
return
|
|
258
|
+
imageType == ImageType::WEBP ||
|
|
259
|
+
imageType == ImageType::MAGICK ||
|
|
251
260
|
imageType == ImageType::GIF ||
|
|
252
261
|
imageType == ImageType::TIFF ||
|
|
253
262
|
imageType == ImageType::HEIF ||
|
|
@@ -292,6 +301,9 @@ namespace sharp {
|
|
|
292
301
|
option->set("n", descriptor->pages);
|
|
293
302
|
option->set("page", descriptor->page);
|
|
294
303
|
}
|
|
304
|
+
if (imageType == ImageType::OPENSLIDE) {
|
|
305
|
+
option->set("level", descriptor->level);
|
|
306
|
+
}
|
|
295
307
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
|
296
308
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
297
309
|
image = SetDensity(image, descriptor->density);
|
|
@@ -341,6 +353,9 @@ namespace sharp {
|
|
|
341
353
|
option->set("n", descriptor->pages);
|
|
342
354
|
option->set("page", descriptor->page);
|
|
343
355
|
}
|
|
356
|
+
if (imageType == ImageType::OPENSLIDE) {
|
|
357
|
+
option->set("level", descriptor->level);
|
|
358
|
+
}
|
|
344
359
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
|
345
360
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
346
361
|
image = SetDensity(image, descriptor->density);
|
|
@@ -410,6 +425,38 @@ namespace sharp {
|
|
|
410
425
|
return copy;
|
|
411
426
|
}
|
|
412
427
|
|
|
428
|
+
/*
|
|
429
|
+
Set animation properties if necessary.
|
|
430
|
+
Non-provided properties will be loaded from image.
|
|
431
|
+
*/
|
|
432
|
+
VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop) {
|
|
433
|
+
bool hasDelay = delay.size() != 1 || delay.front() != -1;
|
|
434
|
+
|
|
435
|
+
if (pageHeight == 0 && image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT) {
|
|
436
|
+
pageHeight = image.get_int(VIPS_META_PAGE_HEIGHT);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (!hasDelay && image.get_typeof("delay") == VIPS_TYPE_ARRAY_INT) {
|
|
440
|
+
delay = image.get_array_int("delay");
|
|
441
|
+
hasDelay = true;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (loop == -1 && image.get_typeof("loop") == G_TYPE_INT) {
|
|
445
|
+
loop = image.get_int("loop");
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (pageHeight == 0) return image;
|
|
449
|
+
|
|
450
|
+
// It is necessary to create the copy as otherwise, pageHeight will be ignored!
|
|
451
|
+
VImage copy = image.copy();
|
|
452
|
+
|
|
453
|
+
copy.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
|
454
|
+
if (hasDelay) copy.set("delay", delay);
|
|
455
|
+
if (loop != -1) copy.set("loop", loop);
|
|
456
|
+
|
|
457
|
+
return copy;
|
|
458
|
+
}
|
|
459
|
+
|
|
413
460
|
/*
|
|
414
461
|
Does this image have a non-default density?
|
|
415
462
|
*/
|
|
@@ -440,14 +487,21 @@ namespace sharp {
|
|
|
440
487
|
Check the proposed format supports the current dimensions.
|
|
441
488
|
*/
|
|
442
489
|
void AssertImageTypeDimensions(VImage image, ImageType const imageType) {
|
|
490
|
+
const int height = image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT
|
|
491
|
+
? image.get_int(VIPS_META_PAGE_HEIGHT)
|
|
492
|
+
: image.height();
|
|
443
493
|
if (imageType == ImageType::JPEG) {
|
|
444
|
-
if (image.width() > 65535 ||
|
|
494
|
+
if (image.width() > 65535 || height > 65535) {
|
|
445
495
|
throw vips::VError("Processed image is too large for the JPEG format");
|
|
446
496
|
}
|
|
447
497
|
} else if (imageType == ImageType::WEBP) {
|
|
448
|
-
if (image.width() > 16383 ||
|
|
498
|
+
if (image.width() > 16383 || height > 16383) {
|
|
449
499
|
throw vips::VError("Processed image is too large for the WebP format");
|
|
450
500
|
}
|
|
501
|
+
} else if (imageType == ImageType::GIF) {
|
|
502
|
+
if (image.width() > 65535 || height > 65535) {
|
|
503
|
+
throw vips::VError("Processed image is too large for the GIF format");
|
|
504
|
+
}
|
|
451
505
|
}
|
|
452
506
|
}
|
|
453
507
|
|
|
@@ -710,4 +764,25 @@ namespace sharp {
|
|
|
710
764
|
return std::make_tuple(image, alphaColour);
|
|
711
765
|
}
|
|
712
766
|
|
|
767
|
+
/*
|
|
768
|
+
Removes alpha channel, if any.
|
|
769
|
+
*/
|
|
770
|
+
VImage RemoveAlpha(VImage image) {
|
|
771
|
+
if (HasAlpha(image)) {
|
|
772
|
+
image = image.extract_band(0, VImage::option()->set("n", image.bands() - 1));
|
|
773
|
+
}
|
|
774
|
+
return image;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/*
|
|
778
|
+
Ensures alpha channel, if missing.
|
|
779
|
+
*/
|
|
780
|
+
VImage EnsureAlpha(VImage image) {
|
|
781
|
+
if (!HasAlpha(image)) {
|
|
782
|
+
std::vector<double> alpha;
|
|
783
|
+
alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
|
|
784
|
+
image = image.bandjoin_const(alpha);
|
|
785
|
+
}
|
|
786
|
+
return image;
|
|
787
|
+
}
|
|
713
788
|
} // namespace sharp
|
package/src/common.h
CHANGED
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
|
|
25
25
|
// Verify platform and compiler compatibility
|
|
26
26
|
|
|
27
|
-
#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION <
|
|
28
|
-
#error "libvips version 8.
|
|
27
|
+
#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 10))
|
|
28
|
+
#error "libvips version 8.10.0+ is required - please see https://sharp.pixelplumbing.com/install"
|
|
29
29
|
#endif
|
|
30
30
|
|
|
31
31
|
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
|
@@ -57,6 +57,7 @@ namespace sharp {
|
|
|
57
57
|
int rawHeight;
|
|
58
58
|
int pages;
|
|
59
59
|
int page;
|
|
60
|
+
int level;
|
|
60
61
|
int createChannels;
|
|
61
62
|
int createWidth;
|
|
62
63
|
int createHeight;
|
|
@@ -75,6 +76,7 @@ namespace sharp {
|
|
|
75
76
|
rawHeight(0),
|
|
76
77
|
pages(1),
|
|
77
78
|
page(0),
|
|
79
|
+
level(0),
|
|
78
80
|
createChannels(0),
|
|
79
81
|
createWidth(0),
|
|
80
82
|
createHeight(0),
|
|
@@ -86,10 +88,12 @@ namespace sharp {
|
|
|
86
88
|
std::string AttrAsStr(Napi::Object obj, std::string attr);
|
|
87
89
|
uint32_t AttrAsUint32(Napi::Object obj, std::string attr);
|
|
88
90
|
int32_t AttrAsInt32(Napi::Object obj, std::string attr);
|
|
91
|
+
int32_t AttrAsInt32(Napi::Object obj, unsigned int const attr);
|
|
89
92
|
double AttrAsDouble(Napi::Object obj, std::string attr);
|
|
90
93
|
double AttrAsDouble(Napi::Object obj, unsigned int const attr);
|
|
91
94
|
bool AttrAsBool(Napi::Object obj, std::string attr);
|
|
92
95
|
std::vector<double> AttrAsRgba(Napi::Object obj, std::string attr);
|
|
96
|
+
std::vector<int32_t> AttrAsInt32Vector(Napi::Object obj, std::string attr);
|
|
93
97
|
|
|
94
98
|
// Create an InputDescriptor instance from a Napi::Object describing an input image
|
|
95
99
|
InputDescriptor* CreateInputDescriptor(Napi::Object input);
|
|
@@ -107,6 +111,7 @@ namespace sharp {
|
|
|
107
111
|
OPENSLIDE,
|
|
108
112
|
PPM,
|
|
109
113
|
FITS,
|
|
114
|
+
EXR,
|
|
110
115
|
VIPS,
|
|
111
116
|
RAW,
|
|
112
117
|
UNKNOWN,
|
|
@@ -123,6 +128,7 @@ namespace sharp {
|
|
|
123
128
|
bool IsJpeg(std::string const &str);
|
|
124
129
|
bool IsPng(std::string const &str);
|
|
125
130
|
bool IsWebp(std::string const &str);
|
|
131
|
+
bool IsGif(std::string const &str);
|
|
126
132
|
bool IsTiff(std::string const &str);
|
|
127
133
|
bool IsHeic(std::string const &str);
|
|
128
134
|
bool IsHeif(std::string const &str);
|
|
@@ -182,6 +188,12 @@ namespace sharp {
|
|
|
182
188
|
*/
|
|
183
189
|
VImage RemoveExifOrientation(VImage image);
|
|
184
190
|
|
|
191
|
+
/*
|
|
192
|
+
Set animation properties if necessary.
|
|
193
|
+
Non-provided properties will be loaded from image.
|
|
194
|
+
*/
|
|
195
|
+
VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop);
|
|
196
|
+
|
|
185
197
|
/*
|
|
186
198
|
Does this image have a non-default density?
|
|
187
199
|
*/
|
|
@@ -269,6 +281,16 @@ namespace sharp {
|
|
|
269
281
|
*/
|
|
270
282
|
std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour);
|
|
271
283
|
|
|
284
|
+
/*
|
|
285
|
+
Removes alpha channel, if any.
|
|
286
|
+
*/
|
|
287
|
+
VImage RemoveAlpha(VImage image);
|
|
288
|
+
|
|
289
|
+
/*
|
|
290
|
+
Ensures alpha channel, if missing.
|
|
291
|
+
*/
|
|
292
|
+
VImage EnsureAlpha(VImage image);
|
|
293
|
+
|
|
272
294
|
} // namespace sharp
|
|
273
295
|
|
|
274
296
|
#endif // SRC_COMMON_H_
|