sharp 0.30.7 → 0.31.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/README.md +1 -2
- package/binding.gyp +4 -3
- package/lib/composite.js +14 -0
- package/lib/constructor.js +41 -4
- package/lib/input.js +92 -0
- package/lib/libvips.js +1 -0
- package/lib/operation.js +57 -12
- package/lib/output.js +89 -25
- package/lib/resize.js +86 -12
- package/lib/utility.js +4 -0
- package/package.json +24 -23
- package/src/common.cc +93 -44
- package/src/common.h +32 -14
- package/src/libvips/cplusplus/VConnection.cpp +0 -1
- package/src/libvips/cplusplus/VError.cpp +0 -1
- package/src/libvips/cplusplus/VImage.cpp +27 -2
- package/src/libvips/cplusplus/VInterpolate.cpp +0 -1
- package/src/libvips/cplusplus/VRegion.cpp +27 -0
- package/src/libvips/cplusplus/vips-operators.cpp +16 -1
- package/src/operations.cc +72 -25
- package/src/operations.h +7 -2
- package/src/pipeline.cc +165 -164
- package/src/pipeline.h +18 -5
- package/src/sharp.cc +0 -1
- package/src/utilities.cc +13 -2
package/src/pipeline.cc
CHANGED
|
@@ -92,7 +92,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
// Rotate pre-extract
|
|
95
|
-
|
|
95
|
+
bool const shouldRotateBefore = baton->rotateBeforePreExtract &&
|
|
96
|
+
(rotation != VIPS_ANGLE_D0 || flip || flop || baton->rotationAngle != 0.0);
|
|
97
|
+
|
|
98
|
+
if (shouldRotateBefore) {
|
|
96
99
|
if (rotation != VIPS_ANGLE_D0) {
|
|
97
100
|
image = image.rot(rotation);
|
|
98
101
|
}
|
|
@@ -118,7 +121,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
118
121
|
// Trim
|
|
119
122
|
if (baton->trimThreshold > 0.0) {
|
|
120
123
|
MultiPageUnsupported(nPages, "Trim");
|
|
121
|
-
image = sharp::Trim(image, baton->trimThreshold);
|
|
124
|
+
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold);
|
|
122
125
|
baton->trimOffsetLeft = image.xoffset();
|
|
123
126
|
baton->trimOffsetTop = image.yoffset();
|
|
124
127
|
}
|
|
@@ -167,7 +170,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
167
170
|
// - input colourspace is not specified;
|
|
168
171
|
bool const shouldPreShrink = (targetResizeWidth > 0 || targetResizeHeight > 0) &&
|
|
169
172
|
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0 &&
|
|
170
|
-
baton->colourspaceInput == VIPS_INTERPRETATION_LAST;
|
|
173
|
+
baton->colourspaceInput == VIPS_INTERPRETATION_LAST && !shouldRotateBefore;
|
|
171
174
|
|
|
172
175
|
if (shouldPreShrink) {
|
|
173
176
|
// The common part of the shrink: the bit by which both axes must be shrunk
|
|
@@ -204,6 +207,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
204
207
|
vips::VOption *option = VImage::option()
|
|
205
208
|
->set("access", baton->input->access)
|
|
206
209
|
->set("shrink", jpegShrinkOnLoad)
|
|
210
|
+
->set("unlimited", baton->input->unlimited)
|
|
207
211
|
->set("fail_on", baton->input->failOn);
|
|
208
212
|
if (baton->input->buffer != nullptr) {
|
|
209
213
|
// Reload JPEG buffer
|
|
@@ -302,8 +306,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
302
306
|
if (
|
|
303
307
|
sharp::HasProfile(image) &&
|
|
304
308
|
image.interpretation() != VIPS_INTERPRETATION_LABS &&
|
|
305
|
-
image.interpretation() != VIPS_INTERPRETATION_GREY16
|
|
306
|
-
image.interpretation() != VIPS_INTERPRETATION_B_W
|
|
309
|
+
image.interpretation() != VIPS_INTERPRETATION_GREY16
|
|
307
310
|
) {
|
|
308
311
|
// Convert to sRGB/P3 using embedded profile
|
|
309
312
|
try {
|
|
@@ -322,16 +325,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
322
325
|
|
|
323
326
|
// Flatten image to remove alpha channel
|
|
324
327
|
if (baton->flatten && sharp::HasAlpha(image)) {
|
|
325
|
-
|
|
326
|
-
double const multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0;
|
|
327
|
-
// Background colour
|
|
328
|
-
std::vector<double> background {
|
|
329
|
-
baton->flattenBackground[0] * multiplier,
|
|
330
|
-
baton->flattenBackground[1] * multiplier,
|
|
331
|
-
baton->flattenBackground[2] * multiplier
|
|
332
|
-
};
|
|
333
|
-
image = image.flatten(VImage::option()
|
|
334
|
-
->set("background", background));
|
|
328
|
+
image = sharp::Flatten(image, baton->flattenBackground);
|
|
335
329
|
}
|
|
336
330
|
|
|
337
331
|
// Negate the colours in the image
|
|
@@ -353,11 +347,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
353
347
|
bool const shouldBlur = baton->blurSigma != 0.0;
|
|
354
348
|
bool const shouldConv = baton->convKernelWidth * baton->convKernelHeight > 0;
|
|
355
349
|
bool const shouldSharpen = baton->sharpenSigma != 0.0;
|
|
356
|
-
bool const shouldApplyMedian = baton->medianSize > 0;
|
|
357
350
|
bool const shouldComposite = !baton->composite.empty();
|
|
358
|
-
bool const shouldModulate = baton->brightness != 1.0 || baton->saturation != 1.0 ||
|
|
359
|
-
baton->hue != 0.0 || baton->lightness != 0.0;
|
|
360
|
-
bool const shouldApplyClahe = baton->claheWidth != 0 && baton->claheHeight != 0;
|
|
361
351
|
|
|
362
352
|
if (shouldComposite && !sharp::HasAlpha(image)) {
|
|
363
353
|
image = sharp::EnsureAlpha(image, 1);
|
|
@@ -366,26 +356,27 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
366
356
|
bool const shouldPremultiplyAlpha = sharp::HasAlpha(image) &&
|
|
367
357
|
(shouldResize || shouldBlur || shouldConv || shouldSharpen);
|
|
368
358
|
|
|
369
|
-
// Premultiply image alpha channel before all transformations to avoid
|
|
370
|
-
// dark fringing around bright pixels
|
|
371
|
-
// See: http://entropymine.com/imageworsener/resizealpha/
|
|
372
359
|
if (shouldPremultiplyAlpha) {
|
|
373
360
|
image = image.premultiply();
|
|
374
361
|
}
|
|
375
362
|
|
|
376
363
|
// Resize
|
|
377
364
|
if (shouldResize) {
|
|
378
|
-
VipsKernel kernel = static_cast<VipsKernel>(
|
|
379
|
-
vips_enum_from_nick(nullptr, VIPS_TYPE_KERNEL, baton->kernel.data()));
|
|
380
|
-
if (
|
|
381
|
-
kernel != VIPS_KERNEL_NEAREST && kernel != VIPS_KERNEL_CUBIC && kernel != VIPS_KERNEL_LANCZOS2 &&
|
|
382
|
-
kernel != VIPS_KERNEL_LANCZOS3 && kernel != VIPS_KERNEL_MITCHELL
|
|
383
|
-
) {
|
|
384
|
-
throw vips::VError("Unknown kernel");
|
|
385
|
-
}
|
|
386
365
|
image = image.resize(1.0 / hshrink, VImage::option()
|
|
387
366
|
->set("vscale", 1.0 / vshrink)
|
|
388
|
-
->set("kernel", kernel));
|
|
367
|
+
->set("kernel", baton->kernel));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Flip (mirror about Y axis)
|
|
371
|
+
if (baton->flip || flip) {
|
|
372
|
+
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
373
|
+
image = sharp::RemoveExifOrientation(image);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Flop (mirror about X axis)
|
|
377
|
+
if (baton->flop || flop) {
|
|
378
|
+
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
379
|
+
image = sharp::RemoveExifOrientation(image);
|
|
389
380
|
}
|
|
390
381
|
|
|
391
382
|
// Rotate post-extract 90-angle
|
|
@@ -402,18 +393,6 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
402
393
|
image = sharp::RemoveExifOrientation(image);
|
|
403
394
|
}
|
|
404
395
|
|
|
405
|
-
// Flip (mirror about Y axis)
|
|
406
|
-
if (baton->flip || flip) {
|
|
407
|
-
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
408
|
-
image = sharp::RemoveExifOrientation(image);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// Flop (mirror about X axis)
|
|
412
|
-
if (baton->flop || flop) {
|
|
413
|
-
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
414
|
-
image = sharp::RemoveExifOrientation(image);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
396
|
// Join additional color channels to the image
|
|
418
397
|
if (baton->joinChannelIn.size() > 0) {
|
|
419
398
|
VImage joinImage;
|
|
@@ -445,18 +424,12 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
445
424
|
std::tie(image, background) = sharp::ApplyAlpha(image, baton->resizeBackground, shouldPremultiplyAlpha);
|
|
446
425
|
|
|
447
426
|
// Embed
|
|
448
|
-
|
|
449
|
-
// Calculate where to position the embedded image if gravity specified, else center.
|
|
450
427
|
int left;
|
|
451
428
|
int top;
|
|
452
|
-
|
|
453
|
-
left = static_cast<int>(round((baton->width - inputWidth) / 2));
|
|
454
|
-
top = static_cast<int>(round((baton->height - inputHeight) / 2));
|
|
455
|
-
|
|
456
|
-
int width = std::max(inputWidth, baton->width);
|
|
457
|
-
int height = std::max(inputHeight, baton->height);
|
|
458
429
|
std::tie(left, top) = sharp::CalculateEmbedPosition(
|
|
459
430
|
inputWidth, inputHeight, baton->width, baton->height, baton->position);
|
|
431
|
+
int width = std::max(inputWidth, baton->width);
|
|
432
|
+
int height = std::max(inputHeight, baton->height);
|
|
460
433
|
|
|
461
434
|
image = nPages > 1
|
|
462
435
|
? sharp::EmbedMultiPage(image,
|
|
@@ -555,7 +528,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
555
528
|
VImage::option()->set("extend", VIPS_EXTEND_BACKGROUND)->set("background", background));
|
|
556
529
|
}
|
|
557
530
|
// Median - must happen before blurring, due to the utility of blurring after thresholding
|
|
558
|
-
if (
|
|
531
|
+
if (baton->medianSize > 0) {
|
|
559
532
|
image = image.median(baton->medianSize);
|
|
560
533
|
}
|
|
561
534
|
// Threshold - must happen before blurring, due to the utility of blurring after thresholding
|
|
@@ -581,7 +554,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
581
554
|
image = sharp::Recomb(image, baton->recombMatrix);
|
|
582
555
|
}
|
|
583
556
|
|
|
584
|
-
|
|
557
|
+
// Modulate
|
|
558
|
+
if (baton->brightness != 1.0 || baton->saturation != 1.0 || baton->hue != 0.0 || baton->lightness != 0.0) {
|
|
585
559
|
image = sharp::Modulate(image, baton->brightness, baton->saturation, baton->hue, baton->lightness);
|
|
586
560
|
}
|
|
587
561
|
|
|
@@ -591,6 +565,18 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
591
565
|
baton->sharpenX1, baton->sharpenY2, baton->sharpenY3);
|
|
592
566
|
}
|
|
593
567
|
|
|
568
|
+
// Reverse premultiplication after all transformations
|
|
569
|
+
if (shouldPremultiplyAlpha) {
|
|
570
|
+
image = image.unpremultiply();
|
|
571
|
+
// Cast pixel values to integer
|
|
572
|
+
if (sharp::Is16Bit(image.interpretation())) {
|
|
573
|
+
image = image.cast(VIPS_FORMAT_USHORT);
|
|
574
|
+
} else {
|
|
575
|
+
image = image.cast(VIPS_FORMAT_UCHAR);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
baton->premultiplied = shouldPremultiplyAlpha;
|
|
579
|
+
|
|
594
580
|
// Composite
|
|
595
581
|
if (shouldComposite) {
|
|
596
582
|
std::vector<VImage> images = { image };
|
|
@@ -668,28 +654,16 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
668
654
|
xs.push_back(left);
|
|
669
655
|
ys.push_back(top);
|
|
670
656
|
}
|
|
671
|
-
image =
|
|
657
|
+
image = VImage::composite(images, modes, VImage::option()->set("x", xs)->set("y", ys));
|
|
672
658
|
}
|
|
673
659
|
|
|
674
|
-
// Reverse premultiplication after all transformations:
|
|
675
|
-
if (shouldPremultiplyAlpha) {
|
|
676
|
-
image = image.unpremultiply();
|
|
677
|
-
// Cast pixel values to integer
|
|
678
|
-
if (sharp::Is16Bit(image.interpretation())) {
|
|
679
|
-
image = image.cast(VIPS_FORMAT_USHORT);
|
|
680
|
-
} else {
|
|
681
|
-
image = image.cast(VIPS_FORMAT_UCHAR);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
baton->premultiplied = shouldPremultiplyAlpha;
|
|
685
|
-
|
|
686
660
|
// Gamma decoding (brighten)
|
|
687
661
|
if (baton->gammaOut >= 1 && baton->gammaOut <= 3) {
|
|
688
662
|
image = sharp::Gamma(image, baton->gammaOut);
|
|
689
663
|
}
|
|
690
664
|
|
|
691
665
|
// Linear adjustment (a * in + b)
|
|
692
|
-
if (baton->linearA
|
|
666
|
+
if (!baton->linearA.empty()) {
|
|
693
667
|
image = sharp::Linear(image, baton->linearA, baton->linearB);
|
|
694
668
|
}
|
|
695
669
|
|
|
@@ -699,7 +673,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
699
673
|
}
|
|
700
674
|
|
|
701
675
|
// Apply contrast limiting adaptive histogram equalization (CLAHE)
|
|
702
|
-
if (
|
|
676
|
+
if (baton->claheWidth != 0 && baton->claheHeight != 0) {
|
|
703
677
|
image = sharp::Clahe(image, baton->claheWidth, baton->claheHeight, baton->claheMaxSlope);
|
|
704
678
|
}
|
|
705
679
|
|
|
@@ -873,6 +847,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
873
847
|
->set("near_lossless", baton->webpNearLossless)
|
|
874
848
|
->set("smart_subsample", baton->webpSmartSubsample)
|
|
875
849
|
->set("effort", baton->webpEffort)
|
|
850
|
+
->set("min_size", baton->webpMinSize)
|
|
851
|
+
->set("mixed", baton->webpMixed)
|
|
876
852
|
->set("alpha_q", baton->webpAlphaQuality)));
|
|
877
853
|
baton->bufferOut = static_cast<char*>(area->data);
|
|
878
854
|
baton->bufferOutLength = area->length;
|
|
@@ -887,6 +863,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
887
863
|
->set("strip", !baton->withMetadata)
|
|
888
864
|
->set("bitdepth", baton->gifBitdepth)
|
|
889
865
|
->set("effort", baton->gifEffort)
|
|
866
|
+
->set("reoptimise", baton->gifReoptimise)
|
|
890
867
|
->set("dither", baton->gifDither)));
|
|
891
868
|
baton->bufferOut = static_cast<char*>(area->data);
|
|
892
869
|
baton->bufferOutLength = area->length;
|
|
@@ -925,12 +902,13 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
925
902
|
} else if (baton->formatOut == "heif" ||
|
|
926
903
|
(baton->formatOut == "input" && inputImageType == sharp::ImageType::HEIF)) {
|
|
927
904
|
// Write HEIF to buffer
|
|
928
|
-
image = sharp::RemoveAnimationProperties(image);
|
|
905
|
+
image = sharp::RemoveAnimationProperties(image).cast(VIPS_FORMAT_UCHAR);
|
|
929
906
|
VipsArea *area = reinterpret_cast<VipsArea*>(image.heifsave_buffer(VImage::option()
|
|
930
907
|
->set("strip", !baton->withMetadata)
|
|
931
908
|
->set("Q", baton->heifQuality)
|
|
932
909
|
->set("compression", baton->heifCompression)
|
|
933
910
|
->set("effort", baton->heifEffort)
|
|
911
|
+
->set("bitdepth", 8)
|
|
934
912
|
->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
|
|
935
913
|
? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
|
|
936
914
|
->set("lossless", baton->heifLossless)));
|
|
@@ -939,6 +917,19 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
939
917
|
area->free_fn = nullptr;
|
|
940
918
|
vips_area_unref(area);
|
|
941
919
|
baton->formatOut = "heif";
|
|
920
|
+
} else if (baton->formatOut == "dz") {
|
|
921
|
+
// Write DZ to buffer
|
|
922
|
+
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
|
923
|
+
if (!sharp::HasAlpha(image)) {
|
|
924
|
+
baton->tileBackground.pop_back();
|
|
925
|
+
}
|
|
926
|
+
vips::VOption *options = BuildOptionsDZ(baton);
|
|
927
|
+
VipsArea *area = reinterpret_cast<VipsArea*>(image.dzsave_buffer(options));
|
|
928
|
+
baton->bufferOut = static_cast<char*>(area->data);
|
|
929
|
+
baton->bufferOutLength = area->length;
|
|
930
|
+
area->free_fn = nullptr;
|
|
931
|
+
vips_area_unref(area);
|
|
932
|
+
baton->formatOut = "dz";
|
|
942
933
|
} else if (baton->formatOut == "raw" ||
|
|
943
934
|
(baton->formatOut == "input" && inputImageType == sharp::ImageType::RAW)) {
|
|
944
935
|
// Write raw, uncompressed image data to buffer
|
|
@@ -1040,6 +1031,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1040
1031
|
->set("near_lossless", baton->webpNearLossless)
|
|
1041
1032
|
->set("smart_subsample", baton->webpSmartSubsample)
|
|
1042
1033
|
->set("effort", baton->webpEffort)
|
|
1034
|
+
->set("min_size", baton->webpMinSize)
|
|
1035
|
+
->set("mixed", baton->webpMixed)
|
|
1043
1036
|
->set("alpha_q", baton->webpAlphaQuality));
|
|
1044
1037
|
baton->formatOut = "webp";
|
|
1045
1038
|
} else if (baton->formatOut == "gif" || (mightMatchInput && isGif) ||
|
|
@@ -1050,6 +1043,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1050
1043
|
->set("strip", !baton->withMetadata)
|
|
1051
1044
|
->set("bitdepth", baton->gifBitdepth)
|
|
1052
1045
|
->set("effort", baton->gifEffort)
|
|
1046
|
+
->set("reoptimise", baton->gifReoptimise)
|
|
1053
1047
|
->set("dither", baton->gifDither));
|
|
1054
1048
|
baton->formatOut = "gif";
|
|
1055
1049
|
} else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
|
|
@@ -1080,75 +1074,26 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1080
1074
|
} else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) ||
|
|
1081
1075
|
(willMatchInput && inputImageType == sharp::ImageType::HEIF)) {
|
|
1082
1076
|
// Write HEIF to file
|
|
1083
|
-
image = sharp::RemoveAnimationProperties(image);
|
|
1077
|
+
image = sharp::RemoveAnimationProperties(image).cast(VIPS_FORMAT_UCHAR);
|
|
1084
1078
|
image.heifsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
1085
1079
|
->set("strip", !baton->withMetadata)
|
|
1086
1080
|
->set("Q", baton->heifQuality)
|
|
1087
1081
|
->set("compression", baton->heifCompression)
|
|
1088
1082
|
->set("effort", baton->heifEffort)
|
|
1083
|
+
->set("bitdepth", 8)
|
|
1089
1084
|
->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
|
|
1090
1085
|
? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
|
|
1091
1086
|
->set("lossless", baton->heifLossless));
|
|
1092
1087
|
baton->formatOut = "heif";
|
|
1093
1088
|
} else if (baton->formatOut == "dz" || isDz || isDzZip) {
|
|
1089
|
+
// Write DZ to file
|
|
1094
1090
|
if (isDzZip) {
|
|
1095
1091
|
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
|
1096
1092
|
}
|
|
1097
|
-
// Forward format options through suffix
|
|
1098
|
-
std::string suffix;
|
|
1099
|
-
if (baton->tileFormat == "png") {
|
|
1100
|
-
std::vector<std::pair<std::string, std::string>> options {
|
|
1101
|
-
{"interlace", baton->pngProgressive ? "TRUE" : "FALSE"},
|
|
1102
|
-
{"compression", std::to_string(baton->pngCompressionLevel)},
|
|
1103
|
-
{"filter", baton->pngAdaptiveFiltering ? "all" : "none"}
|
|
1104
|
-
};
|
|
1105
|
-
suffix = AssembleSuffixString(".png", options);
|
|
1106
|
-
} else if (baton->tileFormat == "webp") {
|
|
1107
|
-
std::vector<std::pair<std::string, std::string>> options {
|
|
1108
|
-
{"Q", std::to_string(baton->webpQuality)},
|
|
1109
|
-
{"alpha_q", std::to_string(baton->webpAlphaQuality)},
|
|
1110
|
-
{"lossless", baton->webpLossless ? "TRUE" : "FALSE"},
|
|
1111
|
-
{"near_lossless", baton->webpNearLossless ? "TRUE" : "FALSE"},
|
|
1112
|
-
{"smart_subsample", baton->webpSmartSubsample ? "TRUE" : "FALSE"},
|
|
1113
|
-
{"effort", std::to_string(baton->webpEffort)}
|
|
1114
|
-
};
|
|
1115
|
-
suffix = AssembleSuffixString(".webp", options);
|
|
1116
|
-
} else {
|
|
1117
|
-
std::vector<std::pair<std::string, std::string>> options {
|
|
1118
|
-
{"Q", std::to_string(baton->jpegQuality)},
|
|
1119
|
-
{"interlace", baton->jpegProgressive ? "TRUE" : "FALSE"},
|
|
1120
|
-
{"subsample_mode", baton->jpegChromaSubsampling == "4:4:4" ? "off" : "on"},
|
|
1121
|
-
{"trellis_quant", baton->jpegTrellisQuantisation ? "TRUE" : "FALSE"},
|
|
1122
|
-
{"quant_table", std::to_string(baton->jpegQuantisationTable)},
|
|
1123
|
-
{"overshoot_deringing", baton->jpegOvershootDeringing ? "TRUE": "FALSE"},
|
|
1124
|
-
{"optimize_scans", baton->jpegOptimiseScans ? "TRUE": "FALSE"},
|
|
1125
|
-
{"optimize_coding", baton->jpegOptimiseCoding ? "TRUE": "FALSE"}
|
|
1126
|
-
};
|
|
1127
|
-
std::string extname = baton->tileLayout == VIPS_FOREIGN_DZ_LAYOUT_DZ ? ".jpeg" : ".jpg";
|
|
1128
|
-
suffix = AssembleSuffixString(extname, options);
|
|
1129
|
-
}
|
|
1130
|
-
// Remove alpha channel from tile background if image does not contain an alpha channel
|
|
1131
1093
|
if (!sharp::HasAlpha(image)) {
|
|
1132
1094
|
baton->tileBackground.pop_back();
|
|
1133
1095
|
}
|
|
1134
|
-
|
|
1135
|
-
vips::VOption *options = VImage::option()
|
|
1136
|
-
->set("strip", !baton->withMetadata)
|
|
1137
|
-
->set("tile_size", baton->tileSize)
|
|
1138
|
-
->set("overlap", baton->tileOverlap)
|
|
1139
|
-
->set("container", baton->tileContainer)
|
|
1140
|
-
->set("layout", baton->tileLayout)
|
|
1141
|
-
->set("suffix", const_cast<char*>(suffix.data()))
|
|
1142
|
-
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
|
1143
|
-
->set("background", baton->tileBackground)
|
|
1144
|
-
->set("centre", baton->tileCentre)
|
|
1145
|
-
->set("id", const_cast<char*>(baton->tileId.data()))
|
|
1146
|
-
->set("skip_blanks", baton->tileSkipBlanks);
|
|
1147
|
-
// libvips chooses a default depth based on layout. Instead of replicating that logic here by
|
|
1148
|
-
// not passing anything - libvips will handle choice
|
|
1149
|
-
if (baton->tileDepth < VIPS_FOREIGN_DZ_DEPTH_LAST) {
|
|
1150
|
-
options->set("depth", baton->tileDepth);
|
|
1151
|
-
}
|
|
1096
|
+
vips::VOption *options = BuildOptionsDZ(baton);
|
|
1152
1097
|
image.dzsave(const_cast<char*>(baton->fileOut.data()), options);
|
|
1153
1098
|
baton->formatOut = "dz";
|
|
1154
1099
|
} else if (baton->formatOut == "v" || (mightMatchInput && isV) ||
|
|
@@ -1217,6 +1162,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1217
1162
|
info.Set("trimOffsetTop", static_cast<int32_t>(baton->trimOffsetTop));
|
|
1218
1163
|
}
|
|
1219
1164
|
|
|
1165
|
+
if (baton->input->textAutofitDpi) {
|
|
1166
|
+
info.Set("textAutofitDpi", static_cast<uint32_t>(baton->input->textAutofitDpi));
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1220
1169
|
if (baton->bufferOutLength > 0) {
|
|
1221
1170
|
// Add buffer size to info
|
|
1222
1171
|
info.Set("size", static_cast<uint32_t>(baton->bufferOutLength));
|
|
@@ -1305,7 +1254,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1305
1254
|
|
|
1306
1255
|
/*
|
|
1307
1256
|
Assemble the suffix argument to dzsave, which is the format (by extname)
|
|
1308
|
-
|
|
1257
|
+
alongside comma-separated arguments to the corresponding `formatsave` vips
|
|
1309
1258
|
action.
|
|
1310
1259
|
*/
|
|
1311
1260
|
std::string
|
|
@@ -1320,6 +1269,67 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1320
1269
|
return extname + "[" + argument + "]";
|
|
1321
1270
|
}
|
|
1322
1271
|
|
|
1272
|
+
/*
|
|
1273
|
+
Build VOption for dzsave
|
|
1274
|
+
*/
|
|
1275
|
+
vips::VOption*
|
|
1276
|
+
BuildOptionsDZ(PipelineBaton *baton) {
|
|
1277
|
+
// Forward format options through suffix
|
|
1278
|
+
std::string suffix;
|
|
1279
|
+
if (baton->tileFormat == "png") {
|
|
1280
|
+
std::vector<std::pair<std::string, std::string>> options {
|
|
1281
|
+
{"interlace", baton->pngProgressive ? "TRUE" : "FALSE"},
|
|
1282
|
+
{"compression", std::to_string(baton->pngCompressionLevel)},
|
|
1283
|
+
{"filter", baton->pngAdaptiveFiltering ? "all" : "none"}
|
|
1284
|
+
};
|
|
1285
|
+
suffix = AssembleSuffixString(".png", options);
|
|
1286
|
+
} else if (baton->tileFormat == "webp") {
|
|
1287
|
+
std::vector<std::pair<std::string, std::string>> options {
|
|
1288
|
+
{"Q", std::to_string(baton->webpQuality)},
|
|
1289
|
+
{"alpha_q", std::to_string(baton->webpAlphaQuality)},
|
|
1290
|
+
{"lossless", baton->webpLossless ? "TRUE" : "FALSE"},
|
|
1291
|
+
{"near_lossless", baton->webpNearLossless ? "TRUE" : "FALSE"},
|
|
1292
|
+
{"smart_subsample", baton->webpSmartSubsample ? "TRUE" : "FALSE"},
|
|
1293
|
+
{"min_size", baton->webpMinSize ? "TRUE" : "FALSE"},
|
|
1294
|
+
{"mixed", baton->webpMixed ? "TRUE" : "FALSE"},
|
|
1295
|
+
{"effort", std::to_string(baton->webpEffort)}
|
|
1296
|
+
};
|
|
1297
|
+
suffix = AssembleSuffixString(".webp", options);
|
|
1298
|
+
} else {
|
|
1299
|
+
std::vector<std::pair<std::string, std::string>> options {
|
|
1300
|
+
{"Q", std::to_string(baton->jpegQuality)},
|
|
1301
|
+
{"interlace", baton->jpegProgressive ? "TRUE" : "FALSE"},
|
|
1302
|
+
{"subsample_mode", baton->jpegChromaSubsampling == "4:4:4" ? "off" : "on"},
|
|
1303
|
+
{"trellis_quant", baton->jpegTrellisQuantisation ? "TRUE" : "FALSE"},
|
|
1304
|
+
{"quant_table", std::to_string(baton->jpegQuantisationTable)},
|
|
1305
|
+
{"overshoot_deringing", baton->jpegOvershootDeringing ? "TRUE": "FALSE"},
|
|
1306
|
+
{"optimize_scans", baton->jpegOptimiseScans ? "TRUE": "FALSE"},
|
|
1307
|
+
{"optimize_coding", baton->jpegOptimiseCoding ? "TRUE": "FALSE"}
|
|
1308
|
+
};
|
|
1309
|
+
std::string extname = baton->tileLayout == VIPS_FOREIGN_DZ_LAYOUT_DZ ? ".jpeg" : ".jpg";
|
|
1310
|
+
suffix = AssembleSuffixString(extname, options);
|
|
1311
|
+
}
|
|
1312
|
+
vips::VOption *options = VImage::option()
|
|
1313
|
+
->set("strip", !baton->withMetadata)
|
|
1314
|
+
->set("tile_size", baton->tileSize)
|
|
1315
|
+
->set("overlap", baton->tileOverlap)
|
|
1316
|
+
->set("container", baton->tileContainer)
|
|
1317
|
+
->set("layout", baton->tileLayout)
|
|
1318
|
+
->set("suffix", const_cast<char*>(suffix.data()))
|
|
1319
|
+
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
|
1320
|
+
->set("background", baton->tileBackground)
|
|
1321
|
+
->set("centre", baton->tileCentre)
|
|
1322
|
+
->set("id", const_cast<char*>(baton->tileId.data()))
|
|
1323
|
+
->set("skip_blanks", baton->tileSkipBlanks);
|
|
1324
|
+
if (baton->tileDepth < VIPS_FOREIGN_DZ_DEPTH_LAST) {
|
|
1325
|
+
options->set("depth", baton->tileDepth);
|
|
1326
|
+
}
|
|
1327
|
+
if (!baton->tileBasename.empty()) {
|
|
1328
|
+
options->set("basename", const_cast<char*>(baton->tileBasename.data()));
|
|
1329
|
+
}
|
|
1330
|
+
return options;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1323
1333
|
/*
|
|
1324
1334
|
Clear all thread-local data.
|
|
1325
1335
|
*/
|
|
@@ -1365,17 +1375,13 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1365
1375
|
} else if (canvas == "ignore_aspect") {
|
|
1366
1376
|
baton->canvas = sharp::Canvas::IGNORE_ASPECT;
|
|
1367
1377
|
}
|
|
1368
|
-
// Tint chroma
|
|
1369
|
-
baton->tintA = sharp::AttrAsDouble(options, "tintA");
|
|
1370
|
-
baton->tintB = sharp::AttrAsDouble(options, "tintB");
|
|
1371
1378
|
// Composite
|
|
1372
1379
|
Napi::Array compositeArray = options.Get("composite").As<Napi::Array>();
|
|
1373
1380
|
for (unsigned int i = 0; i < compositeArray.Length(); i++) {
|
|
1374
1381
|
Napi::Object compositeObject = compositeArray.Get(i).As<Napi::Object>();
|
|
1375
1382
|
Composite *composite = new Composite;
|
|
1376
1383
|
composite->input = sharp::CreateInputDescriptor(compositeObject.Get("input").As<Napi::Object>());
|
|
1377
|
-
composite->mode =
|
|
1378
|
-
vips_enum_from_nick(nullptr, VIPS_TYPE_BLEND_MODE, sharp::AttrAsStr(compositeObject, "blend").data()));
|
|
1384
|
+
composite->mode = sharp::AttrAsEnum<VipsBlendMode>(compositeObject, "blend", VIPS_TYPE_BLEND_MODE);
|
|
1379
1385
|
composite->gravity = sharp::AttrAsUint32(compositeObject, "gravity");
|
|
1380
1386
|
composite->left = sharp::AttrAsInt32(compositeObject, "left");
|
|
1381
1387
|
composite->top = sharp::AttrAsInt32(compositeObject, "top");
|
|
@@ -1389,7 +1395,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1389
1395
|
baton->withoutReduction = sharp::AttrAsBool(options, "withoutReduction");
|
|
1390
1396
|
baton->position = sharp::AttrAsInt32(options, "position");
|
|
1391
1397
|
baton->resizeBackground = sharp::AttrAsVectorOfDouble(options, "resizeBackground");
|
|
1392
|
-
baton->kernel = sharp::
|
|
1398
|
+
baton->kernel = sharp::AttrAsEnum<VipsKernel>(options, "kernel", VIPS_TYPE_KERNEL);
|
|
1393
1399
|
baton->fastShrinkOnLoad = sharp::AttrAsBool(options, "fastShrinkOnLoad");
|
|
1394
1400
|
// Join Channel Options
|
|
1395
1401
|
if (options.Has("joinChannelIn")) {
|
|
@@ -1418,13 +1424,16 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1418
1424
|
baton->sharpenY3 = sharp::AttrAsDouble(options, "sharpenY3");
|
|
1419
1425
|
baton->threshold = sharp::AttrAsInt32(options, "threshold");
|
|
1420
1426
|
baton->thresholdGrayscale = sharp::AttrAsBool(options, "thresholdGrayscale");
|
|
1427
|
+
baton->trimBackground = sharp::AttrAsVectorOfDouble(options, "trimBackground");
|
|
1421
1428
|
baton->trimThreshold = sharp::AttrAsDouble(options, "trimThreshold");
|
|
1422
1429
|
baton->gamma = sharp::AttrAsDouble(options, "gamma");
|
|
1423
1430
|
baton->gammaOut = sharp::AttrAsDouble(options, "gammaOut");
|
|
1424
|
-
baton->linearA = sharp::
|
|
1425
|
-
baton->linearB = sharp::
|
|
1431
|
+
baton->linearA = sharp::AttrAsVectorOfDouble(options, "linearA");
|
|
1432
|
+
baton->linearB = sharp::AttrAsVectorOfDouble(options, "linearB");
|
|
1426
1433
|
baton->greyscale = sharp::AttrAsBool(options, "greyscale");
|
|
1427
1434
|
baton->normalise = sharp::AttrAsBool(options, "normalise");
|
|
1435
|
+
baton->tintA = sharp::AttrAsDouble(options, "tintA");
|
|
1436
|
+
baton->tintB = sharp::AttrAsDouble(options, "tintB");
|
|
1428
1437
|
baton->claheWidth = sharp::AttrAsUint32(options, "claheWidth");
|
|
1429
1438
|
baton->claheHeight = sharp::AttrAsUint32(options, "claheHeight");
|
|
1430
1439
|
baton->claheMaxSlope = sharp::AttrAsUint32(options, "claheMaxSlope");
|
|
@@ -1452,10 +1461,10 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1452
1461
|
baton->ensureAlpha = sharp::AttrAsDouble(options, "ensureAlpha");
|
|
1453
1462
|
if (options.Has("boolean")) {
|
|
1454
1463
|
baton->boolean = sharp::CreateInputDescriptor(options.Get("boolean").As<Napi::Object>());
|
|
1455
|
-
baton->booleanOp = sharp::
|
|
1464
|
+
baton->booleanOp = sharp::AttrAsEnum<VipsOperationBoolean>(options, "booleanOp", VIPS_TYPE_OPERATION_BOOLEAN);
|
|
1456
1465
|
}
|
|
1457
1466
|
if (options.Has("bandBoolOp")) {
|
|
1458
|
-
baton->bandBoolOp = sharp::
|
|
1467
|
+
baton->bandBoolOp = sharp::AttrAsEnum<VipsOperationBoolean>(options, "bandBoolOp", VIPS_TYPE_OPERATION_BOOLEAN);
|
|
1459
1468
|
}
|
|
1460
1469
|
if (options.Has("convKernel")) {
|
|
1461
1470
|
Napi::Object kernel = options.Get("convKernel").As<Napi::Object>();
|
|
@@ -1477,11 +1486,12 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1477
1486
|
baton->recombMatrix[i] = sharp::AttrAsDouble(recombMatrix, i);
|
|
1478
1487
|
}
|
|
1479
1488
|
}
|
|
1480
|
-
baton->colourspaceInput = sharp::
|
|
1489
|
+
baton->colourspaceInput = sharp::AttrAsEnum<VipsInterpretation>(
|
|
1490
|
+
options, "colourspaceInput", VIPS_TYPE_INTERPRETATION);
|
|
1481
1491
|
if (baton->colourspaceInput == VIPS_INTERPRETATION_ERROR) {
|
|
1482
1492
|
baton->colourspaceInput = VIPS_INTERPRETATION_LAST;
|
|
1483
1493
|
}
|
|
1484
|
-
baton->colourspace = sharp::
|
|
1494
|
+
baton->colourspace = sharp::AttrAsEnum<VipsInterpretation>(options, "colourspace", VIPS_TYPE_INTERPRETATION);
|
|
1485
1495
|
if (baton->colourspace == VIPS_INTERPRETATION_ERROR) {
|
|
1486
1496
|
baton->colourspace = VIPS_INTERPRETATION_sRGB;
|
|
1487
1497
|
}
|
|
@@ -1496,7 +1506,9 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1496
1506
|
Napi::Array mdStrKeys = mdStrs.GetPropertyNames();
|
|
1497
1507
|
for (unsigned int i = 0; i < mdStrKeys.Length(); i++) {
|
|
1498
1508
|
std::string k = sharp::AttrAsStr(mdStrKeys, i);
|
|
1499
|
-
|
|
1509
|
+
if (mdStrs.HasOwnProperty(k)) {
|
|
1510
|
+
baton->withMetadataStrs.insert(std::make_pair(k, sharp::AttrAsStr(mdStrs, k)));
|
|
1511
|
+
}
|
|
1500
1512
|
}
|
|
1501
1513
|
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
|
|
1502
1514
|
// Format-specific
|
|
@@ -1527,9 +1539,12 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1527
1539
|
baton->webpNearLossless = sharp::AttrAsBool(options, "webpNearLossless");
|
|
1528
1540
|
baton->webpSmartSubsample = sharp::AttrAsBool(options, "webpSmartSubsample");
|
|
1529
1541
|
baton->webpEffort = sharp::AttrAsUint32(options, "webpEffort");
|
|
1542
|
+
baton->webpMinSize = sharp::AttrAsBool(options, "webpMinSize");
|
|
1543
|
+
baton->webpMixed = sharp::AttrAsBool(options, "webpMixed");
|
|
1530
1544
|
baton->gifBitdepth = sharp::AttrAsUint32(options, "gifBitdepth");
|
|
1531
1545
|
baton->gifEffort = sharp::AttrAsUint32(options, "gifEffort");
|
|
1532
1546
|
baton->gifDither = sharp::AttrAsDouble(options, "gifDither");
|
|
1547
|
+
baton->gifReoptimise = sharp::AttrAsBool(options, "gifReoptimise");
|
|
1533
1548
|
baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
|
|
1534
1549
|
baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid");
|
|
1535
1550
|
baton->tiffBitdepth = sharp::AttrAsUint32(options, "tiffBitdepth");
|
|
@@ -1541,28 +1556,19 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1541
1556
|
if (baton->tiffXres == 1.0 && baton->tiffYres == 1.0 && baton->withMetadataDensity > 0) {
|
|
1542
1557
|
baton->tiffXres = baton->tiffYres = baton->withMetadataDensity / 25.4;
|
|
1543
1558
|
}
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
baton->
|
|
1549
|
-
|
|
1550
|
-
sharp::AttrAsStr(options, "tiffPredictor").data()));
|
|
1551
|
-
baton->tiffResolutionUnit = static_cast<VipsForeignTiffResunit>(
|
|
1552
|
-
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_TIFF_RESUNIT,
|
|
1553
|
-
sharp::AttrAsStr(options, "tiffResolutionUnit").data()));
|
|
1554
|
-
|
|
1559
|
+
baton->tiffCompression = sharp::AttrAsEnum<VipsForeignTiffCompression>(
|
|
1560
|
+
options, "tiffCompression", VIPS_TYPE_FOREIGN_TIFF_COMPRESSION);
|
|
1561
|
+
baton->tiffPredictor = sharp::AttrAsEnum<VipsForeignTiffPredictor>(
|
|
1562
|
+
options, "tiffPredictor", VIPS_TYPE_FOREIGN_TIFF_PREDICTOR);
|
|
1563
|
+
baton->tiffResolutionUnit = sharp::AttrAsEnum<VipsForeignTiffResunit>(
|
|
1564
|
+
options, "tiffResolutionUnit", VIPS_TYPE_FOREIGN_TIFF_RESUNIT);
|
|
1555
1565
|
baton->heifQuality = sharp::AttrAsUint32(options, "heifQuality");
|
|
1556
1566
|
baton->heifLossless = sharp::AttrAsBool(options, "heifLossless");
|
|
1557
|
-
baton->heifCompression =
|
|
1558
|
-
|
|
1559
|
-
sharp::AttrAsStr(options, "heifCompression").data()));
|
|
1567
|
+
baton->heifCompression = sharp::AttrAsEnum<VipsForeignHeifCompression>(
|
|
1568
|
+
options, "heifCompression", VIPS_TYPE_FOREIGN_HEIF_COMPRESSION);
|
|
1560
1569
|
baton->heifEffort = sharp::AttrAsUint32(options, "heifEffort");
|
|
1561
1570
|
baton->heifChromaSubsampling = sharp::AttrAsStr(options, "heifChromaSubsampling");
|
|
1562
|
-
|
|
1563
|
-
baton->rawDepth = static_cast<VipsBandFormat>(
|
|
1564
|
-
vips_enum_from_nick(nullptr, VIPS_TYPE_BAND_FORMAT,
|
|
1565
|
-
sharp::AttrAsStr(options, "rawDepth").data()));
|
|
1571
|
+
baton->rawDepth = sharp::AttrAsEnum<VipsBandFormat>(options, "rawDepth", VIPS_TYPE_BAND_FORMAT);
|
|
1566
1572
|
// Animated output properties
|
|
1567
1573
|
if (sharp::HasAttr(options, "loop")) {
|
|
1568
1574
|
baton->loop = sharp::AttrAsUint32(options, "loop");
|
|
@@ -1570,24 +1576,19 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1570
1576
|
if (sharp::HasAttr(options, "delay")) {
|
|
1571
1577
|
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
|
1572
1578
|
}
|
|
1573
|
-
// Tile output
|
|
1574
1579
|
baton->tileSize = sharp::AttrAsUint32(options, "tileSize");
|
|
1575
1580
|
baton->tileOverlap = sharp::AttrAsUint32(options, "tileOverlap");
|
|
1576
1581
|
baton->tileAngle = sharp::AttrAsInt32(options, "tileAngle");
|
|
1577
1582
|
baton->tileBackground = sharp::AttrAsVectorOfDouble(options, "tileBackground");
|
|
1578
1583
|
baton->tileSkipBlanks = sharp::AttrAsInt32(options, "tileSkipBlanks");
|
|
1579
|
-
baton->tileContainer =
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
baton->tileLayout = static_cast<VipsForeignDzLayout>(
|
|
1583
|
-
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_LAYOUT,
|
|
1584
|
-
sharp::AttrAsStr(options, "tileLayout").data()));
|
|
1584
|
+
baton->tileContainer = sharp::AttrAsEnum<VipsForeignDzContainer>(
|
|
1585
|
+
options, "tileContainer", VIPS_TYPE_FOREIGN_DZ_CONTAINER);
|
|
1586
|
+
baton->tileLayout = sharp::AttrAsEnum<VipsForeignDzLayout>(options, "tileLayout", VIPS_TYPE_FOREIGN_DZ_LAYOUT);
|
|
1585
1587
|
baton->tileFormat = sharp::AttrAsStr(options, "tileFormat");
|
|
1586
|
-
baton->tileDepth =
|
|
1587
|
-
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_DEPTH,
|
|
1588
|
-
sharp::AttrAsStr(options, "tileDepth").data()));
|
|
1588
|
+
baton->tileDepth = sharp::AttrAsEnum<VipsForeignDzDepth>(options, "tileDepth", VIPS_TYPE_FOREIGN_DZ_DEPTH);
|
|
1589
1589
|
baton->tileCentre = sharp::AttrAsBool(options, "tileCentre");
|
|
1590
1590
|
baton->tileId = sharp::AttrAsStr(options, "tileId");
|
|
1591
|
+
baton->tileBasename = sharp::AttrAsStr(options, "tileBasename");
|
|
1591
1592
|
|
|
1592
1593
|
// Force random access for certain operations
|
|
1593
1594
|
if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
|