sharp 0.30.7 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/binding.gyp +4 -3
- package/lib/composite.js +14 -0
- package/lib/constructor.js +41 -4
- package/lib/input.js +92 -0
- package/lib/operation.js +57 -12
- package/lib/output.js +87 -23
- package/lib/resize.js +89 -12
- package/lib/utility.js +4 -0
- package/package.json +23 -21
- package/src/common.cc +90 -43
- 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 +69 -25
- package/src/operations.h +7 -2
- package/src/pipeline.cc +156 -160
- package/src/pipeline.h +18 -5
- package/src/sharp.cc +0 -1
- package/src/utilities.cc +13 -2
package/src/pipeline.cc
CHANGED
|
@@ -118,7 +118,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
118
118
|
// Trim
|
|
119
119
|
if (baton->trimThreshold > 0.0) {
|
|
120
120
|
MultiPageUnsupported(nPages, "Trim");
|
|
121
|
-
image = sharp::Trim(image, baton->trimThreshold);
|
|
121
|
+
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold);
|
|
122
122
|
baton->trimOffsetLeft = image.xoffset();
|
|
123
123
|
baton->trimOffsetTop = image.yoffset();
|
|
124
124
|
}
|
|
@@ -204,6 +204,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
204
204
|
vips::VOption *option = VImage::option()
|
|
205
205
|
->set("access", baton->input->access)
|
|
206
206
|
->set("shrink", jpegShrinkOnLoad)
|
|
207
|
+
->set("unlimited", baton->input->unlimited)
|
|
207
208
|
->set("fail_on", baton->input->failOn);
|
|
208
209
|
if (baton->input->buffer != nullptr) {
|
|
209
210
|
// Reload JPEG buffer
|
|
@@ -302,8 +303,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
302
303
|
if (
|
|
303
304
|
sharp::HasProfile(image) &&
|
|
304
305
|
image.interpretation() != VIPS_INTERPRETATION_LABS &&
|
|
305
|
-
image.interpretation() != VIPS_INTERPRETATION_GREY16
|
|
306
|
-
image.interpretation() != VIPS_INTERPRETATION_B_W
|
|
306
|
+
image.interpretation() != VIPS_INTERPRETATION_GREY16
|
|
307
307
|
) {
|
|
308
308
|
// Convert to sRGB/P3 using embedded profile
|
|
309
309
|
try {
|
|
@@ -322,16 +322,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
322
322
|
|
|
323
323
|
// Flatten image to remove alpha channel
|
|
324
324
|
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));
|
|
325
|
+
image = sharp::Flatten(image, baton->flattenBackground);
|
|
335
326
|
}
|
|
336
327
|
|
|
337
328
|
// Negate the colours in the image
|
|
@@ -353,11 +344,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
353
344
|
bool const shouldBlur = baton->blurSigma != 0.0;
|
|
354
345
|
bool const shouldConv = baton->convKernelWidth * baton->convKernelHeight > 0;
|
|
355
346
|
bool const shouldSharpen = baton->sharpenSigma != 0.0;
|
|
356
|
-
bool const shouldApplyMedian = baton->medianSize > 0;
|
|
357
347
|
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
348
|
|
|
362
349
|
if (shouldComposite && !sharp::HasAlpha(image)) {
|
|
363
350
|
image = sharp::EnsureAlpha(image, 1);
|
|
@@ -366,26 +353,27 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
366
353
|
bool const shouldPremultiplyAlpha = sharp::HasAlpha(image) &&
|
|
367
354
|
(shouldResize || shouldBlur || shouldConv || shouldSharpen);
|
|
368
355
|
|
|
369
|
-
// Premultiply image alpha channel before all transformations to avoid
|
|
370
|
-
// dark fringing around bright pixels
|
|
371
|
-
// See: http://entropymine.com/imageworsener/resizealpha/
|
|
372
356
|
if (shouldPremultiplyAlpha) {
|
|
373
357
|
image = image.premultiply();
|
|
374
358
|
}
|
|
375
359
|
|
|
376
360
|
// Resize
|
|
377
361
|
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
362
|
image = image.resize(1.0 / hshrink, VImage::option()
|
|
387
363
|
->set("vscale", 1.0 / vshrink)
|
|
388
|
-
->set("kernel", kernel));
|
|
364
|
+
->set("kernel", baton->kernel));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Flip (mirror about Y axis)
|
|
368
|
+
if (baton->flip || flip) {
|
|
369
|
+
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
370
|
+
image = sharp::RemoveExifOrientation(image);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Flop (mirror about X axis)
|
|
374
|
+
if (baton->flop || flop) {
|
|
375
|
+
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
376
|
+
image = sharp::RemoveExifOrientation(image);
|
|
389
377
|
}
|
|
390
378
|
|
|
391
379
|
// Rotate post-extract 90-angle
|
|
@@ -402,18 +390,6 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
402
390
|
image = sharp::RemoveExifOrientation(image);
|
|
403
391
|
}
|
|
404
392
|
|
|
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
393
|
// Join additional color channels to the image
|
|
418
394
|
if (baton->joinChannelIn.size() > 0) {
|
|
419
395
|
VImage joinImage;
|
|
@@ -445,18 +421,12 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
445
421
|
std::tie(image, background) = sharp::ApplyAlpha(image, baton->resizeBackground, shouldPremultiplyAlpha);
|
|
446
422
|
|
|
447
423
|
// Embed
|
|
448
|
-
|
|
449
|
-
// Calculate where to position the embedded image if gravity specified, else center.
|
|
450
424
|
int left;
|
|
451
425
|
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
426
|
std::tie(left, top) = sharp::CalculateEmbedPosition(
|
|
459
427
|
inputWidth, inputHeight, baton->width, baton->height, baton->position);
|
|
428
|
+
int width = std::max(inputWidth, baton->width);
|
|
429
|
+
int height = std::max(inputHeight, baton->height);
|
|
460
430
|
|
|
461
431
|
image = nPages > 1
|
|
462
432
|
? sharp::EmbedMultiPage(image,
|
|
@@ -555,7 +525,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
555
525
|
VImage::option()->set("extend", VIPS_EXTEND_BACKGROUND)->set("background", background));
|
|
556
526
|
}
|
|
557
527
|
// Median - must happen before blurring, due to the utility of blurring after thresholding
|
|
558
|
-
if (
|
|
528
|
+
if (baton->medianSize > 0) {
|
|
559
529
|
image = image.median(baton->medianSize);
|
|
560
530
|
}
|
|
561
531
|
// Threshold - must happen before blurring, due to the utility of blurring after thresholding
|
|
@@ -581,7 +551,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
581
551
|
image = sharp::Recomb(image, baton->recombMatrix);
|
|
582
552
|
}
|
|
583
553
|
|
|
584
|
-
|
|
554
|
+
// Modulate
|
|
555
|
+
if (baton->brightness != 1.0 || baton->saturation != 1.0 || baton->hue != 0.0 || baton->lightness != 0.0) {
|
|
585
556
|
image = sharp::Modulate(image, baton->brightness, baton->saturation, baton->hue, baton->lightness);
|
|
586
557
|
}
|
|
587
558
|
|
|
@@ -591,6 +562,18 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
591
562
|
baton->sharpenX1, baton->sharpenY2, baton->sharpenY3);
|
|
592
563
|
}
|
|
593
564
|
|
|
565
|
+
// Reverse premultiplication after all transformations
|
|
566
|
+
if (shouldPremultiplyAlpha) {
|
|
567
|
+
image = image.unpremultiply();
|
|
568
|
+
// Cast pixel values to integer
|
|
569
|
+
if (sharp::Is16Bit(image.interpretation())) {
|
|
570
|
+
image = image.cast(VIPS_FORMAT_USHORT);
|
|
571
|
+
} else {
|
|
572
|
+
image = image.cast(VIPS_FORMAT_UCHAR);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
baton->premultiplied = shouldPremultiplyAlpha;
|
|
576
|
+
|
|
594
577
|
// Composite
|
|
595
578
|
if (shouldComposite) {
|
|
596
579
|
std::vector<VImage> images = { image };
|
|
@@ -668,28 +651,16 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
668
651
|
xs.push_back(left);
|
|
669
652
|
ys.push_back(top);
|
|
670
653
|
}
|
|
671
|
-
image =
|
|
654
|
+
image = VImage::composite(images, modes, VImage::option()->set("x", xs)->set("y", ys));
|
|
672
655
|
}
|
|
673
656
|
|
|
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
657
|
// Gamma decoding (brighten)
|
|
687
658
|
if (baton->gammaOut >= 1 && baton->gammaOut <= 3) {
|
|
688
659
|
image = sharp::Gamma(image, baton->gammaOut);
|
|
689
660
|
}
|
|
690
661
|
|
|
691
662
|
// Linear adjustment (a * in + b)
|
|
692
|
-
if (baton->linearA
|
|
663
|
+
if (!baton->linearA.empty()) {
|
|
693
664
|
image = sharp::Linear(image, baton->linearA, baton->linearB);
|
|
694
665
|
}
|
|
695
666
|
|
|
@@ -699,7 +670,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
699
670
|
}
|
|
700
671
|
|
|
701
672
|
// Apply contrast limiting adaptive histogram equalization (CLAHE)
|
|
702
|
-
if (
|
|
673
|
+
if (baton->claheWidth != 0 && baton->claheHeight != 0) {
|
|
703
674
|
image = sharp::Clahe(image, baton->claheWidth, baton->claheHeight, baton->claheMaxSlope);
|
|
704
675
|
}
|
|
705
676
|
|
|
@@ -873,6 +844,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
873
844
|
->set("near_lossless", baton->webpNearLossless)
|
|
874
845
|
->set("smart_subsample", baton->webpSmartSubsample)
|
|
875
846
|
->set("effort", baton->webpEffort)
|
|
847
|
+
->set("min_size", baton->webpMinSize)
|
|
848
|
+
->set("mixed", baton->webpMixed)
|
|
876
849
|
->set("alpha_q", baton->webpAlphaQuality)));
|
|
877
850
|
baton->bufferOut = static_cast<char*>(area->data);
|
|
878
851
|
baton->bufferOutLength = area->length;
|
|
@@ -887,6 +860,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
887
860
|
->set("strip", !baton->withMetadata)
|
|
888
861
|
->set("bitdepth", baton->gifBitdepth)
|
|
889
862
|
->set("effort", baton->gifEffort)
|
|
863
|
+
->set("reoptimise", baton->gifReoptimise)
|
|
890
864
|
->set("dither", baton->gifDither)));
|
|
891
865
|
baton->bufferOut = static_cast<char*>(area->data);
|
|
892
866
|
baton->bufferOutLength = area->length;
|
|
@@ -939,6 +913,19 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
939
913
|
area->free_fn = nullptr;
|
|
940
914
|
vips_area_unref(area);
|
|
941
915
|
baton->formatOut = "heif";
|
|
916
|
+
} else if (baton->formatOut == "dz") {
|
|
917
|
+
// Write DZ to buffer
|
|
918
|
+
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
|
919
|
+
if (!sharp::HasAlpha(image)) {
|
|
920
|
+
baton->tileBackground.pop_back();
|
|
921
|
+
}
|
|
922
|
+
vips::VOption *options = BuildOptionsDZ(baton);
|
|
923
|
+
VipsArea *area = reinterpret_cast<VipsArea*>(image.dzsave_buffer(options));
|
|
924
|
+
baton->bufferOut = static_cast<char*>(area->data);
|
|
925
|
+
baton->bufferOutLength = area->length;
|
|
926
|
+
area->free_fn = nullptr;
|
|
927
|
+
vips_area_unref(area);
|
|
928
|
+
baton->formatOut = "dz";
|
|
942
929
|
} else if (baton->formatOut == "raw" ||
|
|
943
930
|
(baton->formatOut == "input" && inputImageType == sharp::ImageType::RAW)) {
|
|
944
931
|
// Write raw, uncompressed image data to buffer
|
|
@@ -1040,6 +1027,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1040
1027
|
->set("near_lossless", baton->webpNearLossless)
|
|
1041
1028
|
->set("smart_subsample", baton->webpSmartSubsample)
|
|
1042
1029
|
->set("effort", baton->webpEffort)
|
|
1030
|
+
->set("min_size", baton->webpMinSize)
|
|
1031
|
+
->set("mixed", baton->webpMixed)
|
|
1043
1032
|
->set("alpha_q", baton->webpAlphaQuality));
|
|
1044
1033
|
baton->formatOut = "webp";
|
|
1045
1034
|
} else if (baton->formatOut == "gif" || (mightMatchInput && isGif) ||
|
|
@@ -1050,6 +1039,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1050
1039
|
->set("strip", !baton->withMetadata)
|
|
1051
1040
|
->set("bitdepth", baton->gifBitdepth)
|
|
1052
1041
|
->set("effort", baton->gifEffort)
|
|
1042
|
+
->set("reoptimise", baton->gifReoptimise)
|
|
1053
1043
|
->set("dither", baton->gifDither));
|
|
1054
1044
|
baton->formatOut = "gif";
|
|
1055
1045
|
} else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
|
|
@@ -1091,64 +1081,14 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1091
1081
|
->set("lossless", baton->heifLossless));
|
|
1092
1082
|
baton->formatOut = "heif";
|
|
1093
1083
|
} else if (baton->formatOut == "dz" || isDz || isDzZip) {
|
|
1084
|
+
// Write DZ to file
|
|
1094
1085
|
if (isDzZip) {
|
|
1095
1086
|
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
|
1096
1087
|
}
|
|
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
1088
|
if (!sharp::HasAlpha(image)) {
|
|
1132
1089
|
baton->tileBackground.pop_back();
|
|
1133
1090
|
}
|
|
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
|
-
}
|
|
1091
|
+
vips::VOption *options = BuildOptionsDZ(baton);
|
|
1152
1092
|
image.dzsave(const_cast<char*>(baton->fileOut.data()), options);
|
|
1153
1093
|
baton->formatOut = "dz";
|
|
1154
1094
|
} else if (baton->formatOut == "v" || (mightMatchInput && isV) ||
|
|
@@ -1217,6 +1157,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1217
1157
|
info.Set("trimOffsetTop", static_cast<int32_t>(baton->trimOffsetTop));
|
|
1218
1158
|
}
|
|
1219
1159
|
|
|
1160
|
+
if (baton->input->textAutofitDpi) {
|
|
1161
|
+
info.Set("textAutofitDpi", static_cast<uint32_t>(baton->input->textAutofitDpi));
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1220
1164
|
if (baton->bufferOutLength > 0) {
|
|
1221
1165
|
// Add buffer size to info
|
|
1222
1166
|
info.Set("size", static_cast<uint32_t>(baton->bufferOutLength));
|
|
@@ -1305,7 +1249,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1305
1249
|
|
|
1306
1250
|
/*
|
|
1307
1251
|
Assemble the suffix argument to dzsave, which is the format (by extname)
|
|
1308
|
-
|
|
1252
|
+
alongside comma-separated arguments to the corresponding `formatsave` vips
|
|
1309
1253
|
action.
|
|
1310
1254
|
*/
|
|
1311
1255
|
std::string
|
|
@@ -1320,6 +1264,67 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1320
1264
|
return extname + "[" + argument + "]";
|
|
1321
1265
|
}
|
|
1322
1266
|
|
|
1267
|
+
/*
|
|
1268
|
+
Build VOption for dzsave
|
|
1269
|
+
*/
|
|
1270
|
+
vips::VOption*
|
|
1271
|
+
BuildOptionsDZ(PipelineBaton *baton) {
|
|
1272
|
+
// Forward format options through suffix
|
|
1273
|
+
std::string suffix;
|
|
1274
|
+
if (baton->tileFormat == "png") {
|
|
1275
|
+
std::vector<std::pair<std::string, std::string>> options {
|
|
1276
|
+
{"interlace", baton->pngProgressive ? "TRUE" : "FALSE"},
|
|
1277
|
+
{"compression", std::to_string(baton->pngCompressionLevel)},
|
|
1278
|
+
{"filter", baton->pngAdaptiveFiltering ? "all" : "none"}
|
|
1279
|
+
};
|
|
1280
|
+
suffix = AssembleSuffixString(".png", options);
|
|
1281
|
+
} else if (baton->tileFormat == "webp") {
|
|
1282
|
+
std::vector<std::pair<std::string, std::string>> options {
|
|
1283
|
+
{"Q", std::to_string(baton->webpQuality)},
|
|
1284
|
+
{"alpha_q", std::to_string(baton->webpAlphaQuality)},
|
|
1285
|
+
{"lossless", baton->webpLossless ? "TRUE" : "FALSE"},
|
|
1286
|
+
{"near_lossless", baton->webpNearLossless ? "TRUE" : "FALSE"},
|
|
1287
|
+
{"smart_subsample", baton->webpSmartSubsample ? "TRUE" : "FALSE"},
|
|
1288
|
+
{"min_size", baton->webpMinSize ? "TRUE" : "FALSE"},
|
|
1289
|
+
{"mixed", baton->webpMixed ? "TRUE" : "FALSE"},
|
|
1290
|
+
{"effort", std::to_string(baton->webpEffort)}
|
|
1291
|
+
};
|
|
1292
|
+
suffix = AssembleSuffixString(".webp", options);
|
|
1293
|
+
} else {
|
|
1294
|
+
std::vector<std::pair<std::string, std::string>> options {
|
|
1295
|
+
{"Q", std::to_string(baton->jpegQuality)},
|
|
1296
|
+
{"interlace", baton->jpegProgressive ? "TRUE" : "FALSE"},
|
|
1297
|
+
{"subsample_mode", baton->jpegChromaSubsampling == "4:4:4" ? "off" : "on"},
|
|
1298
|
+
{"trellis_quant", baton->jpegTrellisQuantisation ? "TRUE" : "FALSE"},
|
|
1299
|
+
{"quant_table", std::to_string(baton->jpegQuantisationTable)},
|
|
1300
|
+
{"overshoot_deringing", baton->jpegOvershootDeringing ? "TRUE": "FALSE"},
|
|
1301
|
+
{"optimize_scans", baton->jpegOptimiseScans ? "TRUE": "FALSE"},
|
|
1302
|
+
{"optimize_coding", baton->jpegOptimiseCoding ? "TRUE": "FALSE"}
|
|
1303
|
+
};
|
|
1304
|
+
std::string extname = baton->tileLayout == VIPS_FOREIGN_DZ_LAYOUT_DZ ? ".jpeg" : ".jpg";
|
|
1305
|
+
suffix = AssembleSuffixString(extname, options);
|
|
1306
|
+
}
|
|
1307
|
+
vips::VOption *options = VImage::option()
|
|
1308
|
+
->set("strip", !baton->withMetadata)
|
|
1309
|
+
->set("tile_size", baton->tileSize)
|
|
1310
|
+
->set("overlap", baton->tileOverlap)
|
|
1311
|
+
->set("container", baton->tileContainer)
|
|
1312
|
+
->set("layout", baton->tileLayout)
|
|
1313
|
+
->set("suffix", const_cast<char*>(suffix.data()))
|
|
1314
|
+
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
|
1315
|
+
->set("background", baton->tileBackground)
|
|
1316
|
+
->set("centre", baton->tileCentre)
|
|
1317
|
+
->set("id", const_cast<char*>(baton->tileId.data()))
|
|
1318
|
+
->set("skip_blanks", baton->tileSkipBlanks);
|
|
1319
|
+
if (baton->tileDepth < VIPS_FOREIGN_DZ_DEPTH_LAST) {
|
|
1320
|
+
options->set("depth", baton->tileDepth);
|
|
1321
|
+
}
|
|
1322
|
+
if (!baton->tileBasename.empty()) {
|
|
1323
|
+
options->set("basename", const_cast<char*>(baton->tileBasename.data()));
|
|
1324
|
+
}
|
|
1325
|
+
return options;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1323
1328
|
/*
|
|
1324
1329
|
Clear all thread-local data.
|
|
1325
1330
|
*/
|
|
@@ -1365,17 +1370,13 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1365
1370
|
} else if (canvas == "ignore_aspect") {
|
|
1366
1371
|
baton->canvas = sharp::Canvas::IGNORE_ASPECT;
|
|
1367
1372
|
}
|
|
1368
|
-
// Tint chroma
|
|
1369
|
-
baton->tintA = sharp::AttrAsDouble(options, "tintA");
|
|
1370
|
-
baton->tintB = sharp::AttrAsDouble(options, "tintB");
|
|
1371
1373
|
// Composite
|
|
1372
1374
|
Napi::Array compositeArray = options.Get("composite").As<Napi::Array>();
|
|
1373
1375
|
for (unsigned int i = 0; i < compositeArray.Length(); i++) {
|
|
1374
1376
|
Napi::Object compositeObject = compositeArray.Get(i).As<Napi::Object>();
|
|
1375
1377
|
Composite *composite = new Composite;
|
|
1376
1378
|
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()));
|
|
1379
|
+
composite->mode = sharp::AttrAsEnum<VipsBlendMode>(compositeObject, "blend", VIPS_TYPE_BLEND_MODE);
|
|
1379
1380
|
composite->gravity = sharp::AttrAsUint32(compositeObject, "gravity");
|
|
1380
1381
|
composite->left = sharp::AttrAsInt32(compositeObject, "left");
|
|
1381
1382
|
composite->top = sharp::AttrAsInt32(compositeObject, "top");
|
|
@@ -1389,7 +1390,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1389
1390
|
baton->withoutReduction = sharp::AttrAsBool(options, "withoutReduction");
|
|
1390
1391
|
baton->position = sharp::AttrAsInt32(options, "position");
|
|
1391
1392
|
baton->resizeBackground = sharp::AttrAsVectorOfDouble(options, "resizeBackground");
|
|
1392
|
-
baton->kernel = sharp::
|
|
1393
|
+
baton->kernel = sharp::AttrAsEnum<VipsKernel>(options, "kernel", VIPS_TYPE_KERNEL);
|
|
1393
1394
|
baton->fastShrinkOnLoad = sharp::AttrAsBool(options, "fastShrinkOnLoad");
|
|
1394
1395
|
// Join Channel Options
|
|
1395
1396
|
if (options.Has("joinChannelIn")) {
|
|
@@ -1418,13 +1419,16 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1418
1419
|
baton->sharpenY3 = sharp::AttrAsDouble(options, "sharpenY3");
|
|
1419
1420
|
baton->threshold = sharp::AttrAsInt32(options, "threshold");
|
|
1420
1421
|
baton->thresholdGrayscale = sharp::AttrAsBool(options, "thresholdGrayscale");
|
|
1422
|
+
baton->trimBackground = sharp::AttrAsVectorOfDouble(options, "trimBackground");
|
|
1421
1423
|
baton->trimThreshold = sharp::AttrAsDouble(options, "trimThreshold");
|
|
1422
1424
|
baton->gamma = sharp::AttrAsDouble(options, "gamma");
|
|
1423
1425
|
baton->gammaOut = sharp::AttrAsDouble(options, "gammaOut");
|
|
1424
|
-
baton->linearA = sharp::
|
|
1425
|
-
baton->linearB = sharp::
|
|
1426
|
+
baton->linearA = sharp::AttrAsVectorOfDouble(options, "linearA");
|
|
1427
|
+
baton->linearB = sharp::AttrAsVectorOfDouble(options, "linearB");
|
|
1426
1428
|
baton->greyscale = sharp::AttrAsBool(options, "greyscale");
|
|
1427
1429
|
baton->normalise = sharp::AttrAsBool(options, "normalise");
|
|
1430
|
+
baton->tintA = sharp::AttrAsDouble(options, "tintA");
|
|
1431
|
+
baton->tintB = sharp::AttrAsDouble(options, "tintB");
|
|
1428
1432
|
baton->claheWidth = sharp::AttrAsUint32(options, "claheWidth");
|
|
1429
1433
|
baton->claheHeight = sharp::AttrAsUint32(options, "claheHeight");
|
|
1430
1434
|
baton->claheMaxSlope = sharp::AttrAsUint32(options, "claheMaxSlope");
|
|
@@ -1452,10 +1456,10 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1452
1456
|
baton->ensureAlpha = sharp::AttrAsDouble(options, "ensureAlpha");
|
|
1453
1457
|
if (options.Has("boolean")) {
|
|
1454
1458
|
baton->boolean = sharp::CreateInputDescriptor(options.Get("boolean").As<Napi::Object>());
|
|
1455
|
-
baton->booleanOp = sharp::
|
|
1459
|
+
baton->booleanOp = sharp::AttrAsEnum<VipsOperationBoolean>(options, "booleanOp", VIPS_TYPE_OPERATION_BOOLEAN);
|
|
1456
1460
|
}
|
|
1457
1461
|
if (options.Has("bandBoolOp")) {
|
|
1458
|
-
baton->bandBoolOp = sharp::
|
|
1462
|
+
baton->bandBoolOp = sharp::AttrAsEnum<VipsOperationBoolean>(options, "bandBoolOp", VIPS_TYPE_OPERATION_BOOLEAN);
|
|
1459
1463
|
}
|
|
1460
1464
|
if (options.Has("convKernel")) {
|
|
1461
1465
|
Napi::Object kernel = options.Get("convKernel").As<Napi::Object>();
|
|
@@ -1477,11 +1481,12 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1477
1481
|
baton->recombMatrix[i] = sharp::AttrAsDouble(recombMatrix, i);
|
|
1478
1482
|
}
|
|
1479
1483
|
}
|
|
1480
|
-
baton->colourspaceInput = sharp::
|
|
1484
|
+
baton->colourspaceInput = sharp::AttrAsEnum<VipsInterpretation>(
|
|
1485
|
+
options, "colourspaceInput", VIPS_TYPE_INTERPRETATION);
|
|
1481
1486
|
if (baton->colourspaceInput == VIPS_INTERPRETATION_ERROR) {
|
|
1482
1487
|
baton->colourspaceInput = VIPS_INTERPRETATION_LAST;
|
|
1483
1488
|
}
|
|
1484
|
-
baton->colourspace = sharp::
|
|
1489
|
+
baton->colourspace = sharp::AttrAsEnum<VipsInterpretation>(options, "colourspace", VIPS_TYPE_INTERPRETATION);
|
|
1485
1490
|
if (baton->colourspace == VIPS_INTERPRETATION_ERROR) {
|
|
1486
1491
|
baton->colourspace = VIPS_INTERPRETATION_sRGB;
|
|
1487
1492
|
}
|
|
@@ -1496,7 +1501,9 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1496
1501
|
Napi::Array mdStrKeys = mdStrs.GetPropertyNames();
|
|
1497
1502
|
for (unsigned int i = 0; i < mdStrKeys.Length(); i++) {
|
|
1498
1503
|
std::string k = sharp::AttrAsStr(mdStrKeys, i);
|
|
1499
|
-
|
|
1504
|
+
if (mdStrs.HasOwnProperty(k)) {
|
|
1505
|
+
baton->withMetadataStrs.insert(std::make_pair(k, sharp::AttrAsStr(mdStrs, k)));
|
|
1506
|
+
}
|
|
1500
1507
|
}
|
|
1501
1508
|
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
|
|
1502
1509
|
// Format-specific
|
|
@@ -1527,9 +1534,12 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1527
1534
|
baton->webpNearLossless = sharp::AttrAsBool(options, "webpNearLossless");
|
|
1528
1535
|
baton->webpSmartSubsample = sharp::AttrAsBool(options, "webpSmartSubsample");
|
|
1529
1536
|
baton->webpEffort = sharp::AttrAsUint32(options, "webpEffort");
|
|
1537
|
+
baton->webpMinSize = sharp::AttrAsBool(options, "webpMinSize");
|
|
1538
|
+
baton->webpMixed = sharp::AttrAsBool(options, "webpMixed");
|
|
1530
1539
|
baton->gifBitdepth = sharp::AttrAsUint32(options, "gifBitdepth");
|
|
1531
1540
|
baton->gifEffort = sharp::AttrAsUint32(options, "gifEffort");
|
|
1532
1541
|
baton->gifDither = sharp::AttrAsDouble(options, "gifDither");
|
|
1542
|
+
baton->gifReoptimise = sharp::AttrAsBool(options, "gifReoptimise");
|
|
1533
1543
|
baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
|
|
1534
1544
|
baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid");
|
|
1535
1545
|
baton->tiffBitdepth = sharp::AttrAsUint32(options, "tiffBitdepth");
|
|
@@ -1541,28 +1551,19 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1541
1551
|
if (baton->tiffXres == 1.0 && baton->tiffYres == 1.0 && baton->withMetadataDensity > 0) {
|
|
1542
1552
|
baton->tiffXres = baton->tiffYres = baton->withMetadataDensity / 25.4;
|
|
1543
1553
|
}
|
|
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
|
-
|
|
1554
|
+
baton->tiffCompression = sharp::AttrAsEnum<VipsForeignTiffCompression>(
|
|
1555
|
+
options, "tiffCompression", VIPS_TYPE_FOREIGN_TIFF_COMPRESSION);
|
|
1556
|
+
baton->tiffPredictor = sharp::AttrAsEnum<VipsForeignTiffPredictor>(
|
|
1557
|
+
options, "tiffPredictor", VIPS_TYPE_FOREIGN_TIFF_PREDICTOR);
|
|
1558
|
+
baton->tiffResolutionUnit = sharp::AttrAsEnum<VipsForeignTiffResunit>(
|
|
1559
|
+
options, "tiffResolutionUnit", VIPS_TYPE_FOREIGN_TIFF_RESUNIT);
|
|
1555
1560
|
baton->heifQuality = sharp::AttrAsUint32(options, "heifQuality");
|
|
1556
1561
|
baton->heifLossless = sharp::AttrAsBool(options, "heifLossless");
|
|
1557
|
-
baton->heifCompression =
|
|
1558
|
-
|
|
1559
|
-
sharp::AttrAsStr(options, "heifCompression").data()));
|
|
1562
|
+
baton->heifCompression = sharp::AttrAsEnum<VipsForeignHeifCompression>(
|
|
1563
|
+
options, "heifCompression", VIPS_TYPE_FOREIGN_HEIF_COMPRESSION);
|
|
1560
1564
|
baton->heifEffort = sharp::AttrAsUint32(options, "heifEffort");
|
|
1561
1565
|
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()));
|
|
1566
|
+
baton->rawDepth = sharp::AttrAsEnum<VipsBandFormat>(options, "rawDepth", VIPS_TYPE_BAND_FORMAT);
|
|
1566
1567
|
// Animated output properties
|
|
1567
1568
|
if (sharp::HasAttr(options, "loop")) {
|
|
1568
1569
|
baton->loop = sharp::AttrAsUint32(options, "loop");
|
|
@@ -1570,24 +1571,19 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1570
1571
|
if (sharp::HasAttr(options, "delay")) {
|
|
1571
1572
|
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
|
1572
1573
|
}
|
|
1573
|
-
// Tile output
|
|
1574
1574
|
baton->tileSize = sharp::AttrAsUint32(options, "tileSize");
|
|
1575
1575
|
baton->tileOverlap = sharp::AttrAsUint32(options, "tileOverlap");
|
|
1576
1576
|
baton->tileAngle = sharp::AttrAsInt32(options, "tileAngle");
|
|
1577
1577
|
baton->tileBackground = sharp::AttrAsVectorOfDouble(options, "tileBackground");
|
|
1578
1578
|
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()));
|
|
1579
|
+
baton->tileContainer = sharp::AttrAsEnum<VipsForeignDzContainer>(
|
|
1580
|
+
options, "tileContainer", VIPS_TYPE_FOREIGN_DZ_CONTAINER);
|
|
1581
|
+
baton->tileLayout = sharp::AttrAsEnum<VipsForeignDzLayout>(options, "tileLayout", VIPS_TYPE_FOREIGN_DZ_LAYOUT);
|
|
1585
1582
|
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()));
|
|
1583
|
+
baton->tileDepth = sharp::AttrAsEnum<VipsForeignDzDepth>(options, "tileDepth", VIPS_TYPE_FOREIGN_DZ_DEPTH);
|
|
1589
1584
|
baton->tileCentre = sharp::AttrAsBool(options, "tileCentre");
|
|
1590
1585
|
baton->tileId = sharp::AttrAsStr(options, "tileId");
|
|
1586
|
+
baton->tileBasename = sharp::AttrAsStr(options, "tileBasename");
|
|
1591
1587
|
|
|
1592
1588
|
// Force random access for certain operations
|
|
1593
1589
|
if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
|
package/src/pipeline.h
CHANGED
|
@@ -67,6 +67,7 @@ struct PipelineBaton {
|
|
|
67
67
|
int width;
|
|
68
68
|
int height;
|
|
69
69
|
int channels;
|
|
70
|
+
VipsKernel kernel;
|
|
70
71
|
sharp::Canvas canvas;
|
|
71
72
|
int position;
|
|
72
73
|
std::vector<double> resizeBackground;
|
|
@@ -75,7 +76,6 @@ struct PipelineBaton {
|
|
|
75
76
|
int cropOffsetTop;
|
|
76
77
|
bool premultiplied;
|
|
77
78
|
bool tileCentre;
|
|
78
|
-
std::string kernel;
|
|
79
79
|
bool fastShrinkOnLoad;
|
|
80
80
|
double tintA;
|
|
81
81
|
double tintB;
|
|
@@ -97,11 +97,12 @@ struct PipelineBaton {
|
|
|
97
97
|
double sharpenY3;
|
|
98
98
|
int threshold;
|
|
99
99
|
bool thresholdGrayscale;
|
|
100
|
+
std::vector<double> trimBackground;
|
|
100
101
|
double trimThreshold;
|
|
101
102
|
int trimOffsetLeft;
|
|
102
103
|
int trimOffsetTop;
|
|
103
|
-
double linearA;
|
|
104
|
-
double linearB;
|
|
104
|
+
std::vector<double> linearA;
|
|
105
|
+
std::vector<double> linearB;
|
|
105
106
|
double gamma;
|
|
106
107
|
double gammaOut;
|
|
107
108
|
bool greyscale;
|
|
@@ -157,9 +158,12 @@ struct PipelineBaton {
|
|
|
157
158
|
bool webpLossless;
|
|
158
159
|
bool webpSmartSubsample;
|
|
159
160
|
int webpEffort;
|
|
161
|
+
bool webpMinSize;
|
|
162
|
+
bool webpMixed;
|
|
160
163
|
int gifBitdepth;
|
|
161
164
|
int gifEffort;
|
|
162
165
|
double gifDither;
|
|
166
|
+
bool gifReoptimise;
|
|
163
167
|
int tiffQuality;
|
|
164
168
|
VipsForeignTiffCompression tiffCompression;
|
|
165
169
|
VipsForeignTiffPredictor tiffPredictor;
|
|
@@ -209,6 +213,7 @@ struct PipelineBaton {
|
|
|
209
213
|
int tileSkipBlanks;
|
|
210
214
|
VipsForeignDzDepth tileDepth;
|
|
211
215
|
std::string tileId;
|
|
216
|
+
std::string tileBasename;
|
|
212
217
|
std::unique_ptr<double[]> recombMatrix;
|
|
213
218
|
|
|
214
219
|
PipelineBaton():
|
|
@@ -217,6 +222,7 @@ struct PipelineBaton {
|
|
|
217
222
|
topOffsetPre(-1),
|
|
218
223
|
topOffsetPost(-1),
|
|
219
224
|
channels(0),
|
|
225
|
+
kernel(VIPS_KERNEL_LANCZOS3),
|
|
220
226
|
canvas(sharp::Canvas::CROP),
|
|
221
227
|
position(0),
|
|
222
228
|
resizeBackground{ 0.0, 0.0, 0.0, 255.0 },
|
|
@@ -244,11 +250,12 @@ struct PipelineBaton {
|
|
|
244
250
|
sharpenY3(20.0),
|
|
245
251
|
threshold(0),
|
|
246
252
|
thresholdGrayscale(true),
|
|
253
|
+
trimBackground{},
|
|
247
254
|
trimThreshold(0.0),
|
|
248
255
|
trimOffsetLeft(0),
|
|
249
256
|
trimOffsetTop(0),
|
|
250
|
-
linearA
|
|
251
|
-
linearB
|
|
257
|
+
linearA{},
|
|
258
|
+
linearB{},
|
|
252
259
|
gamma(0.0),
|
|
253
260
|
greyscale(false),
|
|
254
261
|
normalise(false),
|
|
@@ -302,6 +309,12 @@ struct PipelineBaton {
|
|
|
302
309
|
webpLossless(false),
|
|
303
310
|
webpSmartSubsample(false),
|
|
304
311
|
webpEffort(4),
|
|
312
|
+
webpMinSize(false),
|
|
313
|
+
webpMixed(false),
|
|
314
|
+
gifBitdepth(8),
|
|
315
|
+
gifEffort(7),
|
|
316
|
+
gifDither(1.0),
|
|
317
|
+
gifReoptimise(false),
|
|
305
318
|
tiffQuality(80),
|
|
306
319
|
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
|
|
307
320
|
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|