rmagick 7.0.5 → 7.1.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.
@@ -11,8 +11,16 @@
11
11
 
12
12
  #include "rmagick.h"
13
13
 
14
+ struct ImagesFromImageList_Args
15
+ {
16
+ VALUE imagelist;
17
+ VALUE *clones;
18
+ Image *images;
19
+ };
20
+
14
21
  static Image *clone_imagelist(Image *);
15
- static Image *images_from_imagelist(VALUE);
22
+ static Image *images_from_imagelist(VALUE, VALUE *);
23
+ static VALUE images_from_imagelist_protected(VALUE);
16
24
  static long imagelist_length(VALUE);
17
25
  static long check_imagelist_length(VALUE);
18
26
  static void imagelist_push(VALUE, VALUE);
@@ -93,7 +101,8 @@ ImageList_animate(int argc, VALUE *argv, VALUE self)
93
101
  info_obj = rm_info_new();
94
102
 
95
103
  // Convert the images array to an images sequence.
96
- images = images_from_imagelist(self);
104
+ VALUE clones;
105
+ images = images_from_imagelist(self, &clones);
97
106
 
98
107
  if (argc == 1)
99
108
  {
@@ -120,6 +129,7 @@ ImageList_animate(int argc, VALUE *argv, VALUE self)
120
129
  rm_check_image_exception(images, RetainOnError);
121
130
  #endif
122
131
 
132
+ RB_GC_GUARD(clones);
123
133
  RB_GC_GUARD(info_obj);
124
134
 
125
135
  return self;
@@ -140,7 +150,8 @@ ImageList_append(VALUE self, VALUE stack_arg)
140
150
  ExceptionInfo *exception;
141
151
 
142
152
  // Convert the image array to an image sequence.
143
- images = images_from_imagelist(self);
153
+ VALUE clones;
154
+ images = images_from_imagelist(self, &clones);
144
155
 
145
156
  // If stack == true, stack rectangular images top-to-bottom,
146
157
  // otherwise left-to-right.
@@ -150,6 +161,7 @@ ImageList_append(VALUE self, VALUE stack_arg)
150
161
  GVL_STRUCT_TYPE(AppendImages) args = { images, stack, exception };
151
162
  new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(AppendImages), &args);
152
163
  rm_split(images);
164
+ RB_GC_GUARD(clones);
153
165
  rm_check_exception(exception, new_image, DestroyOnError);
154
166
  DestroyExceptionInfo(exception);
155
167
 
@@ -169,12 +181,14 @@ ImageList_average(VALUE self)
169
181
  ExceptionInfo *exception;
170
182
 
171
183
  // Convert the images array to an images sequence.
172
- images = images_from_imagelist(self);
184
+ VALUE clones;
185
+ images = images_from_imagelist(self, &clones);
173
186
 
174
187
  exception = AcquireExceptionInfo();
175
188
  GVL_STRUCT_TYPE(EvaluateImages) args = { images, MeanEvaluateOperator, exception };
176
189
  new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(EvaluateImages), &args);
177
190
  rm_split(images);
191
+ RB_GC_GUARD(clones);
178
192
  rm_check_exception(exception, new_image, DestroyOnError);
179
193
  DestroyExceptionInfo(exception);
180
194
 
@@ -197,12 +211,14 @@ ImageList_coalesce(VALUE self)
197
211
  ExceptionInfo *exception;
198
212
 
199
213
  // Convert the image array to an image sequence.
200
- images = images_from_imagelist(self);
214
+ VALUE clones;
215
+ images = images_from_imagelist(self, &clones);
201
216
 
202
217
  exception = AcquireExceptionInfo();
203
218
  GVL_STRUCT_TYPE(CoalesceImages) args = { images, exception };
204
219
  new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CoalesceImages), &args);
205
220
  rm_split(images);
221
+ RB_GC_GUARD(clones);
206
222
  rm_check_exception(exception, new_images, DestroyOnError);
207
223
  DestroyExceptionInfo(exception);
208
224
 
@@ -284,7 +300,8 @@ VALUE ImageList_combine(int argc, VALUE *argv, VALUE self)
284
300
  }
285
301
  #endif
286
302
 
287
- images = images_from_imagelist(self);
303
+ VALUE clones;
304
+ images = images_from_imagelist(self, &clones);
288
305
  exception = AcquireExceptionInfo();
289
306
  #if defined(IMAGEMAGICK_6)
290
307
  old_colorspace = images->colorspace;
@@ -296,6 +313,7 @@ VALUE ImageList_combine(int argc, VALUE *argv, VALUE self)
296
313
  new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CombineImages), &args);
297
314
 
298
315
  rm_split(images);
316
+ RB_GC_GUARD(clones);
299
317
  #if defined(IMAGEMAGICK_6)
300
318
  images->colorspace = old_colorspace;
301
319
  #endif
@@ -341,11 +359,23 @@ ImageList_composite_layers(int argc, VALUE *argv, VALUE self)
341
359
  }
342
360
 
343
361
  // Convert ImageLists to image sequences.
344
- dest = images_from_imagelist(self);
362
+ VALUE clones, source_clones = Qnil;
363
+ dest = images_from_imagelist(self, &clones);
345
364
  new_images = clone_imagelist(dest);
346
365
  rm_split(dest);
347
-
348
- source = images_from_imagelist(source_images);
366
+ RB_GC_GUARD(clones);
367
+
368
+ // new_images is not owned by any Ruby object yet, so resolving the source
369
+ // list has to be able to unwind without abandoning it.
370
+ struct ImagesFromImageList_Args source_args = { source_images, &source_clones, NULL };
371
+ int state = 0;
372
+ rb_protect(images_from_imagelist_protected, (VALUE)&source_args, &state);
373
+ if (state)
374
+ {
375
+ DestroyImageList(new_images);
376
+ rb_jump_tag(state);
377
+ }
378
+ source = source_args.images;
349
379
 
350
380
  SetGeometry(new_images, &geometry);
351
381
  ParseAbsoluteGeometry(new_images->geometry, &geometry);
@@ -360,6 +390,7 @@ ImageList_composite_layers(int argc, VALUE *argv, VALUE self)
360
390
  GVL_STRUCT_TYPE(CompositeLayers) args = { new_images, composite_op, source, geometry.x, geometry.y, exception };
361
391
  CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CompositeLayers), &args);
362
392
  rm_split(source);
393
+ RB_GC_GUARD(source_clones);
363
394
  rm_check_exception(exception, new_images, DestroyOnError);
364
395
  DestroyExceptionInfo(exception);
365
396
 
@@ -381,7 +412,8 @@ ImageList_deconstruct(VALUE self)
381
412
  Image *new_images, *images;
382
413
  ExceptionInfo *exception;
383
414
 
384
- images = images_from_imagelist(self);
415
+ VALUE clones;
416
+ images = images_from_imagelist(self, &clones);
385
417
  exception = AcquireExceptionInfo();
386
418
  #if defined(IMAGEMAGICK_7)
387
419
  GVL_STRUCT_TYPE(CompareImagesLayers) args = { images, CompareAnyLayer, exception };
@@ -391,6 +423,7 @@ ImageList_deconstruct(VALUE self)
391
423
  new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(DeconstructImages), &args);
392
424
  #endif
393
425
  rm_split(images);
426
+ RB_GC_GUARD(clones);
394
427
  rm_check_exception(exception, new_images, DestroyOnError);
395
428
  DestroyExceptionInfo(exception);
396
429
 
@@ -420,7 +453,8 @@ ImageList_display(VALUE self)
420
453
  TypedData_Get_Struct(info_obj, Info, &rm_info_data_type, info);
421
454
 
422
455
  // Convert the images array to an images sequence.
423
- images = images_from_imagelist(self);
456
+ VALUE clones;
457
+ images = images_from_imagelist(self, &clones);
424
458
  #if defined(IMAGEMAGICK_7)
425
459
  exception = AcquireExceptionInfo();
426
460
  DisplayImages(info, images, exception);
@@ -433,6 +467,7 @@ ImageList_display(VALUE self)
433
467
  rm_check_image_exception(images, RetainOnError);
434
468
  #endif
435
469
 
470
+ RB_GC_GUARD(clones);
436
471
  RB_GC_GUARD(info_obj);
437
472
 
438
473
  return self;
@@ -450,13 +485,15 @@ ImageList_flatten_images(VALUE self)
450
485
  Image *images, *new_image;
451
486
  ExceptionInfo *exception;
452
487
 
453
- images = images_from_imagelist(self);
488
+ VALUE clones;
489
+ images = images_from_imagelist(self, &clones);
454
490
  exception = AcquireExceptionInfo();
455
491
 
456
492
  GVL_STRUCT_TYPE(MergeImageLayers) args = { images, FlattenLayer, exception };
457
493
  new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MergeImageLayers), &args);
458
494
 
459
495
  rm_split(images);
496
+ RB_GC_GUARD(clones);
460
497
  rm_check_exception(exception, new_image, DestroyOnError);
461
498
  DestroyExceptionInfo(exception);
462
499
 
@@ -494,7 +531,8 @@ ImageList_montage(VALUE self)
494
531
 
495
532
  TypedData_Get_Struct(montage_obj, Montage, &rm_montage_data_type, montage);
496
533
 
497
- images = images_from_imagelist(self);
534
+ VALUE clones;
535
+ images = images_from_imagelist(self, &clones);
498
536
 
499
537
  for (Image *image = images; image; image = GetNextImageInList(image))
500
538
  {
@@ -514,6 +552,7 @@ ImageList_montage(VALUE self)
514
552
  GVL_STRUCT_TYPE(MontageImages) args = { images, montage->info, exception };
515
553
  new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MontageImages), &args);
516
554
  rm_split(images);
555
+ RB_GC_GUARD(clones);
517
556
  rm_check_exception(exception, new_images, DestroyOnError);
518
557
  DestroyExceptionInfo(exception);
519
558
 
@@ -546,11 +585,13 @@ ImageList_morph(VALUE self, VALUE nimages)
546
585
  }
547
586
 
548
587
  number_images = NUM2LONG(nimages);
549
- images = images_from_imagelist(self);
588
+ VALUE clones;
589
+ images = images_from_imagelist(self, &clones);
550
590
  exception = AcquireExceptionInfo();
551
591
  GVL_STRUCT_TYPE(MorphImages) args = { images, number_images, exception };
552
592
  new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MorphImages), &args);
553
593
  rm_split(images);
594
+ RB_GC_GUARD(clones);
554
595
  rm_check_exception(exception, new_images, DestroyOnError);
555
596
  DestroyExceptionInfo(exception);
556
597
 
@@ -569,13 +610,15 @@ ImageList_mosaic(VALUE self)
569
610
  Image *images, *new_image;
570
611
  ExceptionInfo *exception;
571
612
 
572
- images = images_from_imagelist(self);
613
+ VALUE clones;
614
+ images = images_from_imagelist(self, &clones);
573
615
 
574
616
  exception = AcquireExceptionInfo();
575
617
  GVL_STRUCT_TYPE(MergeImageLayers) args = { images, MosaicLayer, exception };
576
618
  new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MergeImageLayers), &args);
577
619
 
578
620
  rm_split(images);
621
+ RB_GC_GUARD(clones);
579
622
  rm_check_exception(exception, new_image, DestroyOnError);
580
623
  DestroyExceptionInfo(exception);
581
624
 
@@ -601,7 +644,8 @@ ImageList_optimize_layers(VALUE self, VALUE method)
601
644
  new_images2 = NULL; // defeat "unused variable" message
602
645
 
603
646
  VALUE_TO_ENUM(method, mthd, LayerMethod);
604
- images = images_from_imagelist(self);
647
+ VALUE clones;
648
+ images = images_from_imagelist(self, &clones);
605
649
 
606
650
  exception = AcquireExceptionInfo();
607
651
  switch (mthd)
@@ -730,6 +774,7 @@ ImageList_optimize_layers(VALUE self, VALUE method)
730
774
  }
731
775
 
732
776
  rm_split(images);
777
+ RB_GC_GUARD(clones);
733
778
  rm_check_exception(exception, new_images, DestroyOnError);
734
779
  DestroyExceptionInfo(exception);
735
780
 
@@ -802,12 +847,14 @@ rm_imagelist_from_images(Image *images)
802
847
  * @see rm_imagelist_from_images
803
848
  */
804
849
  static Image *
805
- images_from_imagelist(VALUE imagelist)
850
+ images_from_imagelist(VALUE imagelist, VALUE *clones)
806
851
  {
807
852
  long x, len;
808
853
  Image *head = NULL;
809
854
  VALUE images, t;
810
855
 
856
+ *clones = rb_ary_new();
857
+
811
858
  len = check_imagelist_length(imagelist);
812
859
 
813
860
  images = rb_iv_get(imagelist, "@images");
@@ -823,7 +870,9 @@ images_from_imagelist(VALUE imagelist)
823
870
  image = rm_clone_image(image);
824
871
 
825
872
  // Wrap raw ImageMagick object by Ruby object to destroy using Ruby's GC.
826
- rm_image_new(image);
873
+ // The wrapper is kept in *clones so that the GC cannot reclaim it, and
874
+ // with it the Image, while the list below is still in use.
875
+ rb_ary_push(*clones, rm_image_new(image));
827
876
  }
828
877
  AppendImageToList(&head, image);
829
878
  }
@@ -835,6 +884,26 @@ images_from_imagelist(VALUE imagelist)
835
884
  }
836
885
 
837
886
 
887
+ /**
888
+ * Call images_from_imagelist() so that it can be passed to rb_protect().
889
+ *
890
+ * No Ruby usage (internal function)
891
+ *
892
+ * @param arg a pointer to an ImagesFromImageList_Args, cast to a VALUE
893
+ * @return nil, the result is stored in the argument
894
+ * @see images_from_imagelist
895
+ */
896
+ static VALUE
897
+ images_from_imagelist_protected(VALUE arg)
898
+ {
899
+ struct ImagesFromImageList_Args *args = (struct ImagesFromImageList_Args *)arg;
900
+
901
+ args->images = images_from_imagelist(args->imagelist, args->clones);
902
+
903
+ return Qnil;
904
+ }
905
+
906
+
838
907
  /**
839
908
  * return the # of images in an imagelist.
840
909
  *
@@ -859,7 +928,7 @@ imagelist_length(VALUE imagelist)
859
928
 
860
929
 
861
930
  /**
862
- * Raise exception if imagelist is emtpy.
931
+ * Raise exception if imagelist is empty.
863
932
  *
864
933
  * No Ruby usage (internal function)
865
934
  *
@@ -934,7 +1003,7 @@ clone_imagelist(Image *images)
934
1003
  * Analyzes the colors within a set of reference images and chooses a fixed number of colors to represent the set.
935
1004
  * The goal of the algorithm is to minimize the difference between the input and output images while minimizing the processing time.
936
1005
  *
937
- * @overload quantize(number_colors = 256, colorspace = Magick::RGBColorsapce, dither = true, tree_depth = 0, measure_error = false)
1006
+ * @overload quantize(number_colors = 256, colorspace = Magick::RGBColorspace, dither = true, tree_depth = 0, measure_error = false)
938
1007
  * @param number_colors [Numeric] the maximum number of colors to use in the output images.
939
1008
  * @param colorspace [Magick::ColorspaceType] the colorspace to quantize in.
940
1009
  * @param dither [Magick::DitherMethod, Boolean] a DitherMethod value or true if you want apply dither.
@@ -994,11 +1063,13 @@ ImageList_quantize(int argc, VALUE *argv, VALUE self)
994
1063
 
995
1064
 
996
1065
  // Convert image array to image sequence, clone image sequence.
997
- images = images_from_imagelist(self);
1066
+ VALUE clones;
1067
+ images = images_from_imagelist(self, &clones);
998
1068
  exception = AcquireExceptionInfo();
999
1069
  GVL_STRUCT_TYPE(CloneImageList) args_CloneImageList = { images, exception };
1000
1070
  new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CloneImageList), &args_CloneImageList);
1001
1071
  rm_split(images);
1072
+ RB_GC_GUARD(clones);
1002
1073
  rm_check_exception(exception, new_images, DestroyOnError);
1003
1074
 
1004
1075
  rm_ensure_result(new_images);
@@ -1071,7 +1142,8 @@ ImageList_remap(int argc, VALUE *argv, VALUE self)
1071
1142
  rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc);
1072
1143
  }
1073
1144
 
1074
- images = images_from_imagelist(self);
1145
+ VALUE clones;
1146
+ images = images_from_imagelist(self, &clones);
1075
1147
 
1076
1148
  #if defined(IMAGEMAGICK_7)
1077
1149
  exception = AcquireExceptionInfo();
@@ -1087,6 +1159,8 @@ ImageList_remap(int argc, VALUE *argv, VALUE self)
1087
1159
  rm_check_image_exception(images, RetainOnError);
1088
1160
  #endif
1089
1161
 
1162
+ RB_GC_GUARD(clones);
1163
+
1090
1164
  return self;
1091
1165
  }
1092
1166
 
@@ -1118,7 +1192,8 @@ ImageList_to_blob(VALUE self)
1118
1192
  TypedData_Get_Struct(info_obj, Info, &rm_info_data_type, info);
1119
1193
 
1120
1194
  // Convert the images array to an images sequence.
1121
- images = images_from_imagelist(self);
1195
+ VALUE clones;
1196
+ images = images_from_imagelist(self, &clones);
1122
1197
 
1123
1198
  exception = AcquireExceptionInfo();
1124
1199
  SetImageInfo(info, MagickTrue, exception);
@@ -1151,6 +1226,7 @@ ImageList_to_blob(VALUE self)
1151
1226
  length = 0;
1152
1227
  }
1153
1228
  rm_split(images);
1229
+ RB_GC_GUARD(clones);
1154
1230
  CHECK_EXCEPTION();
1155
1231
  DestroyExceptionInfo(exception);
1156
1232
 
@@ -1216,7 +1292,8 @@ ImageList_write(VALUE self, VALUE file)
1216
1292
  }
1217
1293
 
1218
1294
  // Convert the images array to an images sequence.
1219
- images = images_from_imagelist(self);
1295
+ VALUE clones;
1296
+ images = images_from_imagelist(self, &clones);
1220
1297
 
1221
1298
  // Copy the filename into each image. Set a scene number to be used if
1222
1299
  // writing multiple files. (Ref: ImageMagick's utilities/convert.c
@@ -1267,6 +1344,7 @@ ImageList_write(VALUE self, VALUE file)
1267
1344
  #endif
1268
1345
 
1269
1346
  rm_split(images);
1347
+ RB_GC_GUARD(clones);
1270
1348
 
1271
1349
  RB_GC_GUARD(info_obj);
1272
1350