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.
@@ -93,7 +93,7 @@ negate( std::vector<double> vector )
93
93
  {
94
94
  std::vector<double> new_vector( vector.size() );
95
95
 
96
- for( unsigned int i = 0; i < vector.size(); i++ )
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( unsigned int i = 0; i < vector.size(); i++ )
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
- if( !(operation_name = vips_foreign_find_save_buffer( filename )) ) {
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
- // Wed May 12 11:30:00 AM CEST 2021
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
@@ -40,6 +40,7 @@ struct MetadataBaton {
40
40
  std::vector<int> delay;
41
41
  int pagePrimary;
42
42
  std::string compression;
43
+ std::string resolutionUnit;
43
44
  std::vector<std::pair<int, int>> levels;
44
45
  int subifds;
45
46
  std::vector<double> background;
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, int const hue) {
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
- { 0.0, 0.0, static_cast<double>(hue) }
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
- { 0.0, 0.0, static_cast<double>(hue) }
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 hue
101
+ * Modulate brightness, saturation, hue and lightness
102
102
  */
103
- VImage Modulate(VImage image, double const brightness, double const saturation, int const hue);
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_