@ohos-ports/sharp 0.34.5-beta.8 → 0.35.5-beta.1
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/LICENSE +191 -0
- package/README.md +112 -0
- package/{lib/channel.js → dist/channel.cjs} +1 -1
- package/dist/channel.mjs +177 -0
- package/{lib/colour.js → dist/colour.cjs} +12 -8
- package/dist/colour.mjs +199 -0
- package/{lib/composite.js → dist/composite.cjs} +8 -7
- package/dist/composite.mjs +213 -0
- package/{lib/constructor.js → dist/constructor.cjs} +42 -30
- package/dist/constructor.mjs +511 -0
- package/dist/index.cjs +25 -0
- package/{lib/index.d.ts → dist/index.d.cts} +113 -85
- package/dist/index.d.mts +2046 -0
- package/dist/index.mjs +25 -0
- package/{lib/input.js → dist/input.cjs} +47 -37
- package/dist/input.mjs +819 -0
- package/{lib/is.js → dist/is.cjs} +9 -3
- package/dist/is.mjs +149 -0
- package/{lib/libvips.js → dist/libvips.cjs} +35 -30
- package/dist/libvips.mjs +213 -0
- package/{lib/operation.js → dist/operation.cjs} +39 -53
- package/dist/operation.mjs +1002 -0
- package/{lib/output.js → dist/output.cjs} +167 -47
- package/dist/output.mjs +1786 -0
- package/{lib/resize.js → dist/resize.cjs} +54 -32
- package/dist/resize.mjs +617 -0
- package/dist/sharp.cjs +177 -0
- package/dist/sharp.mjs +177 -0
- package/{lib/utility.js → dist/utility.cjs} +23 -25
- package/dist/utility.mjs +301 -0
- package/install/build.js +3 -3
- package/package.json +56 -56
- package/src/binding.gyp +21 -269
- package/src/common.cc +81 -25
- package/src/common.h +23 -4
- package/src/metadata.cc +66 -8
- package/src/metadata.h +6 -1
- package/src/operations.cc +25 -8
- package/src/operations.h +1 -1
- package/src/pipeline.cc +231 -72
- package/src/pipeline.h +15 -1
- package/src/stats.cc +6 -6
- package/src/utilities.cc +8 -7
- package/install/check.js +0 -73
- package/lib/index.js +0 -16
- package/lib/sharp.js +0 -154
package/src/pipeline.cc
CHANGED
|
@@ -56,9 +56,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
56
56
|
hasAlpha |= image.has_alpha();
|
|
57
57
|
}
|
|
58
58
|
if (hasAlpha) {
|
|
59
|
-
for (
|
|
60
|
-
if (!
|
|
61
|
-
|
|
59
|
+
for (size_t i = 0; i < images.size(); i++) {
|
|
60
|
+
if (!images[i].has_alpha()) {
|
|
61
|
+
images[i] = sharp::EnsureAlpha(images[i], 1);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
} else {
|
|
@@ -84,7 +84,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
84
84
|
if (nPages == -1) {
|
|
85
85
|
// Resolve the number of pages if we need to render until the end of the document
|
|
86
86
|
nPages = image.get_typeof(VIPS_META_N_PAGES) != 0
|
|
87
|
-
? image.get_int(VIPS_META_N_PAGES) - baton->input->page
|
|
87
|
+
? image.get_int(VIPS_META_N_PAGES) - std::max(0, baton->input->page)
|
|
88
88
|
: 1;
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -94,7 +94,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
94
94
|
// Calculate angle of rotation
|
|
95
95
|
VipsAngle rotation = VIPS_ANGLE_D0;
|
|
96
96
|
VipsAngle autoRotation = VIPS_ANGLE_D0;
|
|
97
|
+
VipsAngle gainMapRotation = VIPS_ANGLE_D0;
|
|
97
98
|
bool autoFlop = false;
|
|
99
|
+
bool gainMapFlip = false;
|
|
100
|
+
bool gainMapFlop = false;
|
|
98
101
|
|
|
99
102
|
if (baton->input->autoOrient) {
|
|
100
103
|
// Rotate and flip image according to Exif orientation
|
|
@@ -115,11 +118,13 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
115
118
|
MultiPageUnsupported(nPages, "Rotate");
|
|
116
119
|
}
|
|
117
120
|
image = image.rot(autoRotation);
|
|
121
|
+
gainMapRotation = autoRotation;
|
|
118
122
|
autoRotation = VIPS_ANGLE_D0;
|
|
119
123
|
}
|
|
120
124
|
if (autoFlop) {
|
|
121
125
|
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
122
126
|
autoFlop = false;
|
|
127
|
+
gainMapFlop = true;
|
|
123
128
|
}
|
|
124
129
|
}
|
|
125
130
|
|
|
@@ -128,20 +133,24 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
128
133
|
if (baton->flip) {
|
|
129
134
|
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
130
135
|
baton->flip = false;
|
|
136
|
+
gainMapFlip = true;
|
|
131
137
|
}
|
|
132
138
|
if (baton->flop) {
|
|
133
139
|
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
134
140
|
baton->flop = false;
|
|
141
|
+
gainMapFlop = true;
|
|
135
142
|
}
|
|
136
143
|
if (rotation != VIPS_ANGLE_D0) {
|
|
137
144
|
if (rotation != VIPS_ANGLE_D180) {
|
|
138
145
|
MultiPageUnsupported(nPages, "Rotate");
|
|
139
146
|
}
|
|
140
147
|
image = image.rot(rotation);
|
|
148
|
+
gainMapRotation = rotation;
|
|
141
149
|
rotation = VIPS_ANGLE_D0;
|
|
142
150
|
}
|
|
143
151
|
if (baton->rotationAngle != 0.0) {
|
|
144
152
|
MultiPageUnsupported(nPages, "Rotate");
|
|
153
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Rotate");
|
|
145
154
|
std::vector<double> background;
|
|
146
155
|
std::tie(image, background) = sharp::ApplyAlpha(image, baton->rotationBackground, false);
|
|
147
156
|
image = image.rotate(baton->rotationAngle, VImage::option()->set("background", background)).copy_memory();
|
|
@@ -152,8 +161,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
152
161
|
// Trim
|
|
153
162
|
if (baton->trimThreshold >= 0.0) {
|
|
154
163
|
MultiPageUnsupported(nPages, "Trim");
|
|
164
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Trim");
|
|
155
165
|
image = sharp::StaySequential(image);
|
|
156
|
-
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold, baton->trimLineArt);
|
|
166
|
+
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold, baton->trimLineArt, baton->trimMargin);
|
|
157
167
|
baton->trimOffsetLeft = image.xoffset();
|
|
158
168
|
baton->trimOffsetTop = image.yoffset();
|
|
159
169
|
}
|
|
@@ -203,9 +213,11 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
203
213
|
// - the width or height parameters are specified;
|
|
204
214
|
// - gamma correction doesn't need to be applied;
|
|
205
215
|
// - trimming or pre-resize extract isn't required;
|
|
216
|
+
// - gain map processing is not required;
|
|
206
217
|
// - input colourspace is not specified;
|
|
207
218
|
bool const shouldPreShrink = (targetResizeWidth > 0 || targetResizeHeight > 0) &&
|
|
208
219
|
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold < 0.0 &&
|
|
220
|
+
!baton->keepGainMap && !baton->withGainMap &&
|
|
209
221
|
baton->colourspacePipeline == VIPS_INTERPRETATION_LAST && !(shouldOrientBefore || shouldRotateBefore);
|
|
210
222
|
|
|
211
223
|
if (shouldPreShrink) {
|
|
@@ -274,7 +286,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
274
286
|
}
|
|
275
287
|
sharp::SetDensity(image, baton->input->density);
|
|
276
288
|
if (image.width() > 32767 || image.height() > 32767) {
|
|
277
|
-
throw
|
|
289
|
+
throw std::runtime_error("Input SVG image will exceed 32767x32767 pixel limit when scaled");
|
|
278
290
|
}
|
|
279
291
|
} else if (inputImageType == sharp::ImageType::PDF) {
|
|
280
292
|
if (baton->input->buffer != nullptr) {
|
|
@@ -290,12 +302,42 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
290
302
|
}
|
|
291
303
|
} else {
|
|
292
304
|
if (inputImageType == sharp::ImageType::SVG && (image.width() > 32767 || image.height() > 32767)) {
|
|
293
|
-
throw
|
|
305
|
+
throw std::runtime_error("Input SVG image exceeds 32767x32767 pixel limit");
|
|
294
306
|
}
|
|
295
307
|
}
|
|
296
308
|
if (baton->input->autoOrient) {
|
|
297
309
|
image = sharp::RemoveExifOrientation(image);
|
|
298
310
|
}
|
|
311
|
+
VImage gainMap;
|
|
312
|
+
int gainMapScaleFactor = 1;
|
|
313
|
+
if (sharp::HasGainMap(image)) {
|
|
314
|
+
if (baton->keepGainMap) {
|
|
315
|
+
gainMap = image.gainmap();
|
|
316
|
+
if (image.get_typeof("gainmap-scale-factor") == G_TYPE_INT) {
|
|
317
|
+
gainMapScaleFactor = image.get_int("gainmap-scale-factor");
|
|
318
|
+
}
|
|
319
|
+
if (gainMapFlip) {
|
|
320
|
+
gainMap = gainMap.flip(VIPS_DIRECTION_VERTICAL);
|
|
321
|
+
}
|
|
322
|
+
if (gainMapFlop) {
|
|
323
|
+
gainMap = gainMap.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
324
|
+
}
|
|
325
|
+
if (gainMapRotation != VIPS_ANGLE_D0) {
|
|
326
|
+
gainMap = gainMap.rot(gainMapRotation);
|
|
327
|
+
}
|
|
328
|
+
if (baton->topOffsetPre != -1) {
|
|
329
|
+
gainMap = gainMap.extract_area(
|
|
330
|
+
baton->leftOffsetPre / gainMapScaleFactor, baton->topOffsetPre / gainMapScaleFactor,
|
|
331
|
+
baton->widthPre / gainMapScaleFactor, baton->heightPre / gainMapScaleFactor);
|
|
332
|
+
}
|
|
333
|
+
} else if (baton->withGainMap) {
|
|
334
|
+
image = image.uhdr2scRGB();
|
|
335
|
+
}
|
|
336
|
+
image = sharp::RemoveGainMap(image);
|
|
337
|
+
} else {
|
|
338
|
+
baton->keepGainMap = false;
|
|
339
|
+
baton->withGainMap = false;
|
|
340
|
+
}
|
|
299
341
|
|
|
300
342
|
// Any pre-shrinking may already have been done
|
|
301
343
|
inputWidth = image.width();
|
|
@@ -335,7 +377,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
335
377
|
image.interpretation() != VIPS_INTERPRETATION_LABS &&
|
|
336
378
|
image.interpretation() != VIPS_INTERPRETATION_GREY16 &&
|
|
337
379
|
baton->colourspacePipeline != VIPS_INTERPRETATION_CMYK &&
|
|
338
|
-
!baton->input->ignoreIcc
|
|
380
|
+
!baton->input->ignoreIcc && !baton->withGainMap
|
|
339
381
|
) {
|
|
340
382
|
// Convert to sRGB/P3 using embedded profile
|
|
341
383
|
try {
|
|
@@ -393,6 +435,11 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
393
435
|
image = image.resize(1.0 / hshrink, VImage::option()
|
|
394
436
|
->set("vscale", 1.0 / vshrink)
|
|
395
437
|
->set("kernel", baton->kernel));
|
|
438
|
+
if (baton->keepGainMap) {
|
|
439
|
+
gainMap = gainMap.resize(1.0 / hshrink, VImage::option()
|
|
440
|
+
->set("vscale", 1.0 / vshrink)
|
|
441
|
+
->set("kernel", baton->kernel));
|
|
442
|
+
}
|
|
396
443
|
}
|
|
397
444
|
|
|
398
445
|
image = sharp::StaySequential(image,
|
|
@@ -405,14 +452,23 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
405
452
|
MultiPageUnsupported(nPages, "Rotate");
|
|
406
453
|
}
|
|
407
454
|
image = image.rot(autoRotation);
|
|
455
|
+
if (baton->keepGainMap) {
|
|
456
|
+
gainMap = sharp::StaySequential(gainMap).rot(autoRotation);
|
|
457
|
+
}
|
|
408
458
|
}
|
|
409
459
|
// Mirror vertically (up-down) about the x-axis
|
|
410
460
|
if (baton->flip) {
|
|
411
461
|
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
462
|
+
if (baton->keepGainMap) {
|
|
463
|
+
gainMap = sharp::StaySequential(gainMap).flip(VIPS_DIRECTION_VERTICAL);
|
|
464
|
+
}
|
|
412
465
|
}
|
|
413
466
|
// Mirror horizontally (left-right) about the y-axis
|
|
414
467
|
if (baton->flop != autoFlop) {
|
|
415
468
|
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
469
|
+
if (baton->keepGainMap) {
|
|
470
|
+
gainMap = gainMap.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
471
|
+
}
|
|
416
472
|
}
|
|
417
473
|
// Rotate post-extract 90-angle
|
|
418
474
|
if (rotation != VIPS_ANGLE_D0) {
|
|
@@ -420,6 +476,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
420
476
|
MultiPageUnsupported(nPages, "Rotate");
|
|
421
477
|
}
|
|
422
478
|
image = image.rot(rotation);
|
|
479
|
+
if (baton->keepGainMap) {
|
|
480
|
+
gainMap = sharp::StaySequential(gainMap).rot(rotation);
|
|
481
|
+
}
|
|
423
482
|
}
|
|
424
483
|
|
|
425
484
|
// Join additional color channels to the image
|
|
@@ -466,6 +525,12 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
466
525
|
: image.embed(left, top, width, height, VImage::option()
|
|
467
526
|
->set("extend", VIPS_EXTEND_BACKGROUND)
|
|
468
527
|
->set("background", background));
|
|
528
|
+
if (baton->keepGainMap) {
|
|
529
|
+
gainMap = gainMap.embed(left / gainMapScaleFactor, top / gainMapScaleFactor,
|
|
530
|
+
width / gainMapScaleFactor, height / gainMapScaleFactor, VImage::option()
|
|
531
|
+
->set("extend", VIPS_EXTEND_BACKGROUND)
|
|
532
|
+
->set("background", 0));
|
|
533
|
+
}
|
|
469
534
|
} else if (baton->canvas == sharp::Canvas::CROP) {
|
|
470
535
|
if (baton->width > inputWidth) {
|
|
471
536
|
baton->width = inputWidth;
|
|
@@ -486,12 +551,17 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
486
551
|
? sharp::CropMultiPage(image,
|
|
487
552
|
left, top, width, height, nPages, &targetPageHeight)
|
|
488
553
|
: image.extract_area(left, top, width, height);
|
|
554
|
+
if (baton->keepGainMap) {
|
|
555
|
+
gainMap = gainMap.extract_area(left / gainMapScaleFactor, top / gainMapScaleFactor,
|
|
556
|
+
width / gainMapScaleFactor, height / gainMapScaleFactor);
|
|
557
|
+
}
|
|
489
558
|
} else {
|
|
490
559
|
int attention_x;
|
|
491
560
|
int attention_y;
|
|
492
561
|
|
|
493
562
|
// Attention-based or Entropy-based crop
|
|
494
563
|
MultiPageUnsupported(nPages, "Resize strategy");
|
|
564
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Resize strategy");
|
|
495
565
|
image = sharp::StaySequential(image);
|
|
496
566
|
image = image.smartcrop(baton->width, baton->height, VImage::option()
|
|
497
567
|
->set("interesting", baton->position == 16 ? VIPS_INTERESTING_ENTROPY : VIPS_INTERESTING_ATTENTION)
|
|
@@ -511,10 +581,14 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
511
581
|
// Rotate post-extract non-90 angle
|
|
512
582
|
if (!baton->rotateBefore && baton->rotationAngle != 0.0) {
|
|
513
583
|
MultiPageUnsupported(nPages, "Rotate");
|
|
584
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Rotate");
|
|
514
585
|
image = sharp::StaySequential(image);
|
|
515
586
|
std::vector<double> background;
|
|
516
587
|
std::tie(image, background) = sharp::ApplyAlpha(image, baton->rotationBackground, shouldPremultiplyAlpha);
|
|
517
588
|
image = image.rotate(baton->rotationAngle, VImage::option()->set("background", background));
|
|
589
|
+
if (baton->keepGainMap) {
|
|
590
|
+
gainMap = gainMap.rotate(baton->rotationAngle, VImage::option()->set("background", 0));
|
|
591
|
+
}
|
|
518
592
|
}
|
|
519
593
|
|
|
520
594
|
// Post extraction
|
|
@@ -523,18 +597,23 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
523
597
|
image = sharp::CropMultiPage(image,
|
|
524
598
|
baton->leftOffsetPost, baton->topOffsetPost, baton->widthPost, baton->heightPost,
|
|
525
599
|
nPages, &targetPageHeight);
|
|
526
|
-
|
|
527
600
|
// heightPost is used in the info object, so update to reflect the number of pages
|
|
528
601
|
baton->heightPost *= nPages;
|
|
529
602
|
} else {
|
|
530
603
|
image = image.extract_area(
|
|
531
604
|
baton->leftOffsetPost, baton->topOffsetPost, baton->widthPost, baton->heightPost);
|
|
605
|
+
if (baton->keepGainMap) {
|
|
606
|
+
gainMap = gainMap.extract_area(baton->leftOffsetPost / gainMapScaleFactor,
|
|
607
|
+
baton->topOffsetPost / gainMapScaleFactor, baton->widthPost / gainMapScaleFactor,
|
|
608
|
+
baton->heightPost / gainMapScaleFactor);
|
|
609
|
+
}
|
|
532
610
|
}
|
|
533
611
|
}
|
|
534
612
|
|
|
535
613
|
// Affine transform
|
|
536
614
|
if (!baton->affineMatrix.empty()) {
|
|
537
615
|
MultiPageUnsupported(nPages, "Affine");
|
|
616
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Affine");
|
|
538
617
|
image = sharp::StaySequential(image);
|
|
539
618
|
std::vector<double> background;
|
|
540
619
|
std::tie(image, background) = sharp::ApplyAlpha(image, baton->affineBackground, shouldPremultiplyAlpha);
|
|
@@ -554,26 +633,25 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
554
633
|
baton->width = image.width() + baton->extendLeft + baton->extendRight;
|
|
555
634
|
baton->height = (nPages > 1 ? targetPageHeight : image.height()) + baton->extendTop + baton->extendBottom;
|
|
556
635
|
|
|
636
|
+
std::vector<double> background;
|
|
557
637
|
if (baton->extendWith == VIPS_EXTEND_BACKGROUND) {
|
|
558
|
-
std::vector<double> background;
|
|
559
638
|
std::tie(image, background) = sharp::ApplyAlpha(image, baton->extendBackground, shouldPremultiplyAlpha);
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
image
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
VImage::option()->set("extend", baton->extendWith));
|
|
639
|
+
}
|
|
640
|
+
image = sharp::StaySequential(image, nPages > 1 || baton->extendWith != VIPS_EXTEND_BACKGROUND);
|
|
641
|
+
auto options = VImage::option()->set("extend", baton->extendWith);
|
|
642
|
+
if (baton->extendWith == VIPS_EXTEND_BACKGROUND) {
|
|
643
|
+
options->set("background", background);
|
|
644
|
+
}
|
|
645
|
+
image = nPages > 1
|
|
646
|
+
? sharp::EmbedMultiPage(image,
|
|
647
|
+
baton->extendLeft, baton->extendTop, baton->width, baton->height,
|
|
648
|
+
baton->extendWith, background, nPages, &targetPageHeight)
|
|
649
|
+
: image.embed(baton->extendLeft, baton->extendTop, baton->width, baton->height, options);
|
|
650
|
+
if (baton->keepGainMap) {
|
|
651
|
+
gainMap = gainMap.embed(baton->extendLeft / gainMapScaleFactor, baton->extendTop / gainMapScaleFactor,
|
|
652
|
+
baton->width / gainMapScaleFactor, baton->height / gainMapScaleFactor, VImage::option()
|
|
653
|
+
->set("extend", baton->extendWith)
|
|
654
|
+
->set("background", 0));
|
|
577
655
|
}
|
|
578
656
|
}
|
|
579
657
|
// Median - must happen before blurring, due to the utility of blurring after thresholding
|
|
@@ -600,6 +678,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
600
678
|
// Blur
|
|
601
679
|
if (shouldBlur) {
|
|
602
680
|
image = sharp::Blur(image, baton->blurSigma, baton->precision, baton->minAmpl);
|
|
681
|
+
if (baton->keepGainMap) {
|
|
682
|
+
gainMap = sharp::Blur(gainMap, baton->blurSigma, baton->precision, baton->minAmpl);
|
|
683
|
+
}
|
|
603
684
|
}
|
|
604
685
|
|
|
605
686
|
// Unflatten the image
|
|
@@ -609,6 +690,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
609
690
|
|
|
610
691
|
// Convolve
|
|
611
692
|
if (shouldConv) {
|
|
693
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Convolve");
|
|
612
694
|
image = sharp::Convolve(image,
|
|
613
695
|
baton->convKernelWidth, baton->convKernelHeight,
|
|
614
696
|
baton->convKernelScale, baton->convKernelOffset,
|
|
@@ -617,11 +699,13 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
617
699
|
|
|
618
700
|
// Recomb
|
|
619
701
|
if (!baton->recombMatrix.empty()) {
|
|
702
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Recomb");
|
|
620
703
|
image = sharp::Recomb(image, baton->recombMatrix);
|
|
621
704
|
}
|
|
622
705
|
|
|
623
706
|
// Modulate
|
|
624
707
|
if (baton->brightness != 1.0 || baton->saturation != 1.0 || baton->hue != 0.0 || baton->lightness != 0.0) {
|
|
708
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Modulate");
|
|
625
709
|
image = sharp::Modulate(image, baton->brightness, baton->saturation, baton->hue, baton->lightness);
|
|
626
710
|
}
|
|
627
711
|
|
|
@@ -639,6 +723,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
639
723
|
|
|
640
724
|
// Composite
|
|
641
725
|
if (shouldComposite) {
|
|
726
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Composite");
|
|
642
727
|
std::vector<VImage> images = { image };
|
|
643
728
|
std::vector<int> modes, xs, ys;
|
|
644
729
|
for (Composite *composite : baton->composite) {
|
|
@@ -667,7 +752,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
667
752
|
|
|
668
753
|
// Verify within current dimensions
|
|
669
754
|
if (compositeImage.width() > image.width() || compositeImage.height() > image.height()) {
|
|
670
|
-
throw
|
|
755
|
+
throw std::runtime_error("Image to composite must have same dimensions or smaller");
|
|
671
756
|
}
|
|
672
757
|
// Check if overlay is tiled
|
|
673
758
|
if (composite->tile) {
|
|
@@ -751,18 +836,21 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
751
836
|
|
|
752
837
|
// Apply normalisation - stretch luminance to cover full dynamic range
|
|
753
838
|
if (baton->normalise) {
|
|
839
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Normalise");
|
|
754
840
|
image = sharp::StaySequential(image);
|
|
755
841
|
image = sharp::Normalise(image, baton->normaliseLower, baton->normaliseUpper);
|
|
756
842
|
}
|
|
757
843
|
|
|
758
844
|
// Apply contrast limiting adaptive histogram equalization (CLAHE)
|
|
759
845
|
if (baton->claheWidth != 0 && baton->claheHeight != 0) {
|
|
846
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Clahe");
|
|
760
847
|
image = sharp::StaySequential(image);
|
|
761
848
|
image = sharp::Clahe(image, baton->claheWidth, baton->claheHeight, baton->claheMaxSlope);
|
|
762
849
|
}
|
|
763
850
|
|
|
764
851
|
// Apply bitwise boolean operation between images
|
|
765
852
|
if (baton->boolean != nullptr) {
|
|
853
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Boolean");
|
|
766
854
|
VImage booleanImage;
|
|
767
855
|
sharp::ImageType booleanImageType = sharp::ImageType::UNKNOWN;
|
|
768
856
|
baton->boolean->access = access;
|
|
@@ -805,6 +893,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
805
893
|
|
|
806
894
|
// Extract channel
|
|
807
895
|
if (baton->extractChannel > -1) {
|
|
896
|
+
KeepGainMapUnsupported(baton->keepGainMap, "Extract channel");
|
|
808
897
|
if (baton->extractChannel >= image.bands()) {
|
|
809
898
|
if (baton->extractChannel == 3 && image.has_alpha()) {
|
|
810
899
|
baton->extractChannel = image.bands() - 1;
|
|
@@ -839,6 +928,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
839
928
|
// Negate the colours in the image
|
|
840
929
|
if (baton->negate) {
|
|
841
930
|
image = sharp::Negate(image, baton->negateAlpha);
|
|
931
|
+
if (baton->keepGainMap) {
|
|
932
|
+
gainMap = sharp::Negate(gainMap, false);
|
|
933
|
+
}
|
|
842
934
|
}
|
|
843
935
|
|
|
844
936
|
// Override EXIF Orientation tag
|
|
@@ -877,6 +969,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
877
969
|
baton->pageHeightOut = image.get_int(VIPS_META_PAGE_HEIGHT);
|
|
878
970
|
baton->pagesOut = image.get_int(VIPS_META_N_PAGES);
|
|
879
971
|
}
|
|
972
|
+
baton->hasAlphaOut = image.has_alpha();
|
|
880
973
|
|
|
881
974
|
// Output
|
|
882
975
|
sharp::SetTimeout(image, baton->timeoutSeconds);
|
|
@@ -885,18 +978,27 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
885
978
|
if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == sharp::ImageType::JPEG)) {
|
|
886
979
|
// Write JPEG to buffer
|
|
887
980
|
sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
|
|
888
|
-
VipsArea *area
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
981
|
+
VipsArea *area;
|
|
982
|
+
if (baton->keepGainMap) {
|
|
983
|
+
image = ReattachGainMap(image, gainMap, baton);
|
|
984
|
+
area = reinterpret_cast<VipsArea*>(image.uhdrsave_buffer(VImage::option()
|
|
985
|
+
->set("keep", baton->keepMetadata)
|
|
986
|
+
->set("Q", baton->jpegQuality)
|
|
987
|
+
->set("gainmap_scale_factor", gainMapScaleFactor)));
|
|
988
|
+
} else {
|
|
989
|
+
area = reinterpret_cast<VipsArea*>(image.jpegsave_buffer(VImage::option()
|
|
990
|
+
->set("keep", baton->keepMetadata)
|
|
991
|
+
->set("Q", baton->jpegQuality)
|
|
992
|
+
->set("interlace", baton->jpegProgressive)
|
|
993
|
+
->set("subsample_mode", baton->jpegChromaSubsampling == "4:4:4"
|
|
994
|
+
? VIPS_FOREIGN_SUBSAMPLE_OFF
|
|
995
|
+
: VIPS_FOREIGN_SUBSAMPLE_ON)
|
|
996
|
+
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
|
997
|
+
->set("quant_table", baton->jpegQuantisationTable)
|
|
998
|
+
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
|
999
|
+
->set("optimize_scans", baton->jpegOptimiseScans)
|
|
1000
|
+
->set("optimize_coding", baton->jpegOptimiseCoding)));
|
|
1001
|
+
}
|
|
900
1002
|
baton->bufferOut = static_cast<char*>(area->data);
|
|
901
1003
|
baton->bufferOutLength = area->length;
|
|
902
1004
|
area->free_fn = nullptr;
|
|
@@ -907,6 +1009,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
907
1009
|
} else {
|
|
908
1010
|
baton->channels = std::min(baton->channels, 3);
|
|
909
1011
|
}
|
|
1012
|
+
baton->hasAlphaOut = false;
|
|
910
1013
|
} else if (baton->formatOut == "jp2" || (baton->formatOut == "input"
|
|
911
1014
|
&& inputImageType == sharp::ImageType::JP2)) {
|
|
912
1015
|
// Write JP2 to Buffer
|
|
@@ -957,6 +1060,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
957
1060
|
->set("effort", baton->webpEffort)
|
|
958
1061
|
->set("min_size", baton->webpMinSize)
|
|
959
1062
|
->set("mixed", baton->webpMixed)
|
|
1063
|
+
->set("exact", baton->webpExact)
|
|
960
1064
|
->set("alpha_q", baton->webpAlphaQuality)));
|
|
961
1065
|
baton->bufferOut = static_cast<char*>(area->data);
|
|
962
1066
|
baton->bufferOutLength = area->length;
|
|
@@ -988,6 +1092,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
988
1092
|
if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) {
|
|
989
1093
|
sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
|
|
990
1094
|
baton->channels = std::min(baton->channels, 3);
|
|
1095
|
+
baton->hasAlphaOut = false;
|
|
991
1096
|
}
|
|
992
1097
|
// Cast pixel values to float, if required
|
|
993
1098
|
if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) {
|
|
@@ -1024,6 +1129,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1024
1129
|
->set("compression", baton->heifCompression)
|
|
1025
1130
|
->set("effort", baton->heifEffort)
|
|
1026
1131
|
->set("bitdepth", baton->heifBitdepth)
|
|
1132
|
+
->set("tune", baton->heifTune.c_str())
|
|
1027
1133
|
->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
|
|
1028
1134
|
? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
|
|
1029
1135
|
->set("lossless", baton->heifLossless)));
|
|
@@ -1046,6 +1152,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1046
1152
|
area->free_fn = nullptr;
|
|
1047
1153
|
vips_area_unref(area);
|
|
1048
1154
|
baton->formatOut = "dz";
|
|
1155
|
+
if (baton->tileFormat == "jpeg") {
|
|
1156
|
+
baton->hasAlphaOut = false;
|
|
1157
|
+
}
|
|
1049
1158
|
} else if (baton->formatOut == "jxl" ||
|
|
1050
1159
|
(baton->formatOut == "input" && inputImageType == sharp::ImageType::JXL)) {
|
|
1051
1160
|
// Write JXL to buffer
|
|
@@ -1076,20 +1185,19 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1076
1185
|
// Get raw image data
|
|
1077
1186
|
baton->bufferOut = static_cast<char*>(image.write_to_memory(&baton->bufferOutLength));
|
|
1078
1187
|
if (baton->bufferOut == nullptr) {
|
|
1079
|
-
(
|
|
1080
|
-
return Error();
|
|
1188
|
+
throw std::runtime_error("Could not allocate enough memory for raw output");
|
|
1081
1189
|
}
|
|
1082
1190
|
baton->formatOut = "raw";
|
|
1083
1191
|
} else {
|
|
1084
1192
|
// Unsupported output format
|
|
1085
|
-
(
|
|
1193
|
+
auto unsupported = std::string("Unsupported output format ");
|
|
1086
1194
|
if (baton->formatOut == "input") {
|
|
1087
|
-
|
|
1088
|
-
|
|
1195
|
+
unsupported.append("when trying to match input format of ");
|
|
1196
|
+
unsupported.append(ImageTypeId(inputImageType));
|
|
1089
1197
|
} else {
|
|
1090
|
-
|
|
1198
|
+
unsupported.append(baton->formatOut);
|
|
1091
1199
|
}
|
|
1092
|
-
|
|
1200
|
+
throw std::runtime_error(unsupported);
|
|
1093
1201
|
}
|
|
1094
1202
|
} else {
|
|
1095
1203
|
// File output
|
|
@@ -1112,20 +1220,29 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1112
1220
|
(willMatchInput && inputImageType == sharp::ImageType::JPEG)) {
|
|
1113
1221
|
// Write JPEG to file
|
|
1114
1222
|
sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
->
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
->
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1223
|
+
if (baton->keepGainMap) {
|
|
1224
|
+
image = ReattachGainMap(image, gainMap, baton);
|
|
1225
|
+
image.uhdrsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
1226
|
+
->set("keep", baton->keepMetadata)
|
|
1227
|
+
->set("Q", baton->jpegQuality)
|
|
1228
|
+
->set("gainmap_scale_factor", gainMapScaleFactor));
|
|
1229
|
+
} else {
|
|
1230
|
+
image.jpegsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
1231
|
+
->set("keep", baton->keepMetadata)
|
|
1232
|
+
->set("Q", baton->jpegQuality)
|
|
1233
|
+
->set("interlace", baton->jpegProgressive)
|
|
1234
|
+
->set("subsample_mode", baton->jpegChromaSubsampling == "4:4:4"
|
|
1235
|
+
? VIPS_FOREIGN_SUBSAMPLE_OFF
|
|
1236
|
+
: VIPS_FOREIGN_SUBSAMPLE_ON)
|
|
1237
|
+
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
|
1238
|
+
->set("quant_table", baton->jpegQuantisationTable)
|
|
1239
|
+
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
|
1240
|
+
->set("optimize_scans", baton->jpegOptimiseScans)
|
|
1241
|
+
->set("optimize_coding", baton->jpegOptimiseCoding));
|
|
1242
|
+
}
|
|
1127
1243
|
baton->formatOut = "jpeg";
|
|
1128
1244
|
baton->channels = std::min(baton->channels, 3);
|
|
1245
|
+
baton->hasAlphaOut = false;
|
|
1129
1246
|
} else if (baton->formatOut == "jp2" || (mightMatchInput && isJp2) ||
|
|
1130
1247
|
(willMatchInput && (inputImageType == sharp::ImageType::JP2))) {
|
|
1131
1248
|
// Write JP2 to file
|
|
@@ -1168,6 +1285,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1168
1285
|
->set("effort", baton->webpEffort)
|
|
1169
1286
|
->set("min_size", baton->webpMinSize)
|
|
1170
1287
|
->set("mixed", baton->webpMixed)
|
|
1288
|
+
->set("exact", baton->webpExact)
|
|
1171
1289
|
->set("alpha_q", baton->webpAlphaQuality));
|
|
1172
1290
|
baton->formatOut = "webp";
|
|
1173
1291
|
} else if (baton->formatOut == "gif" || (mightMatchInput && isGif) ||
|
|
@@ -1191,6 +1309,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1191
1309
|
if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) {
|
|
1192
1310
|
sharp::AssertImageTypeDimensions(image, sharp::ImageType::JPEG);
|
|
1193
1311
|
baton->channels = std::min(baton->channels, 3);
|
|
1312
|
+
baton->hasAlphaOut = false;
|
|
1194
1313
|
}
|
|
1195
1314
|
// Cast pixel values to float, if required
|
|
1196
1315
|
if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) {
|
|
@@ -1223,6 +1342,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1223
1342
|
->set("compression", baton->heifCompression)
|
|
1224
1343
|
->set("effort", baton->heifEffort)
|
|
1225
1344
|
->set("bitdepth", baton->heifBitdepth)
|
|
1345
|
+
->set("tune", baton->heifTune.c_str())
|
|
1226
1346
|
->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
|
|
1227
1347
|
? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
|
|
1228
1348
|
->set("lossless", baton->heifLossless));
|
|
@@ -1250,6 +1370,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1250
1370
|
vips::VOption *options = BuildOptionsDZ(baton);
|
|
1251
1371
|
image.dzsave(const_cast<char*>(baton->fileOut.data()), options);
|
|
1252
1372
|
baton->formatOut = "dz";
|
|
1373
|
+
if (baton->tileFormat == "jpeg") {
|
|
1374
|
+
baton->hasAlphaOut = false;
|
|
1375
|
+
}
|
|
1253
1376
|
} else if (baton->formatOut == "v" || (mightMatchInput && isV) ||
|
|
1254
1377
|
(willMatchInput && inputImageType == sharp::ImageType::VIPS)) {
|
|
1255
1378
|
// Write V to file
|
|
@@ -1262,7 +1385,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1262
1385
|
return Error();
|
|
1263
1386
|
}
|
|
1264
1387
|
}
|
|
1265
|
-
} catch (
|
|
1388
|
+
} catch (std::runtime_error const &err) {
|
|
1266
1389
|
char const *what = err.what();
|
|
1267
1390
|
if (what && what[0]) {
|
|
1268
1391
|
(baton->err).append(what);
|
|
@@ -1290,11 +1413,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1290
1413
|
if (baton->errUseWarning) {
|
|
1291
1414
|
(baton->err).append("\n").append(warning);
|
|
1292
1415
|
} else {
|
|
1293
|
-
debuglog.
|
|
1416
|
+
debuglog.SHARP_CALLBACK_FN_NAME(Receiver().Value(), { Napi::String::New(env, warning) });
|
|
1294
1417
|
}
|
|
1295
1418
|
warning = sharp::VipsWarningPop();
|
|
1296
1419
|
}
|
|
1297
|
-
|
|
1298
1420
|
if (baton->err.empty()) {
|
|
1299
1421
|
int width = baton->width;
|
|
1300
1422
|
int height = baton->height;
|
|
@@ -1335,14 +1457,22 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1335
1457
|
info.Set("pageHeight", static_cast<int32_t>(baton->pageHeightOut));
|
|
1336
1458
|
info.Set("pages", static_cast<int32_t>(baton->pagesOut));
|
|
1337
1459
|
}
|
|
1460
|
+
info.Set("hasAlpha", baton->hasAlphaOut);
|
|
1338
1461
|
|
|
1339
1462
|
if (baton->bufferOutLength > 0) {
|
|
1340
|
-
// Add buffer size to info
|
|
1341
1463
|
info.Set("size", static_cast<uint32_t>(baton->bufferOutLength));
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1464
|
+
if (baton->typedArrayOut) {
|
|
1465
|
+
// ECMAScript ArrayBuffer with Uint8Array view
|
|
1466
|
+
Napi::TypedArrayOf<uint8_t> data = Napi::Buffer<char>::Copy(env,
|
|
1467
|
+
static_cast<char*>(baton->bufferOut), baton->bufferOutLength);
|
|
1468
|
+
sharp::FreeCallback(static_cast<char*>(baton->bufferOut), nullptr);
|
|
1469
|
+
Callback().SHARP_CALLBACK_FN_NAME(Receiver().Value(), { env.Null(), data, info });
|
|
1470
|
+
} else {
|
|
1471
|
+
// Node.js Buffer
|
|
1472
|
+
Napi::Buffer<char> data = Napi::Buffer<char>::NewOrCopy(env, static_cast<char*>(baton->bufferOut),
|
|
1473
|
+
baton->bufferOutLength, sharp::FreeCallback);
|
|
1474
|
+
Callback().SHARP_CALLBACK_FN_NAME(Receiver().Value(), { env.Null(), data, info });
|
|
1475
|
+
}
|
|
1346
1476
|
} else {
|
|
1347
1477
|
// Add file size to info
|
|
1348
1478
|
if (baton->formatOut != "dz" || sharp::IsDzZip(baton->fileOut)) {
|
|
@@ -1352,10 +1482,11 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1352
1482
|
info.Set("size", size);
|
|
1353
1483
|
} catch (...) {}
|
|
1354
1484
|
}
|
|
1355
|
-
Callback().
|
|
1485
|
+
Callback().SHARP_CALLBACK_FN_NAME(Receiver().Value(), { env.Null(), info });
|
|
1356
1486
|
}
|
|
1357
1487
|
} else {
|
|
1358
|
-
Callback().
|
|
1488
|
+
Callback().SHARP_CALLBACK_FN_NAME(Receiver().Value(),
|
|
1489
|
+
{ Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
|
1359
1490
|
}
|
|
1360
1491
|
|
|
1361
1492
|
// Delete baton
|
|
@@ -1376,7 +1507,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1376
1507
|
// Decrement processing task counter
|
|
1377
1508
|
sharp::counterProcess--;
|
|
1378
1509
|
Napi::Number queueLength = Napi::Number::New(env, static_cast<int>(sharp::counterQueue));
|
|
1379
|
-
queueListener.
|
|
1510
|
+
queueListener.SHARP_CALLBACK_FN_NAME(Receiver().Value(), { queueLength });
|
|
1380
1511
|
}
|
|
1381
1512
|
|
|
1382
1513
|
private:
|
|
@@ -1386,7 +1517,13 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1386
1517
|
|
|
1387
1518
|
void MultiPageUnsupported(int const pages, std::string op) {
|
|
1388
1519
|
if (pages > 1) {
|
|
1389
|
-
throw
|
|
1520
|
+
throw std::runtime_error(op + " is not supported for multi-page images");
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
void KeepGainMapUnsupported(bool const keepGainMap, std::string op) {
|
|
1525
|
+
if (keepGainMap) {
|
|
1526
|
+
throw std::runtime_error(op + " is not supported when keeping gain maps");
|
|
1390
1527
|
}
|
|
1391
1528
|
}
|
|
1392
1529
|
|
|
@@ -1469,6 +1606,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1469
1606
|
{"preset", vips_enum_nick(VIPS_TYPE_FOREIGN_WEBP_PRESET, baton->webpPreset)},
|
|
1470
1607
|
{"min_size", baton->webpMinSize ? "true" : "false"},
|
|
1471
1608
|
{"mixed", baton->webpMixed ? "true" : "false"},
|
|
1609
|
+
{"exact", baton->webpExact ? "true" : "false"},
|
|
1472
1610
|
{"effort", std::to_string(baton->webpEffort)}
|
|
1473
1611
|
};
|
|
1474
1612
|
suffix = AssembleSuffixString(".webp", options);
|
|
@@ -1507,6 +1645,21 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1507
1645
|
return options;
|
|
1508
1646
|
}
|
|
1509
1647
|
|
|
1648
|
+
VImage ReattachGainMap(VImage image, VImage gainMap, PipelineBaton *baton) {
|
|
1649
|
+
VipsArea *gainMapJpeg = reinterpret_cast<VipsArea*>(gainMap.jpegsave_buffer(VImage::option()
|
|
1650
|
+
->set("keep", FALSE)
|
|
1651
|
+
->set("Q", baton->jpegQuality)
|
|
1652
|
+
->set("subsample_mode", VIPS_FOREIGN_SUBSAMPLE_OFF)
|
|
1653
|
+
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
|
1654
|
+
->set("quant_table", baton->jpegQuantisationTable)
|
|
1655
|
+
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
|
1656
|
+
->set("optimize_coding", baton->jpegOptimiseCoding)));
|
|
1657
|
+
image = image.copy();
|
|
1658
|
+
image.set("gainmap-data", reinterpret_cast<VipsCallbackFn>(vips_area_free_cb),
|
|
1659
|
+
gainMapJpeg->data, gainMapJpeg->length);
|
|
1660
|
+
return image;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1510
1663
|
/*
|
|
1511
1664
|
Clear all thread-local data.
|
|
1512
1665
|
*/
|
|
@@ -1615,6 +1768,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1615
1768
|
baton->trimBackground = sharp::AttrAsVectorOfDouble(options, "trimBackground");
|
|
1616
1769
|
baton->trimThreshold = sharp::AttrAsDouble(options, "trimThreshold");
|
|
1617
1770
|
baton->trimLineArt = sharp::AttrAsBool(options, "trimLineArt");
|
|
1771
|
+
baton->trimMargin = sharp::AttrAsUint32(options, "trimMargin");
|
|
1618
1772
|
baton->gamma = sharp::AttrAsDouble(options, "gamma");
|
|
1619
1773
|
baton->gammaOut = sharp::AttrAsDouble(options, "gammaOut");
|
|
1620
1774
|
baton->linearA = sharp::AttrAsVectorOfDouble(options, "linearA");
|
|
@@ -1692,6 +1846,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1692
1846
|
// Output
|
|
1693
1847
|
baton->formatOut = sharp::AttrAsStr(options, "formatOut");
|
|
1694
1848
|
baton->fileOut = sharp::AttrAsStr(options, "fileOut");
|
|
1849
|
+
baton->typedArrayOut = sharp::AttrAsBool(options, "typedArrayOut");
|
|
1695
1850
|
baton->keepMetadata = sharp::AttrAsUint32(options, "keepMetadata");
|
|
1696
1851
|
baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
|
|
1697
1852
|
baton->withMetadataDensity = sharp::AttrAsDouble(options, "withMetadataDensity");
|
|
@@ -1706,6 +1861,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1706
1861
|
}
|
|
1707
1862
|
baton->withExifMerge = sharp::AttrAsBool(options, "withExifMerge");
|
|
1708
1863
|
baton->withXmp = sharp::AttrAsStr(options, "withXmp");
|
|
1864
|
+
baton->keepGainMap = sharp::AttrAsBool(options, "keepGainMap");
|
|
1865
|
+
baton->withGainMap = sharp::AttrAsBool(options, "withGainMap");
|
|
1709
1866
|
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
|
|
1710
1867
|
baton->loop = sharp::AttrAsUint32(options, "loop");
|
|
1711
1868
|
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
|
@@ -1741,6 +1898,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1741
1898
|
baton->webpEffort = sharp::AttrAsUint32(options, "webpEffort");
|
|
1742
1899
|
baton->webpMinSize = sharp::AttrAsBool(options, "webpMinSize");
|
|
1743
1900
|
baton->webpMixed = sharp::AttrAsBool(options, "webpMixed");
|
|
1901
|
+
baton->webpExact = sharp::AttrAsBool(options, "webpExact");
|
|
1744
1902
|
baton->gifBitdepth = sharp::AttrAsUint32(options, "gifBitdepth");
|
|
1745
1903
|
baton->gifEffort = sharp::AttrAsUint32(options, "gifEffort");
|
|
1746
1904
|
baton->gifDither = sharp::AttrAsDouble(options, "gifDither");
|
|
@@ -1775,6 +1933,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1775
1933
|
baton->heifEffort = sharp::AttrAsUint32(options, "heifEffort");
|
|
1776
1934
|
baton->heifChromaSubsampling = sharp::AttrAsStr(options, "heifChromaSubsampling");
|
|
1777
1935
|
baton->heifBitdepth = sharp::AttrAsUint32(options, "heifBitdepth");
|
|
1936
|
+
baton->heifTune = sharp::AttrAsStr(options, "heifTune");
|
|
1778
1937
|
baton->jxlDistance = sharp::AttrAsDouble(options, "jxlDistance");
|
|
1779
1938
|
baton->jxlDecodingTier = sharp::AttrAsUint32(options, "jxlDecodingTier");
|
|
1780
1939
|
baton->jxlEffort = sharp::AttrAsUint32(options, "jxlEffort");
|
|
@@ -1808,7 +1967,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1808
1967
|
|
|
1809
1968
|
// Increment queued task counter
|
|
1810
1969
|
Napi::Number queueLength = Napi::Number::New(info.Env(), static_cast<int>(++sharp::counterQueue));
|
|
1811
|
-
queueListener.
|
|
1970
|
+
queueListener.SHARP_CALLBACK_FN_NAME(info.This(), { queueLength });
|
|
1812
1971
|
|
|
1813
1972
|
return info.Env().Undefined();
|
|
1814
1973
|
}
|