sharp 0.29.1 → 0.30.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 +5 -5
- package/binding.gyp +2 -0
- package/install/libvips.js +39 -8
- package/lib/constructor.js +13 -4
- package/lib/input.js +21 -4
- package/lib/libvips.js +16 -2
- package/lib/operation.js +14 -1
- package/lib/output.js +158 -69
- package/lib/platform.js +1 -1
- package/lib/resize.js +19 -0
- package/lib/sharp.js +11 -3
- package/lib/utility.js +24 -5
- package/package.json +28 -13
- package/src/common.cc +125 -19
- package/src/common.h +39 -5
- package/src/libvips/cplusplus/VImage.cpp +34 -16
- package/src/libvips/cplusplus/vips-operators.cpp +29 -1
- package/src/metadata.cc +6 -0
- package/src/metadata.h +1 -0
- package/src/operations.cc +94 -0
- package/src/operations.h +12 -0
- package/src/pipeline.cc +291 -255
- package/src/pipeline.h +19 -19
- package/src/sharp.cc +16 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sharp",
|
|
3
|
-
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, AVIF and TIFF images",
|
|
4
|
-
"version": "0.
|
|
3
|
+
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
|
|
4
|
+
"version": "0.30.1",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://github.com/lovell/sharp",
|
|
7
7
|
"contributors": [
|
|
@@ -79,7 +79,9 @@
|
|
|
79
79
|
"Michael Nutt <michael@nutt.im>",
|
|
80
80
|
"Brad Parham <baparham@gmail.com>",
|
|
81
81
|
"Taneli Vatanen <taneli.vatanen@gmail.com>",
|
|
82
|
-
"Joris Dugué <zaruike10@gmail.com>"
|
|
82
|
+
"Joris Dugué <zaruike10@gmail.com>",
|
|
83
|
+
"Chris Banks <christopher.bradley.banks@gmail.com>",
|
|
84
|
+
"Ompal Singh <ompal.hitm09@gmail.com>"
|
|
83
85
|
],
|
|
84
86
|
"scripts": {
|
|
85
87
|
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild && node install/dll-copy)",
|
|
@@ -124,33 +126,46 @@
|
|
|
124
126
|
"vips"
|
|
125
127
|
],
|
|
126
128
|
"dependencies": {
|
|
127
|
-
"color": "^4.0
|
|
128
|
-
"detect-libc": "^
|
|
129
|
-
"node-addon-api": "^4.
|
|
130
|
-
"prebuild-install": "^
|
|
129
|
+
"color": "^4.2.0",
|
|
130
|
+
"detect-libc": "^2.0.0",
|
|
131
|
+
"node-addon-api": "^4.3.0",
|
|
132
|
+
"prebuild-install": "^7.0.1",
|
|
131
133
|
"semver": "^7.3.5",
|
|
132
|
-
"simple-get": "^
|
|
134
|
+
"simple-get": "^4.0.1",
|
|
133
135
|
"tar-fs": "^2.1.1",
|
|
134
136
|
"tunnel-agent": "^0.6.0"
|
|
135
137
|
},
|
|
136
138
|
"devDependencies": {
|
|
137
|
-
"async": "^3.2.
|
|
139
|
+
"async": "^3.2.3",
|
|
138
140
|
"cc": "^3.0.1",
|
|
139
141
|
"decompress-zip": "^0.3.3",
|
|
140
142
|
"documentation": "^13.2.5",
|
|
141
143
|
"exif-reader": "^1.0.3",
|
|
142
144
|
"icc": "^2.0.0",
|
|
143
145
|
"license-checker": "^25.0.1",
|
|
144
|
-
"mocha": "^9.
|
|
145
|
-
"mock-fs": "^5.
|
|
146
|
+
"mocha": "^9.2.0",
|
|
147
|
+
"mock-fs": "^5.1.2",
|
|
146
148
|
"nyc": "^15.1.0",
|
|
147
|
-
"prebuild": "^
|
|
149
|
+
"prebuild": "^11.0.3",
|
|
148
150
|
"rimraf": "^3.0.2",
|
|
149
151
|
"semistandard": "^16.0.1"
|
|
150
152
|
},
|
|
151
153
|
"license": "Apache-2.0",
|
|
152
154
|
"config": {
|
|
153
|
-
"libvips": "8.
|
|
155
|
+
"libvips": "8.12.2",
|
|
156
|
+
"integrity": {
|
|
157
|
+
"darwin-arm64v8": "sha512-p46s/bbJAjkOXzPISZt9HUpG9GWjwQkYnLLRLKzsBJHLtB3X6C6Y/zXI5Hd0DOojcFkks9a0kTN+uDQ/XJY19g==",
|
|
158
|
+
"darwin-x64": "sha512-6vOHVZnvXwe6EXRsy29jdkUzBE6ElNpXUwd+m8vV7qy32AnXu7B9YemHsZ44vWviIwPZeXF6Nhd9EFLM0wWohw==",
|
|
159
|
+
"linux-arm64v8": "sha512-XwZdS63yhqLtbFtx/0eoLF/Agf5qtTrI11FMnMRpuBJWd4jHB60RAH+uzYUgoChCmKIS+AeXYMLm4d8Ns2QX8w==",
|
|
160
|
+
"linux-armv6": "sha512-Rh0Q0kqwPG2MjXWOkPCuPEyiUKFgKJYWLgS835D4MrXgdKr8Tft/eVrc2iGIxt2re30VpDiZ1h0Rby1aCZt2zw==",
|
|
161
|
+
"linux-armv7": "sha512-heTS/MsmRvu4JljINxP+vDiS9ZZfuGhr3IStb5F7Gc0/QLRhllYAg4rcO8L1eTK9sIIzG5ARvI19+YUZe7WbzA==",
|
|
162
|
+
"linux-x64": "sha512-SSWAwBFi0hx8V/h/v82tTFGKWTFv9FiCK3Timz5OExuI+sX1Ngrd0PVQaWXOThGNdel/fcD3Bz9YjSt4feBR1g==",
|
|
163
|
+
"linuxmusl-arm64v8": "sha512-Rhks+5C7p7aO6AucLT1uvzo8ohlqcqCUPgZmN+LZjsPWob/Iix3MfiDYtv/+gTvdeEfXxbCU6/YuPBwHQ7/crA==",
|
|
164
|
+
"linuxmusl-x64": "sha512-IOyjSQqpWVntqOUpCHVWuQwACwmmjdi15H8Pc+Ma1JkhPogTfVsFQWyL7DuOTD3Yr23EuYGzovUX00duOtfy/g==",
|
|
165
|
+
"win32-arm64v8": "sha512-A+Qe8Ipewtvw9ldvF6nWed2J8kphzrUE04nFeKCtNx6pfGQ/MAlCKMjt/U8VgUKNjB01zJDUW9XE0+FhGZ/UpQ==",
|
|
166
|
+
"win32-ia32": "sha512-cMrAvwFdDeAVnLJt0IPMPRKaIFhyXYGTprsM0DND9VUHE8F7dJMR44tS5YkXsGh1QNDtjKT6YuxAVUglmiXtpA==",
|
|
167
|
+
"win32-x64": "sha512-vLFIfw6aW2zABa8jpgzWDhljnE6glktrddErVyazAIoHl6BFFe/Da+LK1DbXvIYHz7fyOoKhSfCJHCiJG1Vg6w=="
|
|
168
|
+
},
|
|
154
169
|
"runtime": "napi",
|
|
155
170
|
"target": 5
|
|
156
171
|
},
|
package/src/common.cc
CHANGED
|
@@ -132,6 +132,8 @@ namespace sharp {
|
|
|
132
132
|
descriptor->limitInputPixels = AttrAsUint32(input, "limitInputPixels");
|
|
133
133
|
// Allow switch from random to sequential access
|
|
134
134
|
descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
|
135
|
+
// Remove safety features and allow unlimited SVG/PNG input
|
|
136
|
+
descriptor->unlimited = AttrAsBool(input, "unlimited");
|
|
135
137
|
return descriptor;
|
|
136
138
|
}
|
|
137
139
|
|
|
@@ -328,7 +330,7 @@ namespace sharp {
|
|
|
328
330
|
vips::VOption *option = VImage::option()
|
|
329
331
|
->set("access", descriptor->access)
|
|
330
332
|
->set("fail", descriptor->failOnError);
|
|
331
|
-
if (imageType == ImageType::SVG) {
|
|
333
|
+
if (descriptor->unlimited && (imageType == ImageType::SVG || imageType == ImageType::PNG)) {
|
|
332
334
|
option->set("unlimited", TRUE);
|
|
333
335
|
}
|
|
334
336
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
|
@@ -403,7 +405,7 @@ namespace sharp {
|
|
|
403
405
|
vips::VOption *option = VImage::option()
|
|
404
406
|
->set("access", descriptor->access)
|
|
405
407
|
->set("fail", descriptor->failOnError);
|
|
406
|
-
if (imageType == ImageType::SVG) {
|
|
408
|
+
if (descriptor->unlimited && (imageType == ImageType::SVG || imageType == ImageType::PNG)) {
|
|
407
409
|
option->set("unlimited", TRUE);
|
|
408
410
|
}
|
|
409
411
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
|
@@ -488,30 +490,24 @@ namespace sharp {
|
|
|
488
490
|
|
|
489
491
|
/*
|
|
490
492
|
Set animation properties if necessary.
|
|
491
|
-
Non-provided properties will be loaded from image.
|
|
492
493
|
*/
|
|
493
|
-
VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop) {
|
|
494
|
-
bool hasDelay = delay.
|
|
494
|
+
VImage SetAnimationProperties(VImage image, int nPages, int pageHeight, std::vector<int> delay, int loop) {
|
|
495
|
+
bool hasDelay = !delay.empty();
|
|
495
496
|
|
|
496
|
-
if
|
|
497
|
-
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
if (!hasDelay && image.get_typeof("delay") == VIPS_TYPE_ARRAY_INT) {
|
|
501
|
-
delay = image.get_array_int("delay");
|
|
502
|
-
hasDelay = true;
|
|
503
|
-
}
|
|
497
|
+
// Avoid a copy if none of the animation properties are needed.
|
|
498
|
+
if (nPages == 1 && !hasDelay && loop == -1) return image;
|
|
504
499
|
|
|
505
|
-
if (
|
|
506
|
-
|
|
500
|
+
if (delay.size() == 1) {
|
|
501
|
+
// We have just one delay, repeat that value for all frames.
|
|
502
|
+
delay.insert(delay.end(), nPages - 1, delay[0]);
|
|
507
503
|
}
|
|
508
504
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
// It is necessary to create the copy as otherwise, pageHeight will be ignored!
|
|
505
|
+
// Attaching metadata, need to copy the image.
|
|
512
506
|
VImage copy = image.copy();
|
|
513
507
|
|
|
514
|
-
|
|
508
|
+
// Only set page-height if we have more than one page, or this could
|
|
509
|
+
// accidentally turn into an animated image later.
|
|
510
|
+
if (nPages > 1) copy.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
|
515
511
|
if (hasDelay) copy.set("delay", delay);
|
|
516
512
|
if (loop != -1) copy.set("loop", loop);
|
|
517
513
|
|
|
@@ -554,6 +550,14 @@ namespace sharp {
|
|
|
554
550
|
return copy;
|
|
555
551
|
}
|
|
556
552
|
|
|
553
|
+
/*
|
|
554
|
+
Multi-page images can have a page height. Fetch it, and sanity check it.
|
|
555
|
+
If page-height is not set, it defaults to the image height
|
|
556
|
+
*/
|
|
557
|
+
int GetPageHeight(VImage image) {
|
|
558
|
+
return vips_image_get_page_height(image.get_image());
|
|
559
|
+
}
|
|
560
|
+
|
|
557
561
|
/*
|
|
558
562
|
Check the proposed format supports the current dimensions.
|
|
559
563
|
*/
|
|
@@ -610,6 +614,33 @@ namespace sharp {
|
|
|
610
614
|
return warning;
|
|
611
615
|
}
|
|
612
616
|
|
|
617
|
+
/*
|
|
618
|
+
Attach an event listener for progress updates, used to detect timeout
|
|
619
|
+
*/
|
|
620
|
+
void SetTimeout(VImage image, int const seconds) {
|
|
621
|
+
if (seconds > 0) {
|
|
622
|
+
VipsImage *im = image.get_image();
|
|
623
|
+
if (im->progress_signal == NULL) {
|
|
624
|
+
int *timeout = VIPS_NEW(im, int);
|
|
625
|
+
*timeout = seconds;
|
|
626
|
+
g_signal_connect(im, "eval", G_CALLBACK(VipsProgressCallBack), timeout);
|
|
627
|
+
vips_image_set_progress(im, TRUE);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/*
|
|
633
|
+
Event listener for progress updates, used to detect timeout
|
|
634
|
+
*/
|
|
635
|
+
void VipsProgressCallBack(VipsImage *im, VipsProgress *progress, int *timeout) {
|
|
636
|
+
// printf("VipsProgressCallBack progress=%d run=%d timeout=%d\n", progress->percent, progress->run, *timeout);
|
|
637
|
+
if (*timeout > 0 && progress->run >= *timeout) {
|
|
638
|
+
vips_image_set_kill(im, TRUE);
|
|
639
|
+
vips_error("timeout", "%d%% complete", progress->percent);
|
|
640
|
+
*timeout = 0;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
613
644
|
/*
|
|
614
645
|
Calculate the (left, top) coordinates of the output image
|
|
615
646
|
within the input image, applying the given gravity during an embed.
|
|
@@ -853,4 +884,79 @@ namespace sharp {
|
|
|
853
884
|
return image;
|
|
854
885
|
}
|
|
855
886
|
|
|
887
|
+
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
|
|
888
|
+
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction) {
|
|
889
|
+
if (swap) {
|
|
890
|
+
// Swap input width and height when requested.
|
|
891
|
+
std::swap(width, height);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
double hshrink = 1.0;
|
|
895
|
+
double vshrink = 1.0;
|
|
896
|
+
|
|
897
|
+
if (targetWidth > 0 && targetHeight > 0) {
|
|
898
|
+
// Fixed width and height
|
|
899
|
+
hshrink = static_cast<double>(width) / targetWidth;
|
|
900
|
+
vshrink = static_cast<double>(height) / targetHeight;
|
|
901
|
+
|
|
902
|
+
switch (canvas) {
|
|
903
|
+
case Canvas::CROP:
|
|
904
|
+
case Canvas::MIN:
|
|
905
|
+
if (hshrink < vshrink) {
|
|
906
|
+
vshrink = hshrink;
|
|
907
|
+
} else {
|
|
908
|
+
hshrink = vshrink;
|
|
909
|
+
}
|
|
910
|
+
break;
|
|
911
|
+
case Canvas::EMBED:
|
|
912
|
+
case Canvas::MAX:
|
|
913
|
+
if (hshrink > vshrink) {
|
|
914
|
+
vshrink = hshrink;
|
|
915
|
+
} else {
|
|
916
|
+
hshrink = vshrink;
|
|
917
|
+
}
|
|
918
|
+
break;
|
|
919
|
+
case Canvas::IGNORE_ASPECT:
|
|
920
|
+
if (swap) {
|
|
921
|
+
std::swap(hshrink, vshrink);
|
|
922
|
+
}
|
|
923
|
+
break;
|
|
924
|
+
}
|
|
925
|
+
} else if (targetWidth > 0) {
|
|
926
|
+
// Fixed width
|
|
927
|
+
hshrink = static_cast<double>(width) / targetWidth;
|
|
928
|
+
|
|
929
|
+
if (canvas != Canvas::IGNORE_ASPECT) {
|
|
930
|
+
// Auto height
|
|
931
|
+
vshrink = hshrink;
|
|
932
|
+
}
|
|
933
|
+
} else if (targetHeight > 0) {
|
|
934
|
+
// Fixed height
|
|
935
|
+
vshrink = static_cast<double>(height) / targetHeight;
|
|
936
|
+
|
|
937
|
+
if (canvas != Canvas::IGNORE_ASPECT) {
|
|
938
|
+
// Auto width
|
|
939
|
+
hshrink = vshrink;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// We should not reduce or enlarge the output image, if
|
|
944
|
+
// withoutReduction or withoutEnlargement is specified.
|
|
945
|
+
if (withoutReduction) {
|
|
946
|
+
// Equivalent of VIPS_SIZE_UP
|
|
947
|
+
hshrink = std::min(1.0, hshrink);
|
|
948
|
+
vshrink = std::min(1.0, vshrink);
|
|
949
|
+
} else if (withoutEnlargement) {
|
|
950
|
+
// Equivalent of VIPS_SIZE_DOWN
|
|
951
|
+
hshrink = std::max(1.0, hshrink);
|
|
952
|
+
vshrink = std::max(1.0, vshrink);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// We don't want to shrink so much that we send an axis to 0
|
|
956
|
+
hshrink = std::min(hshrink, static_cast<double>(width));
|
|
957
|
+
vshrink = std::min(vshrink, static_cast<double>(height));
|
|
958
|
+
|
|
959
|
+
return std::make_pair(hshrink, vshrink);
|
|
960
|
+
}
|
|
961
|
+
|
|
856
962
|
} // namespace sharp
|
package/src/common.h
CHANGED
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
// Verify platform and compiler compatibility
|
|
26
26
|
|
|
27
27
|
#if (VIPS_MAJOR_VERSION < 8) || \
|
|
28
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION <
|
|
29
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION ==
|
|
30
|
-
#error "libvips version 8.
|
|
28
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 12) || \
|
|
29
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 12 && VIPS_MICRO_VERSION < 2)
|
|
30
|
+
#error "libvips version 8.12.2+ is required - please see https://sharp.pixelplumbing.com/install"
|
|
31
31
|
#endif
|
|
32
32
|
|
|
33
33
|
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
|
@@ -50,6 +50,7 @@ namespace sharp {
|
|
|
50
50
|
char *buffer;
|
|
51
51
|
bool failOnError;
|
|
52
52
|
int limitInputPixels;
|
|
53
|
+
bool unlimited;
|
|
53
54
|
VipsAccess access;
|
|
54
55
|
size_t bufferLength;
|
|
55
56
|
bool isBuffer;
|
|
@@ -75,6 +76,7 @@ namespace sharp {
|
|
|
75
76
|
buffer(nullptr),
|
|
76
77
|
failOnError(TRUE),
|
|
77
78
|
limitInputPixels(0x3FFF * 0x3FFF),
|
|
79
|
+
unlimited(FALSE),
|
|
78
80
|
access(VIPS_ACCESS_RANDOM),
|
|
79
81
|
bufferLength(0),
|
|
80
82
|
isBuffer(FALSE),
|
|
@@ -133,6 +135,14 @@ namespace sharp {
|
|
|
133
135
|
MISSING
|
|
134
136
|
};
|
|
135
137
|
|
|
138
|
+
enum class Canvas {
|
|
139
|
+
CROP,
|
|
140
|
+
EMBED,
|
|
141
|
+
MAX,
|
|
142
|
+
MIN,
|
|
143
|
+
IGNORE_ASPECT
|
|
144
|
+
};
|
|
145
|
+
|
|
136
146
|
// How many tasks are in the queue?
|
|
137
147
|
extern volatile int counterQueue;
|
|
138
148
|
|
|
@@ -206,9 +216,8 @@ namespace sharp {
|
|
|
206
216
|
|
|
207
217
|
/*
|
|
208
218
|
Set animation properties if necessary.
|
|
209
|
-
Non-provided properties will be loaded from image.
|
|
210
219
|
*/
|
|
211
|
-
VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop);
|
|
220
|
+
VImage SetAnimationProperties(VImage image, int nPages, int pageHeight, std::vector<int> delay, int loop);
|
|
212
221
|
|
|
213
222
|
/*
|
|
214
223
|
Remove animation properties from image.
|
|
@@ -230,6 +239,12 @@ namespace sharp {
|
|
|
230
239
|
*/
|
|
231
240
|
VImage SetDensity(VImage image, const double density);
|
|
232
241
|
|
|
242
|
+
/*
|
|
243
|
+
Multi-page images can have a page height. Fetch it, and sanity check it.
|
|
244
|
+
If page-height is not set, it defaults to the image height
|
|
245
|
+
*/
|
|
246
|
+
int GetPageHeight(VImage image);
|
|
247
|
+
|
|
233
248
|
/*
|
|
234
249
|
Check the proposed format supports the current dimensions.
|
|
235
250
|
*/
|
|
@@ -250,6 +265,16 @@ namespace sharp {
|
|
|
250
265
|
*/
|
|
251
266
|
std::string VipsWarningPop();
|
|
252
267
|
|
|
268
|
+
/*
|
|
269
|
+
Attach an event listener for progress updates, used to detect timeout
|
|
270
|
+
*/
|
|
271
|
+
void SetTimeout(VImage image, int const timeoutSeconds);
|
|
272
|
+
|
|
273
|
+
/*
|
|
274
|
+
Event listener for progress updates, used to detect timeout
|
|
275
|
+
*/
|
|
276
|
+
void VipsProgressCallBack(VipsImage *image, VipsProgress *progress, int *timeoutSeconds);
|
|
277
|
+
|
|
253
278
|
/*
|
|
254
279
|
Calculate the (left, top) coordinates of the output image
|
|
255
280
|
within the input image, applying the given gravity during an embed.
|
|
@@ -313,6 +338,15 @@ namespace sharp {
|
|
|
313
338
|
*/
|
|
314
339
|
VImage EnsureAlpha(VImage image, double const value);
|
|
315
340
|
|
|
341
|
+
/*
|
|
342
|
+
Calculate the shrink factor, taking into account auto-rotate, the canvas
|
|
343
|
+
mode, and so on. The hshrink/vshrink are the amount to shrink the input
|
|
344
|
+
image axes by in order for the output axes (ie. after rotation) to match
|
|
345
|
+
the required thumbnail width/height and canvas mode.
|
|
346
|
+
*/
|
|
347
|
+
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
|
|
348
|
+
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction);
|
|
349
|
+
|
|
316
350
|
} // namespace sharp
|
|
317
351
|
|
|
318
352
|
#endif // SRC_COMMON_H_
|
|
@@ -93,7 +93,7 @@ negate( std::vector<double> vector )
|
|
|
93
93
|
{
|
|
94
94
|
std::vector<double> new_vector( vector.size() );
|
|
95
95
|
|
|
96
|
-
for(
|
|
96
|
+
for( std::vector<double>::size_type i = 0; i < vector.size(); i++ )
|
|
97
97
|
new_vector[i] = vector[i] * -1;
|
|
98
98
|
|
|
99
99
|
return( new_vector );
|
|
@@ -104,7 +104,7 @@ invert( std::vector<double> vector )
|
|
|
104
104
|
{
|
|
105
105
|
std::vector<double> new_vector( vector.size() );
|
|
106
106
|
|
|
107
|
-
for(
|
|
107
|
+
for( std::vector<double>::size_type i = 0; i < vector.size(); i++ )
|
|
108
108
|
new_vector[i] = 1.0 / vector[i];
|
|
109
109
|
|
|
110
110
|
return( new_vector );
|
|
@@ -210,7 +210,6 @@ VOption::set( const char *name, std::vector<int> value )
|
|
|
210
210
|
Pair *pair = new Pair( name );
|
|
211
211
|
|
|
212
212
|
int *array;
|
|
213
|
-
unsigned int i;
|
|
214
213
|
|
|
215
214
|
pair->input = true;
|
|
216
215
|
|
|
@@ -219,7 +218,7 @@ VOption::set( const char *name, std::vector<int> value )
|
|
|
219
218
|
static_cast< int >( value.size() ) );
|
|
220
219
|
array = vips_value_get_array_int( &pair->value, NULL );
|
|
221
220
|
|
|
222
|
-
for( i = 0; i < value.size(); i++ )
|
|
221
|
+
for( std::vector<double>::size_type i = 0; i < value.size(); i++ )
|
|
223
222
|
array[i] = value[i];
|
|
224
223
|
|
|
225
224
|
options.push_back( pair );
|
|
@@ -234,7 +233,6 @@ VOption::set( const char *name, std::vector<double> value )
|
|
|
234
233
|
Pair *pair = new Pair( name );
|
|
235
234
|
|
|
236
235
|
double *array;
|
|
237
|
-
unsigned int i;
|
|
238
236
|
|
|
239
237
|
pair->input = true;
|
|
240
238
|
|
|
@@ -243,7 +241,7 @@ VOption::set( const char *name, std::vector<double> value )
|
|
|
243
241
|
static_cast< int >( value.size() ) );
|
|
244
242
|
array = vips_value_get_array_double( &pair->value, NULL );
|
|
245
243
|
|
|
246
|
-
for( i = 0; i < value.size(); i++ )
|
|
244
|
+
for( std::vector<double>::size_type i = 0; i < value.size(); i++ )
|
|
247
245
|
array[i] = value[i];
|
|
248
246
|
|
|
249
247
|
options.push_back( pair );
|
|
@@ -258,7 +256,6 @@ VOption::set( const char *name, std::vector<VImage> value )
|
|
|
258
256
|
Pair *pair = new Pair( name );
|
|
259
257
|
|
|
260
258
|
VipsImage **array;
|
|
261
|
-
unsigned int i;
|
|
262
259
|
|
|
263
260
|
pair->input = true;
|
|
264
261
|
|
|
@@ -267,7 +264,7 @@ VOption::set( const char *name, std::vector<VImage> value )
|
|
|
267
264
|
static_cast< int >( value.size() ) );
|
|
268
265
|
array = vips_value_get_array_image( &pair->value, NULL );
|
|
269
266
|
|
|
270
|
-
for( i = 0; i < value.size(); i++ ) {
|
|
267
|
+
for( std::vector<double>::size_type i = 0; i < value.size(); i++ ) {
|
|
271
268
|
VipsImage *vips_image = value[i].get_image();
|
|
272
269
|
|
|
273
270
|
array[i] = vips_image;
|
|
@@ -488,10 +485,9 @@ VOption::get_operation( VipsOperation *operation )
|
|
|
488
485
|
double *array =
|
|
489
486
|
vips_value_get_array_double( value,
|
|
490
487
|
&length );
|
|
491
|
-
int j;
|
|
492
488
|
|
|
493
489
|
((*i)->vvector)->resize( length );
|
|
494
|
-
for( j = 0; j < length; j++ )
|
|
490
|
+
for( int j = 0; j < length; j++ )
|
|
495
491
|
(*((*i)->vvector))[j] = array[j];
|
|
496
492
|
}
|
|
497
493
|
else if( type == VIPS_TYPE_BLOB ) {
|
|
@@ -718,17 +714,38 @@ VImage::write_to_buffer( const char *suffix, void **buf, size_t *size,
|
|
|
718
714
|
const char *operation_name;
|
|
719
715
|
VipsBlob *blob;
|
|
720
716
|
|
|
717
|
+
/* Save with the new target API if we can. Fall back to the older
|
|
718
|
+
* mechanism in case the saver we need has not been converted yet.
|
|
719
|
+
*
|
|
720
|
+
* We need to hide any errors from this first phase.
|
|
721
|
+
*/
|
|
721
722
|
vips__filename_split8( suffix, filename, option_string );
|
|
722
|
-
|
|
723
|
+
|
|
724
|
+
vips_error_freeze();
|
|
725
|
+
operation_name = vips_foreign_find_save_target( filename );
|
|
726
|
+
vips_error_thaw();
|
|
727
|
+
|
|
728
|
+
if( operation_name ) {
|
|
729
|
+
VTarget target = VTarget::new_to_memory();
|
|
730
|
+
|
|
731
|
+
call_option_string( operation_name, option_string,
|
|
732
|
+
(options ? options : VImage::option())->
|
|
733
|
+
set( "in", *this )->
|
|
734
|
+
set( "target", target ) );
|
|
735
|
+
|
|
736
|
+
g_object_get( target.get_target(), "blob", &blob, NULL );
|
|
737
|
+
}
|
|
738
|
+
else if( (operation_name = vips_foreign_find_save_buffer( filename )) ) {
|
|
739
|
+
call_option_string( operation_name, option_string,
|
|
740
|
+
(options ? options : VImage::option())->
|
|
741
|
+
set( "in", *this )->
|
|
742
|
+
set( "buffer", &blob ) );
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
723
745
|
delete options;
|
|
724
746
|
throw VError();
|
|
725
747
|
}
|
|
726
748
|
|
|
727
|
-
call_option_string( operation_name, option_string,
|
|
728
|
-
(options ? options : VImage::option())->
|
|
729
|
-
set( "in", *this )->
|
|
730
|
-
set( "buffer", &blob ) );
|
|
731
|
-
|
|
732
749
|
if( blob ) {
|
|
733
750
|
if( buf ) {
|
|
734
751
|
*buf = VIPS_AREA( blob )->data;
|
|
@@ -767,6 +784,7 @@ std::vector<VImage>
|
|
|
767
784
|
VImage::bandsplit( VOption *options ) const
|
|
768
785
|
{
|
|
769
786
|
std::vector<VImage> b;
|
|
787
|
+
b.reserve(bands());
|
|
770
788
|
|
|
771
789
|
for( int i = 0; i < bands(); i++ )
|
|
772
790
|
b.push_back( extract_band( i ) );
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// bodies for vips operations
|
|
2
|
-
//
|
|
2
|
+
// Mon Nov 1 03:31:09 PM CET 2021
|
|
3
3
|
// this file is generated automatically, do not edit!
|
|
4
4
|
|
|
5
5
|
VImage VImage::CMC2LCh( VOption *options ) const
|
|
@@ -1262,6 +1262,34 @@ VImage VImage::gifload_source( VSource source, VOption *options )
|
|
|
1262
1262
|
return( out );
|
|
1263
1263
|
}
|
|
1264
1264
|
|
|
1265
|
+
void VImage::gifsave( const char *filename, VOption *options ) const
|
|
1266
|
+
{
|
|
1267
|
+
call( "gifsave",
|
|
1268
|
+
(options ? options : VImage::option())->
|
|
1269
|
+
set( "in", *this )->
|
|
1270
|
+
set( "filename", filename ) );
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
VipsBlob *VImage::gifsave_buffer( VOption *options ) const
|
|
1274
|
+
{
|
|
1275
|
+
VipsBlob *buffer;
|
|
1276
|
+
|
|
1277
|
+
call( "gifsave_buffer",
|
|
1278
|
+
(options ? options : VImage::option())->
|
|
1279
|
+
set( "in", *this )->
|
|
1280
|
+
set( "buffer", &buffer ) );
|
|
1281
|
+
|
|
1282
|
+
return( buffer );
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
void VImage::gifsave_target( VTarget target, VOption *options ) const
|
|
1286
|
+
{
|
|
1287
|
+
call( "gifsave_target",
|
|
1288
|
+
(options ? options : VImage::option())->
|
|
1289
|
+
set( "in", *this )->
|
|
1290
|
+
set( "target", target ) );
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1265
1293
|
VImage VImage::globalbalance( VOption *options ) const
|
|
1266
1294
|
{
|
|
1267
1295
|
VImage out;
|
package/src/metadata.cc
CHANGED
|
@@ -77,6 +77,9 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
77
77
|
if (image.get_typeof("heif-compression") == VIPS_TYPE_REF_STRING) {
|
|
78
78
|
baton->compression = image.get_string("heif-compression");
|
|
79
79
|
}
|
|
80
|
+
if (image.get_typeof(VIPS_META_RESOLUTION_UNIT) == VIPS_TYPE_REF_STRING) {
|
|
81
|
+
baton->resolutionUnit = image.get_string(VIPS_META_RESOLUTION_UNIT);
|
|
82
|
+
}
|
|
80
83
|
if (image.get_typeof("openslide.level-count") == VIPS_TYPE_REF_STRING) {
|
|
81
84
|
int const levels = std::stoi(image.get_string("openslide.level-count"));
|
|
82
85
|
for (int l = 0; l < levels; l++) {
|
|
@@ -198,6 +201,9 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
198
201
|
if (!baton->compression.empty()) {
|
|
199
202
|
info.Set("compression", baton->compression);
|
|
200
203
|
}
|
|
204
|
+
if (!baton->resolutionUnit.empty()) {
|
|
205
|
+
info.Set("resolutionUnit", baton->resolutionUnit == "in" ? "inch" : baton->resolutionUnit);
|
|
206
|
+
}
|
|
201
207
|
if (!baton->levels.empty()) {
|
|
202
208
|
int i = 0;
|
|
203
209
|
Napi::Array levels = Napi::Array::New(env, static_cast<size_t>(baton->levels.size()));
|
package/src/metadata.h
CHANGED
package/src/operations.cc
CHANGED
|
@@ -308,4 +308,98 @@ namespace sharp {
|
|
|
308
308
|
return image;
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
/*
|
|
312
|
+
* Split and crop each frame, reassemble, and update pageHeight.
|
|
313
|
+
*/
|
|
314
|
+
VImage CropMultiPage(VImage image, int left, int top, int width, int height,
|
|
315
|
+
int nPages, int *pageHeight) {
|
|
316
|
+
if (top == 0 && height == *pageHeight) {
|
|
317
|
+
// Fast path; no need to adjust the height of the multi-page image
|
|
318
|
+
return image.extract_area(left, 0, width, image.height());
|
|
319
|
+
} else {
|
|
320
|
+
std::vector<VImage> pages;
|
|
321
|
+
pages.reserve(nPages);
|
|
322
|
+
|
|
323
|
+
// Split the image into cropped frames
|
|
324
|
+
for (int i = 0; i < nPages; i++) {
|
|
325
|
+
pages.push_back(
|
|
326
|
+
image.extract_area(left, *pageHeight * i + top, width, height));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Reassemble the frames into a tall, thin image
|
|
330
|
+
VImage assembled = VImage::arrayjoin(pages,
|
|
331
|
+
VImage::option()->set("across", 1));
|
|
332
|
+
|
|
333
|
+
// Update the page height
|
|
334
|
+
*pageHeight = height;
|
|
335
|
+
|
|
336
|
+
return assembled;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/*
|
|
341
|
+
* Split into frames, embed each frame, reassemble, and update pageHeight.
|
|
342
|
+
*/
|
|
343
|
+
VImage EmbedMultiPage(VImage image, int left, int top, int width, int height,
|
|
344
|
+
std::vector<double> background, int nPages, int *pageHeight) {
|
|
345
|
+
if (top == 0 && height == *pageHeight) {
|
|
346
|
+
// Fast path; no need to adjust the height of the multi-page image
|
|
347
|
+
return image.embed(left, 0, width, image.height(), VImage::option()
|
|
348
|
+
->set("extend", VIPS_EXTEND_BACKGROUND)
|
|
349
|
+
->set("background", background));
|
|
350
|
+
} else if (left == 0 && width == image.width()) {
|
|
351
|
+
// Fast path; no need to adjust the width of the multi-page image
|
|
352
|
+
std::vector<VImage> pages;
|
|
353
|
+
pages.reserve(nPages);
|
|
354
|
+
|
|
355
|
+
// Rearrange the tall image into a vertical grid
|
|
356
|
+
image = image.grid(*pageHeight, nPages, 1);
|
|
357
|
+
|
|
358
|
+
// Do the embed on the wide image
|
|
359
|
+
image = image.embed(0, top, image.width(), height, VImage::option()
|
|
360
|
+
->set("extend", VIPS_EXTEND_BACKGROUND)
|
|
361
|
+
->set("background", background));
|
|
362
|
+
|
|
363
|
+
// Split the wide image into frames
|
|
364
|
+
for (int i = 0; i < nPages; i++) {
|
|
365
|
+
pages.push_back(
|
|
366
|
+
image.extract_area(width * i, 0, width, height));
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Reassemble the frames into a tall, thin image
|
|
370
|
+
VImage assembled = VImage::arrayjoin(pages,
|
|
371
|
+
VImage::option()->set("across", 1));
|
|
372
|
+
|
|
373
|
+
// Update the page height
|
|
374
|
+
*pageHeight = height;
|
|
375
|
+
|
|
376
|
+
return assembled;
|
|
377
|
+
} else {
|
|
378
|
+
std::vector<VImage> pages;
|
|
379
|
+
pages.reserve(nPages);
|
|
380
|
+
|
|
381
|
+
// Split the image into frames
|
|
382
|
+
for (int i = 0; i < nPages; i++) {
|
|
383
|
+
pages.push_back(
|
|
384
|
+
image.extract_area(0, *pageHeight * i, image.width(), *pageHeight));
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Embed each frame in the target size
|
|
388
|
+
for (int i = 0; i < nPages; i++) {
|
|
389
|
+
pages[i] = pages[i].embed(left, top, width, height, VImage::option()
|
|
390
|
+
->set("extend", VIPS_EXTEND_BACKGROUND)
|
|
391
|
+
->set("background", background));
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Reassemble the frames into a tall, thin image
|
|
395
|
+
VImage assembled = VImage::arrayjoin(pages,
|
|
396
|
+
VImage::option()->set("across", 1));
|
|
397
|
+
|
|
398
|
+
// Update the page height
|
|
399
|
+
*pageHeight = height;
|
|
400
|
+
|
|
401
|
+
return assembled;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
311
405
|
} // namespace sharp
|