sharp 0.33.5 → 0.35.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 +12 -18
- package/dist/channel.cjs +177 -0
- package/{lib/channel.js → dist/channel.mjs} +11 -8
- package/dist/colour.cjs +199 -0
- package/{lib/colour.js → dist/colour.mjs} +42 -23
- package/dist/composite.cjs +213 -0
- package/{lib/composite.js → dist/composite.mjs} +14 -11
- package/{lib/constructor.js → dist/constructor.cjs} +102 -43
- package/dist/constructor.mjs +511 -0
- package/dist/index.cjs +25 -0
- package/dist/index.d.cts +1999 -0
- package/dist/index.d.mts +2046 -0
- package/dist/index.mjs +25 -0
- package/dist/input.cjs +814 -0
- package/{lib/input.js → dist/input.mjs} +232 -76
- package/{lib/is.js → dist/is.cjs} +19 -45
- package/dist/is.mjs +143 -0
- package/{lib/libvips.js → dist/libvips.cjs} +52 -43
- package/dist/libvips.mjs +212 -0
- package/dist/operation.cjs +998 -0
- package/{lib/operation.js → dist/operation.mjs} +131 -91
- package/{lib/output.js → dist/output.cjs} +262 -61
- package/dist/output.mjs +1788 -0
- package/dist/resize.cjs +617 -0
- package/{lib/resize.js → dist/resize.mjs} +65 -35
- package/dist/sharp.cjs +174 -0
- package/dist/sharp.mjs +174 -0
- package/{lib/utility.js → dist/utility.cjs} +30 -25
- package/dist/utility.mjs +301 -0
- package/install/build.js +38 -0
- package/lib/index.d.ts +387 -142
- package/package.json +90 -85
- package/src/binding.gyp +49 -26
- package/src/common.cc +203 -111
- package/src/common.h +68 -40
- package/src/metadata.cc +106 -22
- package/src/metadata.h +15 -5
- package/src/operations.cc +62 -21
- package/src/operations.h +15 -3
- package/src/pipeline.cc +391 -201
- package/src/pipeline.h +36 -7
- package/src/sharp.cc +11 -8
- package/src/stats.cc +16 -13
- package/src/stats.h +6 -3
- package/src/utilities.cc +35 -15
- package/src/utilities.h +5 -2
- package/install/check.js +0 -41
- package/lib/index.js +0 -16
- package/lib/sharp.js +0 -114
package/src/common.cc
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/*!
|
|
2
|
+
Copyright 2013 Lovell Fuller and others.
|
|
3
|
+
SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
3
5
|
|
|
6
|
+
#include <algorithm>
|
|
4
7
|
#include <cstdlib>
|
|
8
|
+
#include <map>
|
|
9
|
+
#include <mutex>
|
|
10
|
+
#include <queue>
|
|
5
11
|
#include <string>
|
|
6
|
-
#include <
|
|
12
|
+
#include <tuple>
|
|
13
|
+
#include <utility>
|
|
7
14
|
#include <vector>
|
|
8
|
-
#include <queue>
|
|
9
|
-
#include <map>
|
|
10
|
-
#include <mutex> // NOLINT(build/c++11)
|
|
11
15
|
|
|
12
16
|
#include <napi.h>
|
|
13
17
|
#include <vips/vips8>
|
|
14
18
|
|
|
15
|
-
#include "common.h"
|
|
19
|
+
#include "./common.h"
|
|
16
20
|
|
|
17
21
|
using vips::VImage;
|
|
18
22
|
|
|
@@ -93,6 +97,7 @@ namespace sharp {
|
|
|
93
97
|
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
|
94
98
|
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
|
95
99
|
descriptor->rawPremultiplied = AttrAsBool(input, "rawPremultiplied");
|
|
100
|
+
descriptor->rawPageHeight = AttrAsUint32(input, "rawPageHeight");
|
|
96
101
|
}
|
|
97
102
|
// Multi-page input (GIF, TIFF, PDF)
|
|
98
103
|
if (HasAttr(input, "pages")) {
|
|
@@ -101,19 +106,35 @@ namespace sharp {
|
|
|
101
106
|
if (HasAttr(input, "page")) {
|
|
102
107
|
descriptor->page = AttrAsUint32(input, "page");
|
|
103
108
|
}
|
|
109
|
+
// SVG
|
|
110
|
+
if (HasAttr(input, "svgStylesheet")) {
|
|
111
|
+
descriptor->svgStylesheet = AttrAsStr(input, "svgStylesheet");
|
|
112
|
+
}
|
|
113
|
+
if (HasAttr(input, "svgHighBitdepth")) {
|
|
114
|
+
descriptor->svgHighBitdepth = AttrAsBool(input, "svgHighBitdepth");
|
|
115
|
+
}
|
|
104
116
|
// Multi-level input (OpenSlide)
|
|
105
|
-
if (HasAttr(input, "
|
|
106
|
-
descriptor->
|
|
117
|
+
if (HasAttr(input, "openSlideLevel")) {
|
|
118
|
+
descriptor->openSlideLevel = AttrAsUint32(input, "openSlideLevel");
|
|
107
119
|
}
|
|
108
120
|
// subIFD (OME-TIFF)
|
|
109
121
|
if (HasAttr(input, "subifd")) {
|
|
110
|
-
descriptor->
|
|
122
|
+
descriptor->tiffSubifd = AttrAsInt32(input, "tiffSubifd");
|
|
123
|
+
}
|
|
124
|
+
// // PDF background color
|
|
125
|
+
if (HasAttr(input, "pdfBackground")) {
|
|
126
|
+
descriptor->pdfBackground = AttrAsVectorOfDouble(input, "pdfBackground");
|
|
127
|
+
}
|
|
128
|
+
// Use JPEG 2000 oneshot mode?
|
|
129
|
+
if (HasAttr(input, "jp2Oneshot")) {
|
|
130
|
+
descriptor->jp2Oneshot = AttrAsBool(input, "jp2Oneshot");
|
|
111
131
|
}
|
|
112
132
|
// Create new image
|
|
113
133
|
if (HasAttr(input, "createChannels")) {
|
|
114
134
|
descriptor->createChannels = AttrAsUint32(input, "createChannels");
|
|
115
135
|
descriptor->createWidth = AttrAsUint32(input, "createWidth");
|
|
116
136
|
descriptor->createHeight = AttrAsUint32(input, "createHeight");
|
|
137
|
+
descriptor->createPageHeight = AttrAsUint32(input, "createPageHeight");
|
|
117
138
|
if (HasAttr(input, "createNoiseType")) {
|
|
118
139
|
descriptor->createNoiseType = AttrAsStr(input, "createNoiseType");
|
|
119
140
|
descriptor->createNoiseMean = AttrAsDouble(input, "createNoiseMean");
|
|
@@ -156,12 +177,34 @@ namespace sharp {
|
|
|
156
177
|
descriptor->textWrap = AttrAsEnum<VipsTextWrap>(input, "textWrap", VIPS_TYPE_TEXT_WRAP);
|
|
157
178
|
}
|
|
158
179
|
}
|
|
159
|
-
//
|
|
180
|
+
// Join images together
|
|
181
|
+
if (HasAttr(input, "joinAnimated")) {
|
|
182
|
+
descriptor->joinAnimated = AttrAsBool(input, "joinAnimated");
|
|
183
|
+
}
|
|
184
|
+
if (HasAttr(input, "joinAcross")) {
|
|
185
|
+
descriptor->joinAcross = AttrAsUint32(input, "joinAcross");
|
|
186
|
+
}
|
|
187
|
+
if (HasAttr(input, "joinShim")) {
|
|
188
|
+
descriptor->joinShim = AttrAsUint32(input, "joinShim");
|
|
189
|
+
}
|
|
190
|
+
if (HasAttr(input, "joinBackground")) {
|
|
191
|
+
descriptor->joinBackground = AttrAsVectorOfDouble(input, "joinBackground");
|
|
192
|
+
}
|
|
193
|
+
if (HasAttr(input, "joinHalign")) {
|
|
194
|
+
descriptor->joinHalign = AttrAsEnum<VipsAlign>(input, "joinHalign", VIPS_TYPE_ALIGN);
|
|
195
|
+
}
|
|
196
|
+
if (HasAttr(input, "joinValign")) {
|
|
197
|
+
descriptor->joinValign = AttrAsEnum<VipsAlign>(input, "joinValign", VIPS_TYPE_ALIGN);
|
|
198
|
+
}
|
|
160
199
|
descriptor->limitInputPixels = static_cast<uint64_t>(AttrAsInt64(input, "limitInputPixels"));
|
|
161
|
-
|
|
162
|
-
|
|
200
|
+
descriptor->limitInputChannels = static_cast<uint64_t>(AttrAsInt64(input, "limitInputChannels"));
|
|
201
|
+
if (HasAttr(input, "access")) {
|
|
202
|
+
descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
|
203
|
+
}
|
|
163
204
|
// Remove safety features and allow unlimited input
|
|
164
205
|
descriptor->unlimited = AttrAsBool(input, "unlimited");
|
|
206
|
+
// Use the EXIF orientation to auto orient the image
|
|
207
|
+
descriptor->autoOrient = AttrAsBool(input, "autoOrient");
|
|
165
208
|
return descriptor;
|
|
166
209
|
}
|
|
167
210
|
|
|
@@ -244,6 +287,9 @@ namespace sharp {
|
|
|
244
287
|
case ImageType::FITS: id = "fits"; break;
|
|
245
288
|
case ImageType::EXR: id = "exr"; break;
|
|
246
289
|
case ImageType::JXL: id = "jxl"; break;
|
|
290
|
+
case ImageType::RAD: id = "rad"; break;
|
|
291
|
+
case ImageType::DCRAW: id = "dcraw"; break;
|
|
292
|
+
case ImageType::UHDR: id = "uhdr"; break;
|
|
247
293
|
case ImageType::VIPS: id = "vips"; break;
|
|
248
294
|
case ImageType::RAW: id = "raw"; break;
|
|
249
295
|
case ImageType::UNKNOWN: id = "unknown"; break;
|
|
@@ -290,6 +336,13 @@ namespace sharp {
|
|
|
290
336
|
{ "VipsForeignLoadOpenexr", ImageType::EXR },
|
|
291
337
|
{ "VipsForeignLoadJxlFile", ImageType::JXL },
|
|
292
338
|
{ "VipsForeignLoadJxlBuffer", ImageType::JXL },
|
|
339
|
+
{ "VipsForeignLoadRadFile", ImageType::RAD },
|
|
340
|
+
{ "VipsForeignLoadRadBuffer", ImageType::RAD },
|
|
341
|
+
{ "VipsForeignLoadDcRawFile", ImageType::DCRAW },
|
|
342
|
+
{ "VipsForeignLoadDcRawBuffer", ImageType::DCRAW },
|
|
343
|
+
{ "VipsForeignLoadUhdr", ImageType::UHDR },
|
|
344
|
+
{ "VipsForeignLoadUhdrFile", ImageType::UHDR },
|
|
345
|
+
{ "VipsForeignLoadUhdrBuffer", ImageType::UHDR },
|
|
293
346
|
{ "VipsForeignLoadVips", ImageType::VIPS },
|
|
294
347
|
{ "VipsForeignLoadVipsFile", ImageType::VIPS },
|
|
295
348
|
{ "VipsForeignLoadRaw", ImageType::RAW }
|
|
@@ -307,6 +360,9 @@ namespace sharp {
|
|
|
307
360
|
imageType = it->second;
|
|
308
361
|
}
|
|
309
362
|
}
|
|
363
|
+
if (imageType == ImageType::UHDR) {
|
|
364
|
+
imageType = ImageType::JPEG;
|
|
365
|
+
}
|
|
310
366
|
return imageType;
|
|
311
367
|
}
|
|
312
368
|
|
|
@@ -326,6 +382,9 @@ namespace sharp {
|
|
|
326
382
|
imageType = ImageType::MISSING;
|
|
327
383
|
}
|
|
328
384
|
}
|
|
385
|
+
if (imageType == ImageType::UHDR) {
|
|
386
|
+
imageType = ImageType::JPEG;
|
|
387
|
+
}
|
|
329
388
|
return imageType;
|
|
330
389
|
}
|
|
331
390
|
|
|
@@ -351,9 +410,68 @@ namespace sharp {
|
|
|
351
410
|
imageType == ImageType::JPEG ||
|
|
352
411
|
imageType == ImageType::PNG ||
|
|
353
412
|
imageType == ImageType::SVG ||
|
|
413
|
+
imageType == ImageType::TIFF ||
|
|
354
414
|
imageType == ImageType::HEIF;
|
|
355
415
|
}
|
|
356
416
|
|
|
417
|
+
/*
|
|
418
|
+
Format-specific options builder
|
|
419
|
+
*/
|
|
420
|
+
vips::VOption* GetOptionsForImageType(ImageType imageType, InputDescriptor *descriptor) {
|
|
421
|
+
vips::VOption *option = VImage::option()
|
|
422
|
+
->set("access", descriptor->access)
|
|
423
|
+
->set("fail_on", descriptor->failOn);
|
|
424
|
+
if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) {
|
|
425
|
+
option->set("unlimited", true);
|
|
426
|
+
}
|
|
427
|
+
if (ImageTypeSupportsPage(imageType)) {
|
|
428
|
+
option->set("n", descriptor->pages);
|
|
429
|
+
option->set("page", std::max(0, descriptor->page));
|
|
430
|
+
}
|
|
431
|
+
switch (imageType) {
|
|
432
|
+
case ImageType::SVG:
|
|
433
|
+
option->set("dpi", descriptor->density)
|
|
434
|
+
->set("stylesheet", descriptor->svgStylesheet.data())
|
|
435
|
+
->set("high_bitdepth", descriptor->svgHighBitdepth);
|
|
436
|
+
break;
|
|
437
|
+
case ImageType::TIFF:
|
|
438
|
+
option->set("subifd", descriptor->tiffSubifd);
|
|
439
|
+
break;
|
|
440
|
+
case ImageType::PDF:
|
|
441
|
+
option->set("dpi", descriptor->density)
|
|
442
|
+
->set("background", descriptor->pdfBackground);
|
|
443
|
+
break;
|
|
444
|
+
case ImageType::OPENSLIDE:
|
|
445
|
+
option->set("level", descriptor->openSlideLevel);
|
|
446
|
+
break;
|
|
447
|
+
case ImageType::JP2:
|
|
448
|
+
option->set("oneshot", descriptor->jp2Oneshot);
|
|
449
|
+
break;
|
|
450
|
+
case ImageType::MAGICK:
|
|
451
|
+
option->set("density", std::to_string(descriptor->density).data());
|
|
452
|
+
break;
|
|
453
|
+
default:
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
return option;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/*
|
|
460
|
+
Should HEIF image be re-opened using the primary item?
|
|
461
|
+
*/
|
|
462
|
+
static bool HeifPrimaryPageReopen(VImage image, InputDescriptor *descriptor) {
|
|
463
|
+
if (image.get_typeof(VIPS_META_N_PAGES) == G_TYPE_INT && image.get_typeof("heif-primary") == G_TYPE_INT) {
|
|
464
|
+
if (image.get_int(VIPS_META_N_PAGES) > 1 && descriptor->pages == 1 && descriptor->page == -1) {
|
|
465
|
+
int const pagePrimary = image.get_int("heif-primary");
|
|
466
|
+
if (pagePrimary != 0) {
|
|
467
|
+
descriptor->page = pagePrimary;
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
|
|
357
475
|
/*
|
|
358
476
|
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
|
359
477
|
*/
|
|
@@ -371,6 +489,10 @@ namespace sharp {
|
|
|
371
489
|
} else {
|
|
372
490
|
image.get_image()->Type = is8bit ? VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_RGB16;
|
|
373
491
|
}
|
|
492
|
+
if (descriptor->rawPageHeight > 0) {
|
|
493
|
+
image.set(VIPS_META_PAGE_HEIGHT, descriptor->rawPageHeight);
|
|
494
|
+
image.set(VIPS_META_N_PAGES, static_cast<int>(descriptor->rawHeight / descriptor->rawPageHeight));
|
|
495
|
+
}
|
|
374
496
|
if (descriptor->rawPremultiplied) {
|
|
375
497
|
image = image.unpremultiply();
|
|
376
498
|
}
|
|
@@ -380,37 +502,19 @@ namespace sharp {
|
|
|
380
502
|
imageType = DetermineImageType(descriptor->buffer, descriptor->bufferLength);
|
|
381
503
|
if (imageType != ImageType::UNKNOWN) {
|
|
382
504
|
try {
|
|
383
|
-
vips::VOption *option =
|
|
384
|
-
->set("access", descriptor->access)
|
|
385
|
-
->set("fail_on", descriptor->failOn);
|
|
386
|
-
if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) {
|
|
387
|
-
option->set("unlimited", true);
|
|
388
|
-
}
|
|
389
|
-
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
|
390
|
-
option->set("dpi", descriptor->density);
|
|
391
|
-
}
|
|
392
|
-
if (imageType == ImageType::MAGICK) {
|
|
393
|
-
option->set("density", std::to_string(descriptor->density).data());
|
|
394
|
-
}
|
|
395
|
-
if (ImageTypeSupportsPage(imageType)) {
|
|
396
|
-
option->set("n", descriptor->pages);
|
|
397
|
-
option->set("page", descriptor->page);
|
|
398
|
-
}
|
|
399
|
-
if (imageType == ImageType::OPENSLIDE) {
|
|
400
|
-
option->set("level", descriptor->level);
|
|
401
|
-
}
|
|
402
|
-
if (imageType == ImageType::TIFF) {
|
|
403
|
-
option->set("subifd", descriptor->subifd);
|
|
404
|
-
}
|
|
505
|
+
vips::VOption *option = GetOptionsForImageType(imageType, descriptor);
|
|
405
506
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
|
406
507
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
407
508
|
image = SetDensity(image, descriptor->density);
|
|
509
|
+
} else if (imageType == ImageType::HEIF && HeifPrimaryPageReopen(image, descriptor)) {
|
|
510
|
+
option = GetOptionsForImageType(imageType, descriptor);
|
|
511
|
+
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
|
408
512
|
}
|
|
409
|
-
} catch (
|
|
410
|
-
throw
|
|
513
|
+
} catch (std::runtime_error const &err) {
|
|
514
|
+
throw std::runtime_error(std::string("Input buffer has corrupt header: ") + err.what());
|
|
411
515
|
}
|
|
412
516
|
} else {
|
|
413
|
-
throw
|
|
517
|
+
throw std::runtime_error("Input buffer contains unsupported image format");
|
|
414
518
|
}
|
|
415
519
|
}
|
|
416
520
|
} else {
|
|
@@ -441,6 +545,10 @@ namespace sharp {
|
|
|
441
545
|
channels < 3 ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB))
|
|
442
546
|
.new_from_image(background);
|
|
443
547
|
}
|
|
548
|
+
if (descriptor->createPageHeight > 0) {
|
|
549
|
+
image.set(VIPS_META_PAGE_HEIGHT, descriptor->createPageHeight);
|
|
550
|
+
image.set(VIPS_META_N_PAGES, static_cast<int>(descriptor->createHeight / descriptor->createPageHeight));
|
|
551
|
+
}
|
|
444
552
|
image = image.cast(VIPS_FORMAT_UCHAR);
|
|
445
553
|
imageType = ImageType::RAW;
|
|
446
554
|
} else if (descriptor->textValue.length() > 0) {
|
|
@@ -477,44 +585,26 @@ namespace sharp {
|
|
|
477
585
|
imageType = DetermineImageType(descriptor->file.data());
|
|
478
586
|
if (imageType == ImageType::MISSING) {
|
|
479
587
|
if (descriptor->file.find("<svg") != std::string::npos) {
|
|
480
|
-
throw
|
|
588
|
+
throw std::runtime_error("Input file is missing, did you mean "
|
|
481
589
|
"sharp(Buffer.from('" + descriptor->file.substr(0, 8) + "...')?");
|
|
482
590
|
}
|
|
483
|
-
throw
|
|
591
|
+
throw std::runtime_error("Input file is missing: " + descriptor->file);
|
|
484
592
|
}
|
|
485
593
|
if (imageType != ImageType::UNKNOWN) {
|
|
486
594
|
try {
|
|
487
|
-
vips::VOption *option =
|
|
488
|
-
->set("access", descriptor->access)
|
|
489
|
-
->set("fail_on", descriptor->failOn);
|
|
490
|
-
if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) {
|
|
491
|
-
option->set("unlimited", true);
|
|
492
|
-
}
|
|
493
|
-
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
|
494
|
-
option->set("dpi", descriptor->density);
|
|
495
|
-
}
|
|
496
|
-
if (imageType == ImageType::MAGICK) {
|
|
497
|
-
option->set("density", std::to_string(descriptor->density).data());
|
|
498
|
-
}
|
|
499
|
-
if (ImageTypeSupportsPage(imageType)) {
|
|
500
|
-
option->set("n", descriptor->pages);
|
|
501
|
-
option->set("page", descriptor->page);
|
|
502
|
-
}
|
|
503
|
-
if (imageType == ImageType::OPENSLIDE) {
|
|
504
|
-
option->set("level", descriptor->level);
|
|
505
|
-
}
|
|
506
|
-
if (imageType == ImageType::TIFF) {
|
|
507
|
-
option->set("subifd", descriptor->subifd);
|
|
508
|
-
}
|
|
595
|
+
vips::VOption *option = GetOptionsForImageType(imageType, descriptor);
|
|
509
596
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
|
510
597
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
511
598
|
image = SetDensity(image, descriptor->density);
|
|
599
|
+
} else if (imageType == ImageType::HEIF && HeifPrimaryPageReopen(image, descriptor)) {
|
|
600
|
+
option = GetOptionsForImageType(imageType, descriptor);
|
|
601
|
+
image = VImage::new_from_file(descriptor->file.data(), option);
|
|
512
602
|
}
|
|
513
|
-
} catch (
|
|
514
|
-
throw
|
|
603
|
+
} catch (std::runtime_error const &err) {
|
|
604
|
+
throw std::runtime_error(std::string("Input file has corrupt header: ") + err.what());
|
|
515
605
|
}
|
|
516
606
|
} else {
|
|
517
|
-
throw
|
|
607
|
+
throw std::runtime_error("Input file contains unsupported image format");
|
|
518
608
|
}
|
|
519
609
|
}
|
|
520
610
|
}
|
|
@@ -522,7 +612,10 @@ namespace sharp {
|
|
|
522
612
|
// Limit input images to a given number of pixels, where pixels = width * height
|
|
523
613
|
if (descriptor->limitInputPixels > 0 &&
|
|
524
614
|
static_cast<uint64_t>(image.width()) * image.height() > descriptor->limitInputPixels) {
|
|
525
|
-
throw
|
|
615
|
+
throw std::runtime_error("Input image exceeds pixel limit");
|
|
616
|
+
}
|
|
617
|
+
if (descriptor->limitInputChannels > 0 && static_cast<uint64_t>(image.bands()) > descriptor->limitInputChannels) {
|
|
618
|
+
throw std::runtime_error("Input image exceeds channel limit");
|
|
526
619
|
}
|
|
527
620
|
return std::make_tuple(image, imageType);
|
|
528
621
|
}
|
|
@@ -542,7 +635,7 @@ namespace sharp {
|
|
|
542
635
|
if (HasProfile(image)) {
|
|
543
636
|
size_t length;
|
|
544
637
|
const void *data = image.get_blob(VIPS_META_ICC_NAME, &length);
|
|
545
|
-
icc.first = static_cast<char*>(
|
|
638
|
+
icc.first = static_cast<char*>(vips_malloc(reinterpret_cast<VipsObject*>(image.get_image()), length));
|
|
546
639
|
icc.second = length;
|
|
547
640
|
memcpy(icc.first, data, length);
|
|
548
641
|
}
|
|
@@ -555,19 +648,11 @@ namespace sharp {
|
|
|
555
648
|
VImage SetProfile(VImage image, std::pair<char*, size_t> icc) {
|
|
556
649
|
if (icc.first != nullptr) {
|
|
557
650
|
image = image.copy();
|
|
558
|
-
image.set(VIPS_META_ICC_NAME,
|
|
651
|
+
image.set(VIPS_META_ICC_NAME, nullptr, icc.first, icc.second);
|
|
559
652
|
}
|
|
560
653
|
return image;
|
|
561
654
|
}
|
|
562
655
|
|
|
563
|
-
/*
|
|
564
|
-
Does this image have an alpha channel?
|
|
565
|
-
Uses colour space interpretation with number of channels to guess this.
|
|
566
|
-
*/
|
|
567
|
-
bool HasAlpha(VImage image) {
|
|
568
|
-
return image.has_alpha();
|
|
569
|
-
}
|
|
570
|
-
|
|
571
656
|
static void* RemoveExifCallback(VipsImage *image, char const *field, GValue *value, void *data) {
|
|
572
657
|
std::vector<std::string> *fieldNames = static_cast<std::vector<std::string> *>(data);
|
|
573
658
|
std::string fieldName(field);
|
|
@@ -624,22 +709,21 @@ namespace sharp {
|
|
|
624
709
|
*/
|
|
625
710
|
VImage SetAnimationProperties(VImage image, int nPages, int pageHeight, std::vector<int> delay, int loop) {
|
|
626
711
|
bool hasDelay = !delay.empty();
|
|
627
|
-
|
|
628
|
-
// Avoid a copy if none of the animation properties are needed.
|
|
629
|
-
if (nPages == 1 && !hasDelay && loop == -1) return image;
|
|
630
|
-
|
|
631
|
-
if (delay.size() == 1) {
|
|
632
|
-
// We have just one delay, repeat that value for all frames.
|
|
633
|
-
delay.insert(delay.end(), nPages - 1, delay[0]);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
// Attaching metadata, need to copy the image.
|
|
637
712
|
VImage copy = image.copy();
|
|
638
713
|
|
|
639
714
|
// Only set page-height if we have more than one page, or this could
|
|
640
715
|
// accidentally turn into an animated image later.
|
|
641
716
|
if (nPages > 1) copy.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
|
642
|
-
if (hasDelay)
|
|
717
|
+
if (hasDelay) {
|
|
718
|
+
if (delay.size() == 1) {
|
|
719
|
+
// We have just one delay, repeat that value for all frames.
|
|
720
|
+
delay.insert(delay.end(), nPages - 1, delay[0]);
|
|
721
|
+
}
|
|
722
|
+
copy.set("delay", delay);
|
|
723
|
+
}
|
|
724
|
+
if (nPages == 1 && !hasDelay && loop == -1) {
|
|
725
|
+
loop = 1;
|
|
726
|
+
}
|
|
643
727
|
if (loop != -1) copy.set("loop", loop);
|
|
644
728
|
|
|
645
729
|
return copy;
|
|
@@ -707,19 +791,19 @@ namespace sharp {
|
|
|
707
791
|
: image.height();
|
|
708
792
|
if (imageType == ImageType::JPEG) {
|
|
709
793
|
if (image.width() > 65535 || height > 65535) {
|
|
710
|
-
throw
|
|
794
|
+
throw std::runtime_error("Processed image is too large for the JPEG format");
|
|
711
795
|
}
|
|
712
796
|
} else if (imageType == ImageType::WEBP) {
|
|
713
797
|
if (image.width() > 16383 || height > 16383) {
|
|
714
|
-
throw
|
|
798
|
+
throw std::runtime_error("Processed image is too large for the WebP format");
|
|
715
799
|
}
|
|
716
800
|
} else if (imageType == ImageType::GIF) {
|
|
717
801
|
if (image.width() > 65535 || height > 65535) {
|
|
718
|
-
throw
|
|
802
|
+
throw std::runtime_error("Processed image is too large for the GIF format");
|
|
719
803
|
}
|
|
720
804
|
} else if (imageType == ImageType::HEIF) {
|
|
721
805
|
if (image.width() > 16384 || height > 16384) {
|
|
722
|
-
throw
|
|
806
|
+
throw std::runtime_error("Processed image is too large for the HEIF format");
|
|
723
807
|
}
|
|
724
808
|
}
|
|
725
809
|
}
|
|
@@ -925,14 +1009,6 @@ namespace sharp {
|
|
|
925
1009
|
return interpretation == VIPS_INTERPRETATION_RGB16 || interpretation == VIPS_INTERPRETATION_GREY16;
|
|
926
1010
|
}
|
|
927
1011
|
|
|
928
|
-
/*
|
|
929
|
-
Return the image alpha maximum. Useful for combining alpha bands. scRGB
|
|
930
|
-
images are 0 - 1 for image data, but the alpha is 0 - 255.
|
|
931
|
-
*/
|
|
932
|
-
double MaximumImageAlpha(VipsInterpretation const interpretation) {
|
|
933
|
-
return Is16Bit(interpretation) ? 65535.0 : 255.0;
|
|
934
|
-
}
|
|
935
|
-
|
|
936
1012
|
/*
|
|
937
1013
|
Convert RGBA value to another colourspace
|
|
938
1014
|
*/
|
|
@@ -975,25 +1051,25 @@ namespace sharp {
|
|
|
975
1051
|
0.0722 * colour[2])
|
|
976
1052
|
};
|
|
977
1053
|
}
|
|
978
|
-
// Add alpha channel to alphaColour colour
|
|
979
|
-
if (colour[3] < 255.0 ||
|
|
980
|
-
|
|
1054
|
+
// Add alpha channel(s) to alphaColour colour
|
|
1055
|
+
if (colour[3] < 255.0 || image.has_alpha()) {
|
|
1056
|
+
int extraBands = image.bands() > 4 ? image.bands() - 3 : 1;
|
|
1057
|
+
alphaColour.insert(alphaColour.end(), extraBands, colour[3] * multiplier);
|
|
981
1058
|
}
|
|
982
1059
|
// Ensure alphaColour colour uses correct colourspace
|
|
983
1060
|
alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation(), premultiply);
|
|
984
1061
|
// Add non-transparent alpha channel, if required
|
|
985
|
-
if (colour[3] < 255.0 && !
|
|
986
|
-
image = image.
|
|
987
|
-
VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier).cast(image.format()));
|
|
1062
|
+
if (colour[3] < 255.0 && !image.has_alpha()) {
|
|
1063
|
+
image = image.bandjoin_const({ 255 * multiplier });
|
|
988
1064
|
}
|
|
989
1065
|
return std::make_tuple(image, alphaColour);
|
|
990
1066
|
}
|
|
991
1067
|
|
|
992
1068
|
/*
|
|
993
|
-
Removes alpha
|
|
1069
|
+
Removes alpha channels, if any.
|
|
994
1070
|
*/
|
|
995
1071
|
VImage RemoveAlpha(VImage image) {
|
|
996
|
-
|
|
1072
|
+
while (image.bands() > 1 && image.has_alpha()) {
|
|
997
1073
|
image = image.extract_band(0, VImage::option()->set("n", image.bands() - 1));
|
|
998
1074
|
}
|
|
999
1075
|
return image;
|
|
@@ -1003,10 +1079,8 @@ namespace sharp {
|
|
|
1003
1079
|
Ensures alpha channel, if missing.
|
|
1004
1080
|
*/
|
|
1005
1081
|
VImage EnsureAlpha(VImage image, double const value) {
|
|
1006
|
-
if (!
|
|
1007
|
-
|
|
1008
|
-
alpha.push_back(value * sharp::MaximumImageAlpha(image.interpretation()));
|
|
1009
|
-
image = image.bandjoin_const(alpha);
|
|
1082
|
+
if (!image.has_alpha()) {
|
|
1083
|
+
image = image.bandjoin_const({ value * vips_interpretation_max_alpha(image.interpretation()) });
|
|
1010
1084
|
}
|
|
1011
1085
|
return image;
|
|
1012
1086
|
}
|
|
@@ -1088,4 +1162,22 @@ namespace sharp {
|
|
|
1088
1162
|
}
|
|
1089
1163
|
return image;
|
|
1090
1164
|
}
|
|
1165
|
+
|
|
1166
|
+
/*
|
|
1167
|
+
Does this image have a gain map?
|
|
1168
|
+
*/
|
|
1169
|
+
bool HasGainMap(VImage image) {
|
|
1170
|
+
return image.get_typeof("gainmap") == VIPS_TYPE_BLOB ||
|
|
1171
|
+
image.get_typeof("gainmap-data") == VIPS_TYPE_BLOB;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
/*
|
|
1175
|
+
Removes gain map, if any.
|
|
1176
|
+
*/
|
|
1177
|
+
VImage RemoveGainMap(VImage image) {
|
|
1178
|
+
VImage copy = image.copy();
|
|
1179
|
+
copy.remove("gainmap");
|
|
1180
|
+
copy.remove("gainmap-data");
|
|
1181
|
+
return copy;
|
|
1182
|
+
}
|
|
1091
1183
|
} // namespace sharp
|