sharp 0.25.4 → 0.26.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding.gyp +54 -67
- package/install/dll-copy.js +3 -1
- package/install/libvips.js +28 -13
- package/lib/constructor.js +16 -2
- package/lib/input.js +15 -6
- package/lib/libvips.js +1 -7
- package/lib/operation.js +99 -0
- package/lib/output.js +96 -7
- package/lib/platform.js +2 -1
- package/lib/resize.js +2 -1
- package/lib/utility.js +22 -1
- package/package.json +22 -16
- package/src/common.cc +122 -57
- package/src/common.h +23 -3
- package/src/libvips/cplusplus/VImage.cpp +451 -450
- package/src/libvips/cplusplus/vips-operators.cpp +117 -1
- package/src/metadata.cc +1 -1
- package/src/operations.cc +0 -23
- package/src/operations.h +0 -10
- package/src/pipeline.cc +100 -16
- package/src/pipeline.h +24 -2
- package/src/stats.cc +25 -6
- package/src/stats.h +7 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// bodies for vips operations
|
|
2
|
-
//
|
|
2
|
+
// Sun 5 Jul 22:36:37 BST 2020
|
|
3
3
|
// this file is generated automatically, do not edit!
|
|
4
4
|
|
|
5
5
|
VImage VImage::CMC2LCh( VOption *options ) const
|
|
@@ -754,6 +754,18 @@ VImage VImage::csvload( const char *filename, VOption *options )
|
|
|
754
754
|
return( out );
|
|
755
755
|
}
|
|
756
756
|
|
|
757
|
+
VImage VImage::csvload_source( VSource source, VOption *options )
|
|
758
|
+
{
|
|
759
|
+
VImage out;
|
|
760
|
+
|
|
761
|
+
call( "csvload_source",
|
|
762
|
+
(options ? options : VImage::option())->
|
|
763
|
+
set( "out", &out )->
|
|
764
|
+
set( "source", source ) );
|
|
765
|
+
|
|
766
|
+
return( out );
|
|
767
|
+
}
|
|
768
|
+
|
|
757
769
|
void VImage::csvsave( const char *filename, VOption *options ) const
|
|
758
770
|
{
|
|
759
771
|
call( "csvsave",
|
|
@@ -762,6 +774,14 @@ void VImage::csvsave( const char *filename, VOption *options ) const
|
|
|
762
774
|
set( "filename", filename ) );
|
|
763
775
|
}
|
|
764
776
|
|
|
777
|
+
void VImage::csvsave_target( VTarget target, VOption *options ) const
|
|
778
|
+
{
|
|
779
|
+
call( "csvsave_target",
|
|
780
|
+
(options ? options : VImage::option())->
|
|
781
|
+
set( "in", *this )->
|
|
782
|
+
set( "target", target ) );
|
|
783
|
+
}
|
|
784
|
+
|
|
765
785
|
VImage VImage::dE00( VImage right, VOption *options ) const
|
|
766
786
|
{
|
|
767
787
|
VImage out;
|
|
@@ -1218,6 +1238,18 @@ VImage VImage::gifload_buffer( VipsBlob *buffer, VOption *options )
|
|
|
1218
1238
|
return( out );
|
|
1219
1239
|
}
|
|
1220
1240
|
|
|
1241
|
+
VImage VImage::gifload_source( VSource source, VOption *options )
|
|
1242
|
+
{
|
|
1243
|
+
VImage out;
|
|
1244
|
+
|
|
1245
|
+
call( "gifload_source",
|
|
1246
|
+
(options ? options : VImage::option())->
|
|
1247
|
+
set( "out", &out )->
|
|
1248
|
+
set( "source", source ) );
|
|
1249
|
+
|
|
1250
|
+
return( out );
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1221
1253
|
VImage VImage::globalbalance( VOption *options ) const
|
|
1222
1254
|
{
|
|
1223
1255
|
VImage out;
|
|
@@ -1297,6 +1329,18 @@ VImage VImage::heifload_buffer( VipsBlob *buffer, VOption *options )
|
|
|
1297
1329
|
return( out );
|
|
1298
1330
|
}
|
|
1299
1331
|
|
|
1332
|
+
VImage VImage::heifload_source( VSource source, VOption *options )
|
|
1333
|
+
{
|
|
1334
|
+
VImage out;
|
|
1335
|
+
|
|
1336
|
+
call( "heifload_source",
|
|
1337
|
+
(options ? options : VImage::option())->
|
|
1338
|
+
set( "out", &out )->
|
|
1339
|
+
set( "source", source ) );
|
|
1340
|
+
|
|
1341
|
+
return( out );
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1300
1344
|
void VImage::heifsave( const char *filename, VOption *options ) const
|
|
1301
1345
|
{
|
|
1302
1346
|
call( "heifsave",
|
|
@@ -1317,6 +1361,14 @@ VipsBlob *VImage::heifsave_buffer( VOption *options ) const
|
|
|
1317
1361
|
return( buffer );
|
|
1318
1362
|
}
|
|
1319
1363
|
|
|
1364
|
+
void VImage::heifsave_target( VTarget target, VOption *options ) const
|
|
1365
|
+
{
|
|
1366
|
+
call( "heifsave_target",
|
|
1367
|
+
(options ? options : VImage::option())->
|
|
1368
|
+
set( "in", *this )->
|
|
1369
|
+
set( "target", target ) );
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1320
1372
|
VImage VImage::hist_cum( VOption *options ) const
|
|
1321
1373
|
{
|
|
1322
1374
|
VImage out;
|
|
@@ -2028,6 +2080,18 @@ VImage VImage::matload( const char *filename, VOption *options )
|
|
|
2028
2080
|
return( out );
|
|
2029
2081
|
}
|
|
2030
2082
|
|
|
2083
|
+
VImage VImage::matrixinvert( VOption *options ) const
|
|
2084
|
+
{
|
|
2085
|
+
VImage out;
|
|
2086
|
+
|
|
2087
|
+
call( "matrixinvert",
|
|
2088
|
+
(options ? options : VImage::option())->
|
|
2089
|
+
set( "in", *this )->
|
|
2090
|
+
set( "out", &out ) );
|
|
2091
|
+
|
|
2092
|
+
return( out );
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2031
2095
|
VImage VImage::matrixload( const char *filename, VOption *options )
|
|
2032
2096
|
{
|
|
2033
2097
|
VImage out;
|
|
@@ -2040,6 +2104,18 @@ VImage VImage::matrixload( const char *filename, VOption *options )
|
|
|
2040
2104
|
return( out );
|
|
2041
2105
|
}
|
|
2042
2106
|
|
|
2107
|
+
VImage VImage::matrixload_source( VSource source, VOption *options )
|
|
2108
|
+
{
|
|
2109
|
+
VImage out;
|
|
2110
|
+
|
|
2111
|
+
call( "matrixload_source",
|
|
2112
|
+
(options ? options : VImage::option())->
|
|
2113
|
+
set( "out", &out )->
|
|
2114
|
+
set( "source", source ) );
|
|
2115
|
+
|
|
2116
|
+
return( out );
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2043
2119
|
void VImage::matrixprint( VOption *options ) const
|
|
2044
2120
|
{
|
|
2045
2121
|
call( "matrixprint",
|
|
@@ -2055,6 +2131,14 @@ void VImage::matrixsave( const char *filename, VOption *options ) const
|
|
|
2055
2131
|
set( "filename", filename ) );
|
|
2056
2132
|
}
|
|
2057
2133
|
|
|
2134
|
+
void VImage::matrixsave_target( VTarget target, VOption *options ) const
|
|
2135
|
+
{
|
|
2136
|
+
call( "matrixsave_target",
|
|
2137
|
+
(options ? options : VImage::option())->
|
|
2138
|
+
set( "in", *this )->
|
|
2139
|
+
set( "target", target ) );
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2058
2142
|
double VImage::max( VOption *options ) const
|
|
2059
2143
|
{
|
|
2060
2144
|
double out;
|
|
@@ -2256,6 +2340,18 @@ VImage VImage::pdfload_buffer( VipsBlob *buffer, VOption *options )
|
|
|
2256
2340
|
return( out );
|
|
2257
2341
|
}
|
|
2258
2342
|
|
|
2343
|
+
VImage VImage::pdfload_source( VSource source, VOption *options )
|
|
2344
|
+
{
|
|
2345
|
+
VImage out;
|
|
2346
|
+
|
|
2347
|
+
call( "pdfload_source",
|
|
2348
|
+
(options ? options : VImage::option())->
|
|
2349
|
+
set( "out", &out )->
|
|
2350
|
+
set( "source", source ) );
|
|
2351
|
+
|
|
2352
|
+
return( out );
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2259
2355
|
int VImage::percent( double percent, VOption *options ) const
|
|
2260
2356
|
{
|
|
2261
2357
|
int threshold;
|
|
@@ -2371,6 +2467,18 @@ VImage VImage::ppmload( const char *filename, VOption *options )
|
|
|
2371
2467
|
return( out );
|
|
2372
2468
|
}
|
|
2373
2469
|
|
|
2470
|
+
VImage VImage::ppmload_source( VSource source, VOption *options )
|
|
2471
|
+
{
|
|
2472
|
+
VImage out;
|
|
2473
|
+
|
|
2474
|
+
call( "ppmload_source",
|
|
2475
|
+
(options ? options : VImage::option())->
|
|
2476
|
+
set( "out", &out )->
|
|
2477
|
+
set( "source", source ) );
|
|
2478
|
+
|
|
2479
|
+
return( out );
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2374
2482
|
void VImage::ppmsave( const char *filename, VOption *options ) const
|
|
2375
2483
|
{
|
|
2376
2484
|
call( "ppmsave",
|
|
@@ -2379,6 +2487,14 @@ void VImage::ppmsave( const char *filename, VOption *options ) const
|
|
|
2379
2487
|
set( "filename", filename ) );
|
|
2380
2488
|
}
|
|
2381
2489
|
|
|
2490
|
+
void VImage::ppmsave_target( VTarget target, VOption *options ) const
|
|
2491
|
+
{
|
|
2492
|
+
call( "ppmsave_target",
|
|
2493
|
+
(options ? options : VImage::option())->
|
|
2494
|
+
set( "in", *this )->
|
|
2495
|
+
set( "target", target ) );
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2382
2498
|
VImage VImage::premultiply( VOption *options ) const
|
|
2383
2499
|
{
|
|
2384
2500
|
VImage out;
|
package/src/metadata.cc
CHANGED
|
@@ -189,7 +189,7 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
189
189
|
if (!baton->levels.empty()) {
|
|
190
190
|
int i = 0;
|
|
191
191
|
Napi::Array levels = Napi::Array::New(env, static_cast<size_t>(baton->levels.size()));
|
|
192
|
-
for (std::pair<int, int> const l : baton->levels) {
|
|
192
|
+
for (std::pair<int, int> const &l : baton->levels) {
|
|
193
193
|
Napi::Object level = Napi::Object::New(env);
|
|
194
194
|
level.Set("width", l.first);
|
|
195
195
|
level.Set("height", l.second);
|
package/src/operations.cc
CHANGED
|
@@ -27,29 +27,6 @@ using vips::VImage;
|
|
|
27
27
|
using vips::VError;
|
|
28
28
|
|
|
29
29
|
namespace sharp {
|
|
30
|
-
|
|
31
|
-
/*
|
|
32
|
-
Removes alpha channel, if any.
|
|
33
|
-
*/
|
|
34
|
-
VImage RemoveAlpha(VImage image) {
|
|
35
|
-
if (HasAlpha(image)) {
|
|
36
|
-
image = image.extract_band(0, VImage::option()->set("n", image.bands() - 1));
|
|
37
|
-
}
|
|
38
|
-
return image;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/*
|
|
42
|
-
Ensures alpha channel, if missing.
|
|
43
|
-
*/
|
|
44
|
-
VImage EnsureAlpha(VImage image) {
|
|
45
|
-
if (!HasAlpha(image)) {
|
|
46
|
-
std::vector<double> alpha;
|
|
47
|
-
alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
|
|
48
|
-
image = image.bandjoin_const(alpha);
|
|
49
|
-
}
|
|
50
|
-
return image;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
30
|
/*
|
|
54
31
|
* Tint an image using the specified chroma, preserving the original image luminance
|
|
55
32
|
*/
|
package/src/operations.h
CHANGED
|
@@ -25,16 +25,6 @@ using vips::VImage;
|
|
|
25
25
|
|
|
26
26
|
namespace sharp {
|
|
27
27
|
|
|
28
|
-
/*
|
|
29
|
-
Removes alpha channel, if any.
|
|
30
|
-
*/
|
|
31
|
-
VImage RemoveAlpha(VImage image);
|
|
32
|
-
|
|
33
|
-
/*
|
|
34
|
-
Ensures alpha channel, if missing.
|
|
35
|
-
*/
|
|
36
|
-
VImage EnsureAlpha(VImage image);
|
|
37
|
-
|
|
38
28
|
/*
|
|
39
29
|
* Tint an image using the specified chroma, preserving the original image luminance
|
|
40
30
|
*/
|
package/src/pipeline.cc
CHANGED
|
@@ -485,6 +485,18 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
485
485
|
baton->leftOffsetPost, baton->topOffsetPost, baton->widthPost, baton->heightPost);
|
|
486
486
|
}
|
|
487
487
|
|
|
488
|
+
// Affine transform
|
|
489
|
+
if (baton->affineMatrix.size() > 0) {
|
|
490
|
+
std::vector<double> background;
|
|
491
|
+
std::tie(image, background) = sharp::ApplyAlpha(image, baton->affineBackground);
|
|
492
|
+
image = image.affine(baton->affineMatrix, VImage::option()->set("background", background)
|
|
493
|
+
->set("idx", baton->affineIdx)
|
|
494
|
+
->set("idy", baton->affineIdy)
|
|
495
|
+
->set("odx", baton->affineOdx)
|
|
496
|
+
->set("ody", baton->affineOdy)
|
|
497
|
+
->set("interpolate", baton->affineInterpolator));
|
|
498
|
+
}
|
|
499
|
+
|
|
488
500
|
// Extend edges
|
|
489
501
|
if (baton->extendTop > 0 || baton->extendBottom > 0 || baton->extendLeft > 0 || baton->extendRight > 0) {
|
|
490
502
|
std::vector<double> background;
|
|
@@ -684,6 +696,15 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
684
696
|
}
|
|
685
697
|
}
|
|
686
698
|
|
|
699
|
+
// Apply output ICC profile
|
|
700
|
+
if (!baton->withMetadataIcc.empty()) {
|
|
701
|
+
image = image.icc_transform(
|
|
702
|
+
const_cast<char*>(baton->withMetadataIcc.data()),
|
|
703
|
+
VImage::option()
|
|
704
|
+
->set("input_profile", "srgb")
|
|
705
|
+
->set("intent", VIPS_INTENT_PERCEPTUAL));
|
|
706
|
+
}
|
|
707
|
+
|
|
687
708
|
// Override EXIF Orientation tag
|
|
688
709
|
if (baton->withMetadata && baton->withMetadataOrientation != -1) {
|
|
689
710
|
image = sharp::SetExifOrientation(image, baton->withMetadataOrientation);
|
|
@@ -693,6 +714,16 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
693
714
|
baton->channels = image.bands();
|
|
694
715
|
baton->width = image.width();
|
|
695
716
|
baton->height = image.height();
|
|
717
|
+
|
|
718
|
+
bool const supportsGifOutput = vips_type_find("VipsOperation", "magicksave") != 0 &&
|
|
719
|
+
vips_type_find("VipsOperation", "magicksave_buffer") != 0;
|
|
720
|
+
|
|
721
|
+
image = sharp::SetAnimationProperties(
|
|
722
|
+
image,
|
|
723
|
+
baton->pageHeight,
|
|
724
|
+
baton->delay,
|
|
725
|
+
baton->loop);
|
|
726
|
+
|
|
696
727
|
// Output
|
|
697
728
|
if (baton->fileOut.empty()) {
|
|
698
729
|
// Buffer output
|
|
@@ -703,7 +734,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
703
734
|
->set("strip", !baton->withMetadata)
|
|
704
735
|
->set("Q", baton->jpegQuality)
|
|
705
736
|
->set("interlace", baton->jpegProgressive)
|
|
706
|
-
->set("
|
|
737
|
+
->set("subsample_mode", baton->jpegChromaSubsampling == "4:4:4"
|
|
738
|
+
? VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF
|
|
739
|
+
: VIPS_FOREIGN_JPEG_SUBSAMPLE_ON)
|
|
707
740
|
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
|
708
741
|
->set("quant_table", baton->jpegQuantisationTable)
|
|
709
742
|
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
|
@@ -720,8 +753,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
720
753
|
baton->channels = std::min(baton->channels, 3);
|
|
721
754
|
}
|
|
722
755
|
} else if (baton->formatOut == "png" || (baton->formatOut == "input" &&
|
|
723
|
-
(inputImageType == sharp::ImageType::PNG || inputImageType == sharp::ImageType::GIF ||
|
|
724
|
-
|
|
756
|
+
(inputImageType == sharp::ImageType::PNG || (inputImageType == sharp::ImageType::GIF && !supportsGifOutput) ||
|
|
757
|
+
inputImageType == sharp::ImageType::SVG))) {
|
|
725
758
|
// Write PNG to buffer
|
|
726
759
|
sharp::AssertImageTypeDimensions(image, sharp::ImageType::PNG);
|
|
727
760
|
VipsArea *area = VIPS_AREA(image.pngsave_buffer(VImage::option()
|
|
@@ -755,6 +788,20 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
755
788
|
area->free_fn = nullptr;
|
|
756
789
|
vips_area_unref(area);
|
|
757
790
|
baton->formatOut = "webp";
|
|
791
|
+
} else if (baton->formatOut == "gif" ||
|
|
792
|
+
(baton->formatOut == "input" && inputImageType == sharp::ImageType::GIF && supportsGifOutput)) {
|
|
793
|
+
// Write GIF to buffer
|
|
794
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
|
|
795
|
+
VipsArea *area = VIPS_AREA(image.magicksave_buffer(VImage::option()
|
|
796
|
+
->set("strip", !baton->withMetadata)
|
|
797
|
+
->set("optimize_gif_frames", TRUE)
|
|
798
|
+
->set("optimize_gif_transparency", TRUE)
|
|
799
|
+
->set("format", "gif")));
|
|
800
|
+
baton->bufferOut = static_cast<char*>(area->data);
|
|
801
|
+
baton->bufferOutLength = area->length;
|
|
802
|
+
area->free_fn = nullptr;
|
|
803
|
+
vips_area_unref(area);
|
|
804
|
+
baton->formatOut = "gif";
|
|
758
805
|
} else if (baton->formatOut == "tiff" ||
|
|
759
806
|
(baton->formatOut == "input" && inputImageType == sharp::ImageType::TIFF)) {
|
|
760
807
|
// Write TIFF to buffer
|
|
@@ -769,7 +816,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
769
816
|
VipsArea *area = VIPS_AREA(image.tiffsave_buffer(VImage::option()
|
|
770
817
|
->set("strip", !baton->withMetadata)
|
|
771
818
|
->set("Q", baton->tiffQuality)
|
|
772
|
-
->set("
|
|
819
|
+
->set("bitdepth", baton->tiffBitdepth)
|
|
773
820
|
->set("compression", baton->tiffCompression)
|
|
774
821
|
->set("predictor", baton->tiffPredictor)
|
|
775
822
|
->set("pyramid", baton->tiffPyramid)
|
|
@@ -830,13 +877,16 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
830
877
|
bool const isJpeg = sharp::IsJpeg(baton->fileOut);
|
|
831
878
|
bool const isPng = sharp::IsPng(baton->fileOut);
|
|
832
879
|
bool const isWebp = sharp::IsWebp(baton->fileOut);
|
|
880
|
+
bool const isGif = sharp::IsGif(baton->fileOut);
|
|
833
881
|
bool const isTiff = sharp::IsTiff(baton->fileOut);
|
|
834
882
|
bool const isHeif = sharp::IsHeif(baton->fileOut);
|
|
835
883
|
bool const isDz = sharp::IsDz(baton->fileOut);
|
|
836
884
|
bool const isDzZip = sharp::IsDzZip(baton->fileOut);
|
|
837
885
|
bool const isV = sharp::IsV(baton->fileOut);
|
|
838
886
|
bool const mightMatchInput = baton->formatOut == "input";
|
|
839
|
-
bool const willMatchInput = mightMatchInput &&
|
|
887
|
+
bool const willMatchInput = mightMatchInput &&
|
|
888
|
+
!(isJpeg || isPng || isWebp || isGif || isTiff || isDz || isDzZip || isV);
|
|
889
|
+
|
|
840
890
|
if (baton->formatOut == "jpeg" || (mightMatchInput && isJpeg) ||
|
|
841
891
|
(willMatchInput && inputImageType == sharp::ImageType::JPEG)) {
|
|
842
892
|
// Write JPEG to file
|
|
@@ -845,7 +895,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
845
895
|
->set("strip", !baton->withMetadata)
|
|
846
896
|
->set("Q", baton->jpegQuality)
|
|
847
897
|
->set("interlace", baton->jpegProgressive)
|
|
848
|
-
->set("
|
|
898
|
+
->set("subsample_mode", baton->jpegChromaSubsampling == "4:4:4"
|
|
899
|
+
? VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF
|
|
900
|
+
: VIPS_FOREIGN_JPEG_SUBSAMPLE_ON)
|
|
849
901
|
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
|
850
902
|
->set("quant_table", baton->jpegQuantisationTable)
|
|
851
903
|
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
|
@@ -854,8 +906,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
854
906
|
baton->formatOut = "jpeg";
|
|
855
907
|
baton->channels = std::min(baton->channels, 3);
|
|
856
908
|
} else if (baton->formatOut == "png" || (mightMatchInput && isPng) || (willMatchInput &&
|
|
857
|
-
(inputImageType == sharp::ImageType::PNG || inputImageType == sharp::ImageType::GIF ||
|
|
858
|
-
|
|
909
|
+
(inputImageType == sharp::ImageType::PNG || (inputImageType == sharp::ImageType::GIF && !supportsGifOutput) ||
|
|
910
|
+
inputImageType == sharp::ImageType::SVG))) {
|
|
859
911
|
// Write PNG to file
|
|
860
912
|
sharp::AssertImageTypeDimensions(image, sharp::ImageType::PNG);
|
|
861
913
|
image.pngsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
@@ -881,6 +933,16 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
881
933
|
->set("reduction_effort", baton->webpReductionEffort)
|
|
882
934
|
->set("alpha_q", baton->webpAlphaQuality));
|
|
883
935
|
baton->formatOut = "webp";
|
|
936
|
+
} else if (baton->formatOut == "gif" || (mightMatchInput && isGif) ||
|
|
937
|
+
(willMatchInput && inputImageType == sharp::ImageType::GIF && supportsGifOutput)) {
|
|
938
|
+
// Write GIF to file
|
|
939
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
|
|
940
|
+
image.magicksave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
941
|
+
->set("strip", !baton->withMetadata)
|
|
942
|
+
->set("optimize_gif_frames", TRUE)
|
|
943
|
+
->set("optimize_gif_transparency", TRUE)
|
|
944
|
+
->set("format", "gif"));
|
|
945
|
+
baton->formatOut = "gif";
|
|
884
946
|
} else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
|
|
885
947
|
(willMatchInput && inputImageType == sharp::ImageType::TIFF)) {
|
|
886
948
|
// Write TIFF to file
|
|
@@ -891,7 +953,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
891
953
|
image.tiffsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
892
954
|
->set("strip", !baton->withMetadata)
|
|
893
955
|
->set("Q", baton->tiffQuality)
|
|
894
|
-
->set("
|
|
956
|
+
->set("bitdepth", baton->tiffBitdepth)
|
|
895
957
|
->set("compression", baton->tiffCompression)
|
|
896
958
|
->set("predictor", baton->tiffPredictor)
|
|
897
959
|
->set("pyramid", baton->tiffPyramid)
|
|
@@ -940,7 +1002,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
940
1002
|
std::vector<std::pair<std::string, std::string>> options {
|
|
941
1003
|
{"Q", std::to_string(baton->jpegQuality)},
|
|
942
1004
|
{"interlace", baton->jpegProgressive ? "TRUE" : "FALSE"},
|
|
943
|
-
{"
|
|
1005
|
+
{"subsample_mode", baton->jpegChromaSubsampling == "4:4:4" ? "off" : "on"},
|
|
944
1006
|
{"trellis_quant", baton->jpegTrellisQuantisation ? "TRUE" : "FALSE"},
|
|
945
1007
|
{"quant_table", std::to_string(baton->jpegQuantisationTable)},
|
|
946
1008
|
{"overshoot_deringing", baton->jpegOvershootDeringing ? "TRUE": "FALSE"},
|
|
@@ -964,6 +1026,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
964
1026
|
->set("suffix", const_cast<char*>(suffix.data()))
|
|
965
1027
|
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
|
966
1028
|
->set("background", baton->tileBackground)
|
|
1029
|
+
->set("centre", baton->tileCentre)
|
|
967
1030
|
->set("skip_blanks", baton->tileSkipBlanks);
|
|
968
1031
|
// libvips chooses a default depth based on layout. Instead of replicating that logic here by
|
|
969
1032
|
// not passing anything - libvips will handle choice
|
|
@@ -1198,7 +1261,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1198
1261
|
// Resize options
|
|
1199
1262
|
baton->withoutEnlargement = sharp::AttrAsBool(options, "withoutEnlargement");
|
|
1200
1263
|
baton->position = sharp::AttrAsInt32(options, "position");
|
|
1201
|
-
baton->resizeBackground = sharp::
|
|
1264
|
+
baton->resizeBackground = sharp::AttrAsVectorOfDouble(options, "resizeBackground");
|
|
1202
1265
|
baton->kernel = sharp::AttrAsStr(options, "kernel");
|
|
1203
1266
|
baton->fastShrinkOnLoad = sharp::AttrAsBool(options, "fastShrinkOnLoad");
|
|
1204
1267
|
// Join Channel Options
|
|
@@ -1211,7 +1274,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1211
1274
|
}
|
|
1212
1275
|
// Operators
|
|
1213
1276
|
baton->flatten = sharp::AttrAsBool(options, "flatten");
|
|
1214
|
-
baton->flattenBackground = sharp::
|
|
1277
|
+
baton->flattenBackground = sharp::AttrAsVectorOfDouble(options, "flattenBackground");
|
|
1215
1278
|
baton->negate = sharp::AttrAsBool(options, "negate");
|
|
1216
1279
|
baton->blurSigma = sharp::AttrAsDouble(options, "blurSigma");
|
|
1217
1280
|
baton->brightness = sharp::AttrAsDouble(options, "brightness");
|
|
@@ -1233,7 +1296,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1233
1296
|
baton->useExifOrientation = sharp::AttrAsBool(options, "useExifOrientation");
|
|
1234
1297
|
baton->angle = sharp::AttrAsInt32(options, "angle");
|
|
1235
1298
|
baton->rotationAngle = sharp::AttrAsDouble(options, "rotationAngle");
|
|
1236
|
-
baton->rotationBackground = sharp::
|
|
1299
|
+
baton->rotationBackground = sharp::AttrAsVectorOfDouble(options, "rotationBackground");
|
|
1237
1300
|
baton->rotateBeforePreExtract = sharp::AttrAsBool(options, "rotateBeforePreExtract");
|
|
1238
1301
|
baton->flip = sharp::AttrAsBool(options, "flip");
|
|
1239
1302
|
baton->flop = sharp::AttrAsBool(options, "flop");
|
|
@@ -1241,8 +1304,15 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1241
1304
|
baton->extendBottom = sharp::AttrAsInt32(options, "extendBottom");
|
|
1242
1305
|
baton->extendLeft = sharp::AttrAsInt32(options, "extendLeft");
|
|
1243
1306
|
baton->extendRight = sharp::AttrAsInt32(options, "extendRight");
|
|
1244
|
-
baton->extendBackground = sharp::
|
|
1307
|
+
baton->extendBackground = sharp::AttrAsVectorOfDouble(options, "extendBackground");
|
|
1245
1308
|
baton->extractChannel = sharp::AttrAsInt32(options, "extractChannel");
|
|
1309
|
+
baton->affineMatrix = sharp::AttrAsVectorOfDouble(options, "affineMatrix");
|
|
1310
|
+
baton->affineBackground = sharp::AttrAsVectorOfDouble(options, "affineBackground");
|
|
1311
|
+
baton->affineIdx = sharp::AttrAsDouble(options, "affineIdx");
|
|
1312
|
+
baton->affineIdy = sharp::AttrAsDouble(options, "affineIdy");
|
|
1313
|
+
baton->affineOdx = sharp::AttrAsDouble(options, "affineOdx");
|
|
1314
|
+
baton->affineOdy = sharp::AttrAsDouble(options, "affineOdy");
|
|
1315
|
+
baton->affineInterpolator = vips::VInterpolate::new_from_name(sharp::AttrAsStr(options, "affineInterpolator").data());
|
|
1246
1316
|
|
|
1247
1317
|
baton->removeAlpha = sharp::AttrAsBool(options, "removeAlpha");
|
|
1248
1318
|
baton->ensureAlpha = sharp::AttrAsBool(options, "ensureAlpha");
|
|
@@ -1282,6 +1352,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1282
1352
|
baton->fileOut = sharp::AttrAsStr(options, "fileOut");
|
|
1283
1353
|
baton->withMetadata = sharp::AttrAsBool(options, "withMetadata");
|
|
1284
1354
|
baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
|
|
1355
|
+
baton->withMetadataIcc = sharp::AttrAsStr(options, "withMetadataIcc");
|
|
1285
1356
|
// Format-specific
|
|
1286
1357
|
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
|
|
1287
1358
|
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
|
|
@@ -1306,7 +1377,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1306
1377
|
baton->webpReductionEffort = sharp::AttrAsUint32(options, "webpReductionEffort");
|
|
1307
1378
|
baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
|
|
1308
1379
|
baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid");
|
|
1309
|
-
baton->
|
|
1380
|
+
baton->tiffBitdepth = sharp::AttrAsUint32(options, "tiffBitdepth");
|
|
1310
1381
|
baton->tiffTile = sharp::AttrAsBool(options, "tiffTile");
|
|
1311
1382
|
baton->tiffTileWidth = sharp::AttrAsUint32(options, "tiffTileWidth");
|
|
1312
1383
|
baton->tiffTileHeight = sharp::AttrAsUint32(options, "tiffTileHeight");
|
|
@@ -1324,11 +1395,23 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1324
1395
|
baton->heifCompression = static_cast<VipsForeignHeifCompression>(
|
|
1325
1396
|
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_HEIF_COMPRESSION,
|
|
1326
1397
|
sharp::AttrAsStr(options, "heifCompression").data()));
|
|
1398
|
+
|
|
1399
|
+
// Animated output
|
|
1400
|
+
if (sharp::HasAttr(options, "pageHeight")) {
|
|
1401
|
+
baton->pageHeight = sharp::AttrAsUint32(options, "pageHeight");
|
|
1402
|
+
}
|
|
1403
|
+
if (sharp::HasAttr(options, "loop")) {
|
|
1404
|
+
baton->loop = sharp::AttrAsUint32(options, "loop");
|
|
1405
|
+
}
|
|
1406
|
+
if (sharp::HasAttr(options, "delay")) {
|
|
1407
|
+
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1327
1410
|
// Tile output
|
|
1328
1411
|
baton->tileSize = sharp::AttrAsUint32(options, "tileSize");
|
|
1329
1412
|
baton->tileOverlap = sharp::AttrAsUint32(options, "tileOverlap");
|
|
1330
1413
|
baton->tileAngle = sharp::AttrAsInt32(options, "tileAngle");
|
|
1331
|
-
baton->tileBackground = sharp::
|
|
1414
|
+
baton->tileBackground = sharp::AttrAsVectorOfDouble(options, "tileBackground");
|
|
1332
1415
|
baton->tileSkipBlanks = sharp::AttrAsInt32(options, "tileSkipBlanks");
|
|
1333
1416
|
baton->tileContainer = static_cast<VipsForeignDzContainer>(
|
|
1334
1417
|
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_CONTAINER,
|
|
@@ -1340,6 +1423,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1340
1423
|
baton->tileDepth = static_cast<VipsForeignDzDepth>(
|
|
1341
1424
|
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_DEPTH,
|
|
1342
1425
|
sharp::AttrAsStr(options, "tileDepth").data()));
|
|
1426
|
+
baton->tileCentre = sharp::AttrAsBool(options, "tileCentre");
|
|
1343
1427
|
|
|
1344
1428
|
// Force random access for certain operations
|
|
1345
1429
|
if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
|
package/src/pipeline.h
CHANGED
|
@@ -79,6 +79,7 @@ struct PipelineBaton {
|
|
|
79
79
|
int cropOffsetLeft;
|
|
80
80
|
int cropOffsetTop;
|
|
81
81
|
bool premultiplied;
|
|
82
|
+
bool tileCentre;
|
|
82
83
|
std::string kernel;
|
|
83
84
|
bool fastShrinkOnLoad;
|
|
84
85
|
double tintA;
|
|
@@ -118,6 +119,13 @@ struct PipelineBaton {
|
|
|
118
119
|
int extendRight;
|
|
119
120
|
std::vector<double> extendBackground;
|
|
120
121
|
bool withoutEnlargement;
|
|
122
|
+
std::vector<double> affineMatrix;
|
|
123
|
+
std::vector<double> affineBackground;
|
|
124
|
+
double affineIdx;
|
|
125
|
+
double affineIdy;
|
|
126
|
+
double affineOdx;
|
|
127
|
+
double affineOdy;
|
|
128
|
+
vips::VInterpolate affineInterpolator;
|
|
121
129
|
int jpegQuality;
|
|
122
130
|
bool jpegProgressive;
|
|
123
131
|
std::string jpegChromaSubsampling;
|
|
@@ -143,7 +151,7 @@ struct PipelineBaton {
|
|
|
143
151
|
VipsForeignTiffCompression tiffCompression;
|
|
144
152
|
VipsForeignTiffPredictor tiffPredictor;
|
|
145
153
|
bool tiffPyramid;
|
|
146
|
-
|
|
154
|
+
int tiffBitdepth;
|
|
147
155
|
bool tiffTile;
|
|
148
156
|
int tiffTileHeight;
|
|
149
157
|
int tiffTileWidth;
|
|
@@ -155,6 +163,7 @@ struct PipelineBaton {
|
|
|
155
163
|
std::string err;
|
|
156
164
|
bool withMetadata;
|
|
157
165
|
int withMetadataOrientation;
|
|
166
|
+
std::string withMetadataIcc;
|
|
158
167
|
std::unique_ptr<double[]> convKernel;
|
|
159
168
|
int convKernelWidth;
|
|
160
169
|
int convKernelHeight;
|
|
@@ -167,6 +176,9 @@ struct PipelineBaton {
|
|
|
167
176
|
bool removeAlpha;
|
|
168
177
|
bool ensureAlpha;
|
|
169
178
|
VipsInterpretation colourspace;
|
|
179
|
+
int pageHeight;
|
|
180
|
+
std::vector<int> delay;
|
|
181
|
+
int loop;
|
|
170
182
|
int tileSize;
|
|
171
183
|
int tileOverlap;
|
|
172
184
|
VipsForeignDzContainer tileContainer;
|
|
@@ -226,6 +238,13 @@ struct PipelineBaton {
|
|
|
226
238
|
extendRight(0),
|
|
227
239
|
extendBackground{ 0.0, 0.0, 0.0, 255.0 },
|
|
228
240
|
withoutEnlargement(false),
|
|
241
|
+
affineMatrix{ 1.0, 0.0, 0.0, 1.0 },
|
|
242
|
+
affineBackground{ 0.0, 0.0, 0.0, 255.0 },
|
|
243
|
+
affineIdx(0),
|
|
244
|
+
affineIdy(0),
|
|
245
|
+
affineOdx(0),
|
|
246
|
+
affineOdy(0),
|
|
247
|
+
affineInterpolator(vips::VInterpolate::new_from_name("bicubic")),
|
|
229
248
|
jpegQuality(80),
|
|
230
249
|
jpegProgressive(false),
|
|
231
250
|
jpegChromaSubsampling("4:2:0"),
|
|
@@ -251,7 +270,7 @@ struct PipelineBaton {
|
|
|
251
270
|
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
|
|
252
271
|
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|
|
253
272
|
tiffPyramid(false),
|
|
254
|
-
|
|
273
|
+
tiffBitdepth(8),
|
|
255
274
|
tiffTile(false),
|
|
256
275
|
tiffTileHeight(256),
|
|
257
276
|
tiffTileWidth(256),
|
|
@@ -273,6 +292,9 @@ struct PipelineBaton {
|
|
|
273
292
|
removeAlpha(false),
|
|
274
293
|
ensureAlpha(false),
|
|
275
294
|
colourspace(VIPS_INTERPRETATION_LAST),
|
|
295
|
+
pageHeight(0),
|
|
296
|
+
delay{-1},
|
|
297
|
+
loop(-1),
|
|
276
298
|
tileSize(256),
|
|
277
299
|
tileOverlap(0),
|
|
278
300
|
tileContainer(VIPS_FOREIGN_DZ_CONTAINER_FS),
|
package/src/stats.cc
CHANGED
|
@@ -80,12 +80,26 @@ class StatsWorker : public Napi::AsyncWorker {
|
|
|
80
80
|
// Estimate entropy via histogram of greyscale value frequency
|
|
81
81
|
baton->entropy = std::abs(greyscale.hist_find().hist_entropy());
|
|
82
82
|
// Estimate sharpness via standard deviation of greyscale laplacian
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
if (image.width() > 1 || image.height() > 1) {
|
|
84
|
+
VImage laplacian = VImage::new_matrixv(3, 3,
|
|
85
|
+
0.0, 1.0, 0.0,
|
|
86
|
+
1.0, -4.0, 1.0,
|
|
87
|
+
0.0, 1.0, 0.0);
|
|
88
|
+
laplacian.set("scale", 9.0);
|
|
89
|
+
baton->sharpness = greyscale.conv(laplacian).deviate();
|
|
90
|
+
}
|
|
91
|
+
// Most dominant sRGB colour via 4096-bin 3D histogram
|
|
92
|
+
vips::VImage hist = sharp::RemoveAlpha(image)
|
|
93
|
+
.colourspace(VIPS_INTERPRETATION_sRGB)
|
|
94
|
+
.hist_find_ndim(VImage::option()->set("bins", 16));
|
|
95
|
+
std::complex<double> maxpos = hist.maxpos();
|
|
96
|
+
int const dx = static_cast<int>(std::real(maxpos));
|
|
97
|
+
int const dy = static_cast<int>(std::imag(maxpos));
|
|
98
|
+
std::vector<double> pel = hist(dx, dy);
|
|
99
|
+
int const dz = std::distance(pel.begin(), std::find(pel.begin(), pel.end(), hist.max()));
|
|
100
|
+
baton->dominantRed = dx * 16 + 8;
|
|
101
|
+
baton->dominantGreen = dy * 16 + 8;
|
|
102
|
+
baton->dominantBlue = dz * 16 + 8;
|
|
89
103
|
} catch (vips::VError const &err) {
|
|
90
104
|
(baton->err).append(err.what());
|
|
91
105
|
}
|
|
@@ -133,6 +147,11 @@ class StatsWorker : public Napi::AsyncWorker {
|
|
|
133
147
|
info.Set("isOpaque", baton->isOpaque);
|
|
134
148
|
info.Set("entropy", baton->entropy);
|
|
135
149
|
info.Set("sharpness", baton->sharpness);
|
|
150
|
+
Napi::Object dominant = Napi::Object::New(env);
|
|
151
|
+
dominant.Set("r", baton->dominantRed);
|
|
152
|
+
dominant.Set("g", baton->dominantGreen);
|
|
153
|
+
dominant.Set("b", baton->dominantBlue);
|
|
154
|
+
info.Set("dominant", dominant);
|
|
136
155
|
Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
|
|
137
156
|
} else {
|
|
138
157
|
Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, baton->err).Value() });
|
package/src/stats.h
CHANGED
|
@@ -48,6 +48,9 @@ struct StatsBaton {
|
|
|
48
48
|
bool isOpaque;
|
|
49
49
|
double entropy;
|
|
50
50
|
double sharpness;
|
|
51
|
+
int dominantRed;
|
|
52
|
+
int dominantGreen;
|
|
53
|
+
int dominantBlue;
|
|
51
54
|
|
|
52
55
|
std::string err;
|
|
53
56
|
|
|
@@ -55,7 +58,10 @@ struct StatsBaton {
|
|
|
55
58
|
input(nullptr),
|
|
56
59
|
isOpaque(true),
|
|
57
60
|
entropy(0.0),
|
|
58
|
-
sharpness(0.0)
|
|
61
|
+
sharpness(0.0),
|
|
62
|
+
dominantRed(0),
|
|
63
|
+
dominantGreen(0),
|
|
64
|
+
dominantBlue(0)
|
|
59
65
|
{}
|
|
60
66
|
};
|
|
61
67
|
|