sharp 0.27.1 → 0.30.5
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 +19 -18
- package/binding.gyp +15 -14
- package/install/can-compile.js +11 -0
- package/install/dll-copy.js +10 -10
- package/install/libvips.js +128 -47
- package/lib/agent.js +1 -1
- package/lib/channel.js +38 -14
- package/lib/colour.js +51 -1
- package/lib/composite.js +19 -2
- package/lib/constructor.js +47 -46
- package/lib/input.js +112 -18
- package/lib/is.js +19 -5
- package/lib/libvips.js +64 -29
- package/lib/operation.js +239 -35
- package/lib/output.js +398 -116
- package/lib/platform.js +5 -3
- package/lib/resize.js +61 -15
- package/lib/sharp.js +32 -0
- package/lib/utility.js +58 -19
- package/package.json +46 -24
- package/src/common.cc +202 -52
- package/src/common.h +59 -10
- package/src/libvips/cplusplus/VConnection.cpp +0 -26
- package/src/libvips/cplusplus/VImage.cpp +88 -32
- package/src/libvips/cplusplus/VInterpolate.cpp +0 -13
- package/src/libvips/cplusplus/vips-operators.cpp +213 -1
- package/src/metadata.cc +26 -0
- package/src/metadata.h +4 -0
- package/src/operations.cc +141 -7
- package/src/operations.h +32 -3
- package/src/pipeline.cc +454 -306
- package/src/pipeline.h +64 -29
- package/src/sharp.cc +1 -0
- package/src/utilities.cc +17 -1
- package/src/utilities.h +1 -0
package/src/common.cc
CHANGED
|
@@ -36,6 +36,9 @@ namespace sharp {
|
|
|
36
36
|
std::string AttrAsStr(Napi::Object obj, std::string attr) {
|
|
37
37
|
return obj.Get(attr).As<Napi::String>();
|
|
38
38
|
}
|
|
39
|
+
std::string AttrAsStr(Napi::Object obj, unsigned int const attr) {
|
|
40
|
+
return obj.Get(attr).As<Napi::String>();
|
|
41
|
+
}
|
|
39
42
|
uint32_t AttrAsUint32(Napi::Object obj, std::string attr) {
|
|
40
43
|
return obj.Get(attr).As<Napi::Number>().Uint32Value();
|
|
41
44
|
}
|
|
@@ -82,16 +85,22 @@ namespace sharp {
|
|
|
82
85
|
descriptor->buffer = buffer.Data();
|
|
83
86
|
descriptor->isBuffer = TRUE;
|
|
84
87
|
}
|
|
85
|
-
descriptor->
|
|
88
|
+
descriptor->failOn = static_cast<VipsFailOn>(
|
|
89
|
+
vips_enum_from_nick(nullptr, VIPS_TYPE_FAIL_ON,
|
|
90
|
+
AttrAsStr(input, "failOn").data()));
|
|
86
91
|
// Density for vector-based input
|
|
87
92
|
if (HasAttr(input, "density")) {
|
|
88
93
|
descriptor->density = AttrAsDouble(input, "density");
|
|
89
94
|
}
|
|
90
95
|
// Raw pixel input
|
|
91
96
|
if (HasAttr(input, "rawChannels")) {
|
|
97
|
+
descriptor->rawDepth = static_cast<VipsBandFormat>(
|
|
98
|
+
vips_enum_from_nick(nullptr, VIPS_TYPE_BAND_FORMAT,
|
|
99
|
+
AttrAsStr(input, "rawDepth").data()));
|
|
92
100
|
descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
|
|
93
101
|
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
|
94
102
|
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
|
103
|
+
descriptor->rawPremultiplied = AttrAsBool(input, "rawPremultiplied");
|
|
95
104
|
}
|
|
96
105
|
// Multi-page input (GIF, TIFF, PDF)
|
|
97
106
|
if (HasAttr(input, "pages")) {
|
|
@@ -104,6 +113,10 @@ namespace sharp {
|
|
|
104
113
|
if (HasAttr(input, "level")) {
|
|
105
114
|
descriptor->level = AttrAsUint32(input, "level");
|
|
106
115
|
}
|
|
116
|
+
// subIFD (OME-TIFF)
|
|
117
|
+
if (HasAttr(input, "subifd")) {
|
|
118
|
+
descriptor->subifd = AttrAsInt32(input, "subifd");
|
|
119
|
+
}
|
|
107
120
|
// Create new image
|
|
108
121
|
if (HasAttr(input, "createChannels")) {
|
|
109
122
|
descriptor->createChannels = AttrAsUint32(input, "createChannels");
|
|
@@ -121,6 +134,8 @@ namespace sharp {
|
|
|
121
134
|
descriptor->limitInputPixels = AttrAsUint32(input, "limitInputPixels");
|
|
122
135
|
// Allow switch from random to sequential access
|
|
123
136
|
descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
|
137
|
+
// Remove safety features and allow unlimited SVG/PNG input
|
|
138
|
+
descriptor->unlimited = AttrAsBool(input, "unlimited");
|
|
124
139
|
return descriptor;
|
|
125
140
|
}
|
|
126
141
|
|
|
@@ -146,6 +161,10 @@ namespace sharp {
|
|
|
146
161
|
bool IsGif(std::string const &str) {
|
|
147
162
|
return EndsWith(str, ".gif") || EndsWith(str, ".GIF");
|
|
148
163
|
}
|
|
164
|
+
bool IsJp2(std::string const &str) {
|
|
165
|
+
return EndsWith(str, ".jp2") || EndsWith(str, ".jpx") || EndsWith(str, ".j2k") || EndsWith(str, ".j2c")
|
|
166
|
+
|| EndsWith(str, ".JP2") || EndsWith(str, ".JPX") || EndsWith(str, ".J2K") || EndsWith(str, ".J2C");
|
|
167
|
+
}
|
|
149
168
|
bool IsTiff(std::string const &str) {
|
|
150
169
|
return EndsWith(str, ".tif") || EndsWith(str, ".tiff") || EndsWith(str, ".TIF") || EndsWith(str, ".TIFF");
|
|
151
170
|
}
|
|
@@ -179,6 +198,7 @@ namespace sharp {
|
|
|
179
198
|
case ImageType::WEBP: id = "webp"; break;
|
|
180
199
|
case ImageType::TIFF: id = "tiff"; break;
|
|
181
200
|
case ImageType::GIF: id = "gif"; break;
|
|
201
|
+
case ImageType::JP2: id = "jp2"; break;
|
|
182
202
|
case ImageType::SVG: id = "svg"; break;
|
|
183
203
|
case ImageType::HEIF: id = "heif"; break;
|
|
184
204
|
case ImageType::PDF: id = "pdf"; break;
|
|
@@ -213,6 +233,10 @@ namespace sharp {
|
|
|
213
233
|
{ "VipsForeignLoadTiffBuffer", ImageType::TIFF },
|
|
214
234
|
{ "VipsForeignLoadGifFile", ImageType::GIF },
|
|
215
235
|
{ "VipsForeignLoadGifBuffer", ImageType::GIF },
|
|
236
|
+
{ "VipsForeignLoadNsgifFile", ImageType::GIF },
|
|
237
|
+
{ "VipsForeignLoadNsgifBuffer", ImageType::GIF },
|
|
238
|
+
{ "VipsForeignLoadJp2kBuffer", ImageType::JP2 },
|
|
239
|
+
{ "VipsForeignLoadJp2kFile", ImageType::JP2 },
|
|
216
240
|
{ "VipsForeignLoadSvgFile", ImageType::SVG },
|
|
217
241
|
{ "VipsForeignLoadSvgBuffer", ImageType::SVG },
|
|
218
242
|
{ "VipsForeignLoadHeifFile", ImageType::HEIF },
|
|
@@ -221,11 +245,14 @@ namespace sharp {
|
|
|
221
245
|
{ "VipsForeignLoadPdfBuffer", ImageType::PDF },
|
|
222
246
|
{ "VipsForeignLoadMagickFile", ImageType::MAGICK },
|
|
223
247
|
{ "VipsForeignLoadMagickBuffer", ImageType::MAGICK },
|
|
248
|
+
{ "VipsForeignLoadMagick7File", ImageType::MAGICK },
|
|
249
|
+
{ "VipsForeignLoadMagick7Buffer", ImageType::MAGICK },
|
|
224
250
|
{ "VipsForeignLoadOpenslide", ImageType::OPENSLIDE },
|
|
225
251
|
{ "VipsForeignLoadPpmFile", ImageType::PPM },
|
|
226
252
|
{ "VipsForeignLoadFits", ImageType::FITS },
|
|
227
253
|
{ "VipsForeignLoadOpenexr", ImageType::EXR },
|
|
228
254
|
{ "VipsForeignLoadVips", ImageType::VIPS },
|
|
255
|
+
{ "VipsForeignLoadVipsFile", ImageType::VIPS },
|
|
229
256
|
{ "VipsForeignLoadRaw", ImageType::RAW }
|
|
230
257
|
};
|
|
231
258
|
|
|
@@ -271,6 +298,7 @@ namespace sharp {
|
|
|
271
298
|
imageType == ImageType::WEBP ||
|
|
272
299
|
imageType == ImageType::MAGICK ||
|
|
273
300
|
imageType == ImageType::GIF ||
|
|
301
|
+
imageType == ImageType::JP2 ||
|
|
274
302
|
imageType == ImageType::TIFF ||
|
|
275
303
|
imageType == ImageType::HEIF ||
|
|
276
304
|
imageType == ImageType::PDF;
|
|
@@ -286,12 +314,15 @@ namespace sharp {
|
|
|
286
314
|
if (descriptor->rawChannels > 0) {
|
|
287
315
|
// Raw, uncompressed pixel data
|
|
288
316
|
image = VImage::new_from_memory(descriptor->buffer, descriptor->bufferLength,
|
|
289
|
-
descriptor->rawWidth, descriptor->rawHeight, descriptor->rawChannels,
|
|
317
|
+
descriptor->rawWidth, descriptor->rawHeight, descriptor->rawChannels, descriptor->rawDepth);
|
|
290
318
|
if (descriptor->rawChannels < 3) {
|
|
291
319
|
image.get_image()->Type = VIPS_INTERPRETATION_B_W;
|
|
292
320
|
} else {
|
|
293
321
|
image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
|
|
294
322
|
}
|
|
323
|
+
if (descriptor->rawPremultiplied) {
|
|
324
|
+
image = image.unpremultiply();
|
|
325
|
+
}
|
|
295
326
|
imageType = ImageType::RAW;
|
|
296
327
|
} else {
|
|
297
328
|
// Compressed data
|
|
@@ -300,8 +331,8 @@ namespace sharp {
|
|
|
300
331
|
try {
|
|
301
332
|
vips::VOption *option = VImage::option()
|
|
302
333
|
->set("access", descriptor->access)
|
|
303
|
-
->set("
|
|
304
|
-
if (imageType == ImageType::SVG) {
|
|
334
|
+
->set("fail_on", descriptor->failOn);
|
|
335
|
+
if (descriptor->unlimited && (imageType == ImageType::SVG || imageType == ImageType::PNG)) {
|
|
305
336
|
option->set("unlimited", TRUE);
|
|
306
337
|
}
|
|
307
338
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
|
@@ -317,6 +348,9 @@ namespace sharp {
|
|
|
317
348
|
if (imageType == ImageType::OPENSLIDE) {
|
|
318
349
|
option->set("level", descriptor->level);
|
|
319
350
|
}
|
|
351
|
+
if (imageType == ImageType::TIFF) {
|
|
352
|
+
option->set("subifd", descriptor->subifd);
|
|
353
|
+
}
|
|
320
354
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
|
321
355
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
322
356
|
image = SetDensity(image, descriptor->density);
|
|
@@ -343,12 +377,6 @@ namespace sharp {
|
|
|
343
377
|
VImage::option()->set("mean", descriptor->createNoiseMean)->set("sigma", descriptor->createNoiseSigma)));
|
|
344
378
|
}
|
|
345
379
|
image = image.bandjoin(bands);
|
|
346
|
-
image = image.cast(VipsBandFormat::VIPS_FORMAT_UCHAR);
|
|
347
|
-
if (channels < 3) {
|
|
348
|
-
image = image.colourspace(VIPS_INTERPRETATION_B_W);
|
|
349
|
-
} else {
|
|
350
|
-
image = image.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
351
|
-
}
|
|
352
380
|
} else {
|
|
353
381
|
std::vector<double> background = {
|
|
354
382
|
descriptor->createBackground[0],
|
|
@@ -360,20 +388,25 @@ namespace sharp {
|
|
|
360
388
|
}
|
|
361
389
|
image = VImage::new_matrix(descriptor->createWidth, descriptor->createHeight).new_from_image(background);
|
|
362
390
|
}
|
|
363
|
-
image.get_image()->Type =
|
|
391
|
+
image.get_image()->Type = image.guess_interpretation();
|
|
392
|
+
image = image.cast(VIPS_FORMAT_UCHAR);
|
|
364
393
|
imageType = ImageType::RAW;
|
|
365
394
|
} else {
|
|
366
395
|
// From filesystem
|
|
367
396
|
imageType = DetermineImageType(descriptor->file.data());
|
|
368
397
|
if (imageType == ImageType::MISSING) {
|
|
369
|
-
|
|
398
|
+
if (descriptor->file.find("<svg") != std::string::npos) {
|
|
399
|
+
throw vips::VError("Input file is missing, did you mean "
|
|
400
|
+
"sharp(Buffer.from('" + descriptor->file.substr(0, 8) + "...')?");
|
|
401
|
+
}
|
|
402
|
+
throw vips::VError("Input file is missing: " + descriptor->file);
|
|
370
403
|
}
|
|
371
404
|
if (imageType != ImageType::UNKNOWN) {
|
|
372
405
|
try {
|
|
373
406
|
vips::VOption *option = VImage::option()
|
|
374
407
|
->set("access", descriptor->access)
|
|
375
|
-
->set("
|
|
376
|
-
if (imageType == ImageType::SVG) {
|
|
408
|
+
->set("fail_on", descriptor->failOn);
|
|
409
|
+
if (descriptor->unlimited && (imageType == ImageType::SVG || imageType == ImageType::PNG)) {
|
|
377
410
|
option->set("unlimited", TRUE);
|
|
378
411
|
}
|
|
379
412
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
|
@@ -389,6 +422,9 @@ namespace sharp {
|
|
|
389
422
|
if (imageType == ImageType::OPENSLIDE) {
|
|
390
423
|
option->set("level", descriptor->level);
|
|
391
424
|
}
|
|
425
|
+
if (imageType == ImageType::TIFF) {
|
|
426
|
+
option->set("subifd", descriptor->subifd);
|
|
427
|
+
}
|
|
392
428
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
|
393
429
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
394
430
|
image = SetDensity(image, descriptor->density);
|
|
@@ -421,12 +457,7 @@ namespace sharp {
|
|
|
421
457
|
Uses colour space interpretation with number of channels to guess this.
|
|
422
458
|
*/
|
|
423
459
|
bool HasAlpha(VImage image) {
|
|
424
|
-
|
|
425
|
-
VipsInterpretation const interpretation = image.interpretation();
|
|
426
|
-
return (
|
|
427
|
-
(bands == 2 && interpretation == VIPS_INTERPRETATION_B_W) ||
|
|
428
|
-
(bands == 4 && interpretation != VIPS_INTERPRETATION_CMYK) ||
|
|
429
|
-
(bands == 5 && interpretation == VIPS_INTERPRETATION_CMYK));
|
|
460
|
+
return image.has_alpha();
|
|
430
461
|
}
|
|
431
462
|
|
|
432
463
|
/*
|
|
@@ -460,36 +491,41 @@ namespace sharp {
|
|
|
460
491
|
|
|
461
492
|
/*
|
|
462
493
|
Set animation properties if necessary.
|
|
463
|
-
Non-provided properties will be loaded from image.
|
|
464
494
|
*/
|
|
465
|
-
VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop) {
|
|
466
|
-
bool hasDelay = delay.
|
|
495
|
+
VImage SetAnimationProperties(VImage image, int nPages, int pageHeight, std::vector<int> delay, int loop) {
|
|
496
|
+
bool hasDelay = !delay.empty();
|
|
467
497
|
|
|
468
|
-
if
|
|
469
|
-
|
|
470
|
-
}
|
|
498
|
+
// Avoid a copy if none of the animation properties are needed.
|
|
499
|
+
if (nPages == 1 && !hasDelay && loop == -1) return image;
|
|
471
500
|
|
|
472
|
-
if (
|
|
473
|
-
delay
|
|
474
|
-
|
|
501
|
+
if (delay.size() == 1) {
|
|
502
|
+
// We have just one delay, repeat that value for all frames.
|
|
503
|
+
delay.insert(delay.end(), nPages - 1, delay[0]);
|
|
475
504
|
}
|
|
476
505
|
|
|
477
|
-
|
|
478
|
-
loop = image.get_int("loop");
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
if (pageHeight == 0) return image;
|
|
482
|
-
|
|
483
|
-
// It is necessary to create the copy as otherwise, pageHeight will be ignored!
|
|
506
|
+
// Attaching metadata, need to copy the image.
|
|
484
507
|
VImage copy = image.copy();
|
|
485
508
|
|
|
486
|
-
|
|
509
|
+
// Only set page-height if we have more than one page, or this could
|
|
510
|
+
// accidentally turn into an animated image later.
|
|
511
|
+
if (nPages > 1) copy.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
|
487
512
|
if (hasDelay) copy.set("delay", delay);
|
|
488
513
|
if (loop != -1) copy.set("loop", loop);
|
|
489
514
|
|
|
490
515
|
return copy;
|
|
491
516
|
}
|
|
492
517
|
|
|
518
|
+
/*
|
|
519
|
+
Remove animation properties from image.
|
|
520
|
+
*/
|
|
521
|
+
VImage RemoveAnimationProperties(VImage image) {
|
|
522
|
+
VImage copy = image.copy();
|
|
523
|
+
copy.remove(VIPS_META_PAGE_HEIGHT);
|
|
524
|
+
copy.remove("delay");
|
|
525
|
+
copy.remove("loop");
|
|
526
|
+
return copy;
|
|
527
|
+
}
|
|
528
|
+
|
|
493
529
|
/*
|
|
494
530
|
Does this image have a non-default density?
|
|
495
531
|
*/
|
|
@@ -510,12 +546,19 @@ namespace sharp {
|
|
|
510
546
|
VImage SetDensity(VImage image, const double density) {
|
|
511
547
|
const double pixelsPerMm = density / 25.4;
|
|
512
548
|
VImage copy = image.copy();
|
|
513
|
-
copy.
|
|
514
|
-
copy.
|
|
515
|
-
copy.set(VIPS_META_RESOLUTION_UNIT, "in");
|
|
549
|
+
copy.get_image()->Xres = pixelsPerMm;
|
|
550
|
+
copy.get_image()->Yres = pixelsPerMm;
|
|
516
551
|
return copy;
|
|
517
552
|
}
|
|
518
553
|
|
|
554
|
+
/*
|
|
555
|
+
Multi-page images can have a page height. Fetch it, and sanity check it.
|
|
556
|
+
If page-height is not set, it defaults to the image height
|
|
557
|
+
*/
|
|
558
|
+
int GetPageHeight(VImage image) {
|
|
559
|
+
return vips_image_get_page_height(image.get_image());
|
|
560
|
+
}
|
|
561
|
+
|
|
519
562
|
/*
|
|
520
563
|
Check the proposed format supports the current dimensions.
|
|
521
564
|
*/
|
|
@@ -572,6 +615,33 @@ namespace sharp {
|
|
|
572
615
|
return warning;
|
|
573
616
|
}
|
|
574
617
|
|
|
618
|
+
/*
|
|
619
|
+
Attach an event listener for progress updates, used to detect timeout
|
|
620
|
+
*/
|
|
621
|
+
void SetTimeout(VImage image, int const seconds) {
|
|
622
|
+
if (seconds > 0) {
|
|
623
|
+
VipsImage *im = image.get_image();
|
|
624
|
+
if (im->progress_signal == NULL) {
|
|
625
|
+
int *timeout = VIPS_NEW(im, int);
|
|
626
|
+
*timeout = seconds;
|
|
627
|
+
g_signal_connect(im, "eval", G_CALLBACK(VipsProgressCallBack), timeout);
|
|
628
|
+
vips_image_set_progress(im, TRUE);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/*
|
|
634
|
+
Event listener for progress updates, used to detect timeout
|
|
635
|
+
*/
|
|
636
|
+
void VipsProgressCallBack(VipsImage *im, VipsProgress *progress, int *timeout) {
|
|
637
|
+
// printf("VipsProgressCallBack progress=%d run=%d timeout=%d\n", progress->percent, progress->run, *timeout);
|
|
638
|
+
if (*timeout > 0 && progress->run >= *timeout) {
|
|
639
|
+
vips_image_set_kill(im, TRUE);
|
|
640
|
+
vips_error("timeout", "%d%% complete", progress->percent);
|
|
641
|
+
*timeout = 0;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
575
645
|
/*
|
|
576
646
|
Calculate the (left, top) coordinates of the output image
|
|
577
647
|
within the input image, applying the given gravity during an embed.
|
|
@@ -740,23 +810,27 @@ namespace sharp {
|
|
|
740
810
|
/*
|
|
741
811
|
Convert RGBA value to another colourspace
|
|
742
812
|
*/
|
|
743
|
-
std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba,
|
|
813
|
+
std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba,
|
|
814
|
+
VipsInterpretation const interpretation, bool premultiply) {
|
|
744
815
|
int const bands = static_cast<int>(rgba.size());
|
|
745
|
-
if (bands < 3
|
|
816
|
+
if (bands < 3) {
|
|
746
817
|
return rgba;
|
|
747
|
-
} else {
|
|
748
|
-
VImage pixel = VImage::new_matrix(1, 1);
|
|
749
|
-
pixel.set("bands", bands);
|
|
750
|
-
pixel = pixel.new_from_image(rgba);
|
|
751
|
-
pixel = pixel.colourspace(interpretation, VImage::option()->set("source_space", VIPS_INTERPRETATION_sRGB));
|
|
752
|
-
return pixel(0, 0);
|
|
753
818
|
}
|
|
819
|
+
VImage pixel = VImage::new_matrix(1, 1);
|
|
820
|
+
pixel.set("bands", bands);
|
|
821
|
+
pixel = pixel
|
|
822
|
+
.new_from_image(rgba)
|
|
823
|
+
.colourspace(interpretation, VImage::option()->set("source_space", VIPS_INTERPRETATION_sRGB));
|
|
824
|
+
if (premultiply) {
|
|
825
|
+
pixel = pixel.premultiply();
|
|
826
|
+
}
|
|
827
|
+
return pixel(0, 0);
|
|
754
828
|
}
|
|
755
829
|
|
|
756
830
|
/*
|
|
757
831
|
Apply the alpha channel to a given colour
|
|
758
832
|
*/
|
|
759
|
-
std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour) {
|
|
833
|
+
std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour, bool premultiply) {
|
|
760
834
|
// Scale up 8-bit values to match 16-bit input image
|
|
761
835
|
double const multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0;
|
|
762
836
|
// Create alphaColour colour
|
|
@@ -780,7 +854,7 @@ namespace sharp {
|
|
|
780
854
|
alphaColour.push_back(colour[3] * multiplier);
|
|
781
855
|
}
|
|
782
856
|
// Ensure alphaColour colour uses correct colourspace
|
|
783
|
-
alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation());
|
|
857
|
+
alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation(), premultiply);
|
|
784
858
|
// Add non-transparent alpha channel, if required
|
|
785
859
|
if (colour[3] < 255.0 && !HasAlpha(image)) {
|
|
786
860
|
image = image.bandjoin(
|
|
@@ -802,12 +876,88 @@ namespace sharp {
|
|
|
802
876
|
/*
|
|
803
877
|
Ensures alpha channel, if missing.
|
|
804
878
|
*/
|
|
805
|
-
VImage EnsureAlpha(VImage image) {
|
|
879
|
+
VImage EnsureAlpha(VImage image, double const value) {
|
|
806
880
|
if (!HasAlpha(image)) {
|
|
807
881
|
std::vector<double> alpha;
|
|
808
|
-
alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
|
|
882
|
+
alpha.push_back(value * sharp::MaximumImageAlpha(image.interpretation()));
|
|
809
883
|
image = image.bandjoin_const(alpha);
|
|
810
884
|
}
|
|
811
885
|
return image;
|
|
812
886
|
}
|
|
887
|
+
|
|
888
|
+
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
|
|
889
|
+
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction) {
|
|
890
|
+
if (swap) {
|
|
891
|
+
// Swap input width and height when requested.
|
|
892
|
+
std::swap(width, height);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
double hshrink = 1.0;
|
|
896
|
+
double vshrink = 1.0;
|
|
897
|
+
|
|
898
|
+
if (targetWidth > 0 && targetHeight > 0) {
|
|
899
|
+
// Fixed width and height
|
|
900
|
+
hshrink = static_cast<double>(width) / targetWidth;
|
|
901
|
+
vshrink = static_cast<double>(height) / targetHeight;
|
|
902
|
+
|
|
903
|
+
switch (canvas) {
|
|
904
|
+
case Canvas::CROP:
|
|
905
|
+
case Canvas::MIN:
|
|
906
|
+
if (hshrink < vshrink) {
|
|
907
|
+
vshrink = hshrink;
|
|
908
|
+
} else {
|
|
909
|
+
hshrink = vshrink;
|
|
910
|
+
}
|
|
911
|
+
break;
|
|
912
|
+
case Canvas::EMBED:
|
|
913
|
+
case Canvas::MAX:
|
|
914
|
+
if (hshrink > vshrink) {
|
|
915
|
+
vshrink = hshrink;
|
|
916
|
+
} else {
|
|
917
|
+
hshrink = vshrink;
|
|
918
|
+
}
|
|
919
|
+
break;
|
|
920
|
+
case Canvas::IGNORE_ASPECT:
|
|
921
|
+
if (swap) {
|
|
922
|
+
std::swap(hshrink, vshrink);
|
|
923
|
+
}
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
} else if (targetWidth > 0) {
|
|
927
|
+
// Fixed width
|
|
928
|
+
hshrink = static_cast<double>(width) / targetWidth;
|
|
929
|
+
|
|
930
|
+
if (canvas != Canvas::IGNORE_ASPECT) {
|
|
931
|
+
// Auto height
|
|
932
|
+
vshrink = hshrink;
|
|
933
|
+
}
|
|
934
|
+
} else if (targetHeight > 0) {
|
|
935
|
+
// Fixed height
|
|
936
|
+
vshrink = static_cast<double>(height) / targetHeight;
|
|
937
|
+
|
|
938
|
+
if (canvas != Canvas::IGNORE_ASPECT) {
|
|
939
|
+
// Auto width
|
|
940
|
+
hshrink = vshrink;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// We should not reduce or enlarge the output image, if
|
|
945
|
+
// withoutReduction or withoutEnlargement is specified.
|
|
946
|
+
if (withoutReduction) {
|
|
947
|
+
// Equivalent of VIPS_SIZE_UP
|
|
948
|
+
hshrink = std::min(1.0, hshrink);
|
|
949
|
+
vshrink = std::min(1.0, vshrink);
|
|
950
|
+
} else if (withoutEnlargement) {
|
|
951
|
+
// Equivalent of VIPS_SIZE_DOWN
|
|
952
|
+
hshrink = std::max(1.0, hshrink);
|
|
953
|
+
vshrink = std::max(1.0, vshrink);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// We don't want to shrink so much that we send an axis to 0
|
|
957
|
+
hshrink = std::min(hshrink, static_cast<double>(width));
|
|
958
|
+
vshrink = std::min(vshrink, static_cast<double>(height));
|
|
959
|
+
|
|
960
|
+
return std::make_pair(hshrink, vshrink);
|
|
961
|
+
}
|
|
962
|
+
|
|
813
963
|
} // namespace sharp
|
package/src/common.h
CHANGED
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
// Verify platform and compiler compatibility
|
|
26
26
|
|
|
27
27
|
#if (VIPS_MAJOR_VERSION < 8) || \
|
|
28
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION <
|
|
29
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION ==
|
|
30
|
-
#error "libvips version 8.
|
|
28
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 12) || \
|
|
29
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 12 && VIPS_MICRO_VERSION < 2)
|
|
30
|
+
#error "libvips version 8.12.2+ 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)))
|
|
@@ -48,18 +48,22 @@ namespace sharp {
|
|
|
48
48
|
std::string name;
|
|
49
49
|
std::string file;
|
|
50
50
|
char *buffer;
|
|
51
|
-
|
|
51
|
+
VipsFailOn failOn;
|
|
52
52
|
int limitInputPixels;
|
|
53
|
+
bool unlimited;
|
|
53
54
|
VipsAccess access;
|
|
54
55
|
size_t bufferLength;
|
|
55
56
|
bool isBuffer;
|
|
56
57
|
double density;
|
|
58
|
+
VipsBandFormat rawDepth;
|
|
57
59
|
int rawChannels;
|
|
58
60
|
int rawWidth;
|
|
59
61
|
int rawHeight;
|
|
62
|
+
bool rawPremultiplied;
|
|
60
63
|
int pages;
|
|
61
64
|
int page;
|
|
62
65
|
int level;
|
|
66
|
+
int subifd;
|
|
63
67
|
int createChannels;
|
|
64
68
|
int createWidth;
|
|
65
69
|
int createHeight;
|
|
@@ -70,18 +74,22 @@ namespace sharp {
|
|
|
70
74
|
|
|
71
75
|
InputDescriptor():
|
|
72
76
|
buffer(nullptr),
|
|
73
|
-
|
|
77
|
+
failOn(VIPS_FAIL_ON_WARNING),
|
|
74
78
|
limitInputPixels(0x3FFF * 0x3FFF),
|
|
79
|
+
unlimited(FALSE),
|
|
75
80
|
access(VIPS_ACCESS_RANDOM),
|
|
76
81
|
bufferLength(0),
|
|
77
82
|
isBuffer(FALSE),
|
|
78
83
|
density(72.0),
|
|
84
|
+
rawDepth(VIPS_FORMAT_UCHAR),
|
|
79
85
|
rawChannels(0),
|
|
80
86
|
rawWidth(0),
|
|
81
87
|
rawHeight(0),
|
|
88
|
+
rawPremultiplied(false),
|
|
82
89
|
pages(1),
|
|
83
90
|
page(0),
|
|
84
91
|
level(0),
|
|
92
|
+
subifd(-1),
|
|
85
93
|
createChannels(0),
|
|
86
94
|
createWidth(0),
|
|
87
95
|
createHeight(0),
|
|
@@ -93,6 +101,7 @@ namespace sharp {
|
|
|
93
101
|
// Convenience methods to access the attributes of a Napi::Object
|
|
94
102
|
bool HasAttr(Napi::Object obj, std::string attr);
|
|
95
103
|
std::string AttrAsStr(Napi::Object obj, std::string attr);
|
|
104
|
+
std::string AttrAsStr(Napi::Object obj, unsigned int const attr);
|
|
96
105
|
uint32_t AttrAsUint32(Napi::Object obj, std::string attr);
|
|
97
106
|
int32_t AttrAsInt32(Napi::Object obj, std::string attr);
|
|
98
107
|
int32_t AttrAsInt32(Napi::Object obj, unsigned int const attr);
|
|
@@ -109,6 +118,7 @@ namespace sharp {
|
|
|
109
118
|
JPEG,
|
|
110
119
|
PNG,
|
|
111
120
|
WEBP,
|
|
121
|
+
JP2,
|
|
112
122
|
TIFF,
|
|
113
123
|
GIF,
|
|
114
124
|
SVG,
|
|
@@ -125,6 +135,14 @@ namespace sharp {
|
|
|
125
135
|
MISSING
|
|
126
136
|
};
|
|
127
137
|
|
|
138
|
+
enum class Canvas {
|
|
139
|
+
CROP,
|
|
140
|
+
EMBED,
|
|
141
|
+
MAX,
|
|
142
|
+
MIN,
|
|
143
|
+
IGNORE_ASPECT
|
|
144
|
+
};
|
|
145
|
+
|
|
128
146
|
// How many tasks are in the queue?
|
|
129
147
|
extern volatile int counterQueue;
|
|
130
148
|
|
|
@@ -135,6 +153,7 @@ namespace sharp {
|
|
|
135
153
|
bool IsJpeg(std::string const &str);
|
|
136
154
|
bool IsPng(std::string const &str);
|
|
137
155
|
bool IsWebp(std::string const &str);
|
|
156
|
+
bool IsJp2(std::string const &str);
|
|
138
157
|
bool IsGif(std::string const &str);
|
|
139
158
|
bool IsTiff(std::string const &str);
|
|
140
159
|
bool IsHeic(std::string const &str);
|
|
@@ -197,9 +216,13 @@ namespace sharp {
|
|
|
197
216
|
|
|
198
217
|
/*
|
|
199
218
|
Set animation properties if necessary.
|
|
200
|
-
Non-provided properties will be loaded from image.
|
|
201
219
|
*/
|
|
202
|
-
VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop);
|
|
220
|
+
VImage SetAnimationProperties(VImage image, int nPages, int pageHeight, std::vector<int> delay, int loop);
|
|
221
|
+
|
|
222
|
+
/*
|
|
223
|
+
Remove animation properties from image.
|
|
224
|
+
*/
|
|
225
|
+
VImage RemoveAnimationProperties(VImage image);
|
|
203
226
|
|
|
204
227
|
/*
|
|
205
228
|
Does this image have a non-default density?
|
|
@@ -216,6 +239,12 @@ namespace sharp {
|
|
|
216
239
|
*/
|
|
217
240
|
VImage SetDensity(VImage image, const double density);
|
|
218
241
|
|
|
242
|
+
/*
|
|
243
|
+
Multi-page images can have a page height. Fetch it, and sanity check it.
|
|
244
|
+
If page-height is not set, it defaults to the image height
|
|
245
|
+
*/
|
|
246
|
+
int GetPageHeight(VImage image);
|
|
247
|
+
|
|
219
248
|
/*
|
|
220
249
|
Check the proposed format supports the current dimensions.
|
|
221
250
|
*/
|
|
@@ -236,6 +265,16 @@ namespace sharp {
|
|
|
236
265
|
*/
|
|
237
266
|
std::string VipsWarningPop();
|
|
238
267
|
|
|
268
|
+
/*
|
|
269
|
+
Attach an event listener for progress updates, used to detect timeout
|
|
270
|
+
*/
|
|
271
|
+
void SetTimeout(VImage image, int const timeoutSeconds);
|
|
272
|
+
|
|
273
|
+
/*
|
|
274
|
+
Event listener for progress updates, used to detect timeout
|
|
275
|
+
*/
|
|
276
|
+
void VipsProgressCallBack(VipsImage *image, VipsProgress *progress, int *timeoutSeconds);
|
|
277
|
+
|
|
239
278
|
/*
|
|
240
279
|
Calculate the (left, top) coordinates of the output image
|
|
241
280
|
within the input image, applying the given gravity during an embed.
|
|
@@ -281,12 +320,13 @@ namespace sharp {
|
|
|
281
320
|
/*
|
|
282
321
|
Convert RGBA value to another colourspace
|
|
283
322
|
*/
|
|
284
|
-
std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba,
|
|
323
|
+
std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba,
|
|
324
|
+
VipsInterpretation const interpretation, bool premultiply);
|
|
285
325
|
|
|
286
326
|
/*
|
|
287
327
|
Apply the alpha channel to a given colour
|
|
288
328
|
*/
|
|
289
|
-
std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour);
|
|
329
|
+
std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour, bool premultiply);
|
|
290
330
|
|
|
291
331
|
/*
|
|
292
332
|
Removes alpha channel, if any.
|
|
@@ -296,7 +336,16 @@ namespace sharp {
|
|
|
296
336
|
/*
|
|
297
337
|
Ensures alpha channel, if missing.
|
|
298
338
|
*/
|
|
299
|
-
VImage EnsureAlpha(VImage image);
|
|
339
|
+
VImage EnsureAlpha(VImage image, double const value);
|
|
340
|
+
|
|
341
|
+
/*
|
|
342
|
+
Calculate the shrink factor, taking into account auto-rotate, the canvas
|
|
343
|
+
mode, and so on. The hshrink/vshrink are the amount to shrink the input
|
|
344
|
+
image axes by in order for the output axes (ie. after rotation) to match
|
|
345
|
+
the required thumbnail width/height and canvas mode.
|
|
346
|
+
*/
|
|
347
|
+
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
|
|
348
|
+
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction);
|
|
300
349
|
|
|
301
350
|
} // namespace sharp
|
|
302
351
|
|
|
@@ -110,19 +110,6 @@ VSource::new_from_options( const char *options )
|
|
|
110
110
|
return( out );
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
VOption *
|
|
114
|
-
VOption::set( const char *name, const VSource value )
|
|
115
|
-
{
|
|
116
|
-
Pair *pair = new Pair( name );
|
|
117
|
-
|
|
118
|
-
pair->input = true;
|
|
119
|
-
g_value_init( &pair->value, VIPS_TYPE_SOURCE );
|
|
120
|
-
g_value_set_object( &pair->value, value.get_source() );
|
|
121
|
-
options.push_back( pair );
|
|
122
|
-
|
|
123
|
-
return( this );
|
|
124
|
-
}
|
|
125
|
-
|
|
126
113
|
VTarget
|
|
127
114
|
VTarget::new_to_descriptor( int descriptor )
|
|
128
115
|
{
|
|
@@ -162,17 +149,4 @@ VTarget::new_to_memory()
|
|
|
162
149
|
return( out );
|
|
163
150
|
}
|
|
164
151
|
|
|
165
|
-
VOption *
|
|
166
|
-
VOption::set( const char *name, const VTarget value )
|
|
167
|
-
{
|
|
168
|
-
Pair *pair = new Pair( name );
|
|
169
|
-
|
|
170
|
-
pair->input = true;
|
|
171
|
-
g_value_init( &pair->value, VIPS_TYPE_TARGET );
|
|
172
|
-
g_value_set_object( &pair->value, value.get_target() );
|
|
173
|
-
options.push_back( pair );
|
|
174
|
-
|
|
175
|
-
return( this );
|
|
176
|
-
}
|
|
177
|
-
|
|
178
152
|
VIPS_NAMESPACE_END
|