sharp 0.29.0 → 0.30.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 +2 -2
- package/binding.gyp +2 -0
- package/install/libvips.js +39 -8
- package/lib/constructor.js +20 -5
- package/lib/input.js +21 -4
- package/lib/libvips.js +16 -2
- package/lib/operation.js +31 -3
- package/lib/output.js +250 -73
- package/lib/platform.js +1 -1
- package/lib/resize.js +19 -0
- package/lib/sharp.js +11 -3
- package/lib/utility.js +22 -3
- package/package.json +30 -13
- package/src/common.cc +156 -29
- package/src/common.h +49 -7
- 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 +98 -3
- package/src/operations.h +15 -2
- package/src/pipeline.cc +357 -268
- package/src/pipeline.h +31 -19
- package/src/sharp.cc +16 -0
- package/src/utilities.cc +1 -1
|
@@ -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
|
@@ -182,7 +182,8 @@ namespace sharp {
|
|
|
182
182
|
0.0, 0.0, 0.0, 1.0));
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
VImage Modulate(VImage image, double const brightness, double const saturation,
|
|
185
|
+
VImage Modulate(VImage image, double const brightness, double const saturation,
|
|
186
|
+
int const hue, double const lightness) {
|
|
186
187
|
if (HasAlpha(image)) {
|
|
187
188
|
// Separate alpha channel
|
|
188
189
|
VImage alpha = image[image.bands() - 1];
|
|
@@ -190,7 +191,7 @@ namespace sharp {
|
|
|
190
191
|
.colourspace(VIPS_INTERPRETATION_LCH)
|
|
191
192
|
.linear(
|
|
192
193
|
{ brightness, saturation, 1},
|
|
193
|
-
{
|
|
194
|
+
{ lightness, 0.0, static_cast<double>(hue) }
|
|
194
195
|
)
|
|
195
196
|
.colourspace(VIPS_INTERPRETATION_sRGB)
|
|
196
197
|
.bandjoin(alpha);
|
|
@@ -199,7 +200,7 @@ namespace sharp {
|
|
|
199
200
|
.colourspace(VIPS_INTERPRETATION_LCH)
|
|
200
201
|
.linear(
|
|
201
202
|
{ brightness, saturation, 1 },
|
|
202
|
-
{
|
|
203
|
+
{ lightness, 0.0, static_cast<double>(hue) }
|
|
203
204
|
)
|
|
204
205
|
.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
205
206
|
}
|
|
@@ -307,4 +308,98 @@ namespace sharp {
|
|
|
307
308
|
return image;
|
|
308
309
|
}
|
|
309
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
|
+
|
|
310
405
|
} // namespace sharp
|
package/src/operations.h
CHANGED
|
@@ -98,15 +98,28 @@ namespace sharp {
|
|
|
98
98
|
VImage Recomb(VImage image, std::unique_ptr<double[]> const &matrix);
|
|
99
99
|
|
|
100
100
|
/*
|
|
101
|
-
* Modulate brightness, saturation and
|
|
101
|
+
* Modulate brightness, saturation, hue and lightness
|
|
102
102
|
*/
|
|
103
|
-
VImage Modulate(VImage image, double const brightness, double const saturation,
|
|
103
|
+
VImage Modulate(VImage image, double const brightness, double const saturation,
|
|
104
|
+
int const hue, double const lightness);
|
|
104
105
|
|
|
105
106
|
/*
|
|
106
107
|
* Ensure the image is in a given colourspace
|
|
107
108
|
*/
|
|
108
109
|
VImage EnsureColourspace(VImage image, VipsInterpretation colourspace);
|
|
109
110
|
|
|
111
|
+
/*
|
|
112
|
+
* Split and crop each frame, reassemble, and update pageHeight.
|
|
113
|
+
*/
|
|
114
|
+
VImage CropMultiPage(VImage image, int left, int top, int width, int height,
|
|
115
|
+
int nPages, int *pageHeight);
|
|
116
|
+
|
|
117
|
+
/*
|
|
118
|
+
* Split into frames, embed each frame, reassemble, and update pageHeight.
|
|
119
|
+
*/
|
|
120
|
+
VImage EmbedMultiPage(VImage image, int left, int top, int width, int height,
|
|
121
|
+
std::vector<double> background, int nPages, int *pageHeight);
|
|
122
|
+
|
|
110
123
|
} // namespace sharp
|
|
111
124
|
|
|
112
125
|
#endif // SRC_OPERATIONS_H_
|