rmagick 7.0.3 → 7.0.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32acca4c4c8093c4473e8ed5347b925e688b1674082a8b11731508da616ca859
4
- data.tar.gz: 184b70abce972992538f018162aa2a31e31e4d5ca864f945fa829de22a788501
3
+ metadata.gz: 6a209cf0d468a316b82b18e0dc8cdfe37d07e3a9a89a54750303c48fddbc4721
4
+ data.tar.gz: ec494eed858ad482b7fbc1a3784c471bed373ab2ad1cd3835c99b3c998548736
5
5
  SHA512:
6
- metadata.gz: 0d100afa5ed1091828e68066199393d0a5fd472aa635b6edabc37a4d916a1efe0e8c44f65567cdcda099996d1d30aece01120715ba1dabdb040497c9f595e207
7
- data.tar.gz: 850e978981ebca5d4c63c59b2f577f4c9138eb48cab4402a59f78a54e95cfaac56b9806d690e025bae5502235e713d0b53c72645dac1bbcc855e43b5b05fc042
6
+ metadata.gz: 8879e76297539f5ab7816fb3ba4894530141292fdd828277774d5631655176c717f0888f4624d22f6b7006e9d1b544f7065705220d06df77eadbb428216d6dce
7
+ data.tar.gz: 67e8ff6082884e98cf7cf3dfc35eee092377fc2e4a1d60cc6679b9872dc4c52effc6a6ad6b95966a552eb6f15c2b0264ee2580d768dfce0b71a9aa1ee90b866a
data/CHANGELOG.md CHANGED
@@ -3,6 +3,26 @@
3
3
  All notable changes to this project are documented in this file.
4
4
  This project adheres to [Semantic Versioning](http://semver.org/).
5
5
 
6
+ ## RMagick 7.0.5
7
+
8
+ Bug Fixes
9
+
10
+ * Fix heap overflow from integer overflow in dispatch/export_pixels geometry (#1816)
11
+ * Fix SEGV in Image/Pixel/Draw #marshal_load on a non-collection argument (#1815)
12
+ * Fix SEGV when a Draw method is called on an uninitialized object (#1814)
13
+ * Fix SEGV in Draw#primitive on non-String argument (#1813)
14
+
15
+ ## RMagick 7.0.4
16
+
17
+ Bug Fixes
18
+
19
+ * Fix report size in rm_kernel_info_memsize (#1808)
20
+ * Fix NULL dereference in KernelInfo instance methods (#1807)
21
+ * Fix memory leak and NULL deref in Image#properties (#1806)
22
+ * Fix memory leak when string conversion raises (#1805)
23
+ * Fix error handling in Pixel#to_color when QueryColorname fails (#1800)
24
+ * Reject NAN in Pixel#from_hsla() (#1798)
25
+
6
26
  ## RMagick 7.0.3
7
27
 
8
28
  Bug Fixes
data/README.md CHANGED
@@ -3,6 +3,7 @@ RMagick
3
3
 
4
4
  [![GemVersion](https://img.shields.io/gem/v/rmagick.svg?style=flat)](https://rubygems.org/gems/rmagick)
5
5
  ![CI](https://github.com/rmagick/rmagick/workflows/CI/badge.svg)
6
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/rmagick/rmagick)
6
7
 
7
8
  Table of Contents
8
9
  -----------------
@@ -47,6 +47,33 @@ DEFINE_GVL_STUB3(GetTypeMetrics, Image *, const DrawInfo *, TypeMetric *);
47
47
  #endif
48
48
 
49
49
 
50
+ /**
51
+ * Fetch the Draw struct and ensure it has been initialized (draw->info != NULL).
52
+ *
53
+ * Draw_alloc() leaves draw->info NULL until #initialize runs, so a Draw obtained
54
+ * via .allocate (or a subclass whose #initialize skips super) would otherwise
55
+ * dereference a NULL DrawInfo and crash the process. Raise instead.
56
+ *
57
+ * No Ruby usage (internal function)
58
+ *
59
+ * @param self the Draw object
60
+ * @return the initialized Draw struct
61
+ * @throw RuntimeError if the Draw object has not been initialized
62
+ */
63
+ static Draw *
64
+ get_draw(VALUE self)
65
+ {
66
+ Draw *draw;
67
+
68
+ TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
69
+ if (!draw->info)
70
+ {
71
+ rb_raise(rb_eRuntimeError, "%s has not been initialized", rb_obj_classname(self));
72
+ }
73
+ return draw;
74
+ }
75
+
76
+
50
77
  /**
51
78
  * Set the affine matrix from an {Magick::AffineMatrix}.
52
79
  *
@@ -59,7 +86,7 @@ Draw_affine_eq(VALUE self, VALUE matrix)
59
86
  Draw *draw;
60
87
 
61
88
  rb_check_frozen(self);
62
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
89
+ draw = get_draw(self);
63
90
  Export_AffineMatrix(&draw->info->affine, matrix);
64
91
  return matrix;
65
92
  }
@@ -77,7 +104,7 @@ Draw_align_eq(VALUE self, VALUE align)
77
104
  Draw *draw;
78
105
 
79
106
  rb_check_frozen(self);
80
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
107
+ draw = get_draw(self);
81
108
  VALUE_TO_ENUM(align, draw->info->align, AlignType);
82
109
  return align;
83
110
  }
@@ -95,7 +122,7 @@ Draw_decorate_eq(VALUE self, VALUE decorate)
95
122
  Draw *draw;
96
123
 
97
124
  rb_check_frozen(self);
98
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
125
+ draw = get_draw(self);
99
126
  VALUE_TO_ENUM(decorate, draw->info->decorate, DecorationType);
100
127
  return decorate;
101
128
  }
@@ -113,7 +140,7 @@ Draw_density_eq(VALUE self, VALUE density)
113
140
  Draw *draw;
114
141
 
115
142
  rb_check_frozen(self);
116
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
143
+ draw = get_draw(self);
117
144
  magick_clone_string(&draw->info->density, StringValueCStr(density));
118
145
 
119
146
  return density;
@@ -132,7 +159,7 @@ Draw_encoding_eq(VALUE self, VALUE encoding)
132
159
  Draw *draw;
133
160
 
134
161
  rb_check_frozen(self);
135
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
162
+ draw = get_draw(self);
136
163
  magick_clone_string(&draw->info->encoding, StringValueCStr(encoding));
137
164
 
138
165
  return encoding;
@@ -151,7 +178,7 @@ Draw_fill_eq(VALUE self, VALUE fill)
151
178
  Draw *draw;
152
179
 
153
180
  rb_check_frozen(self);
154
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
181
+ draw = get_draw(self);
155
182
  Color_to_PixelColor(&draw->info->fill, fill);
156
183
  return fill;
157
184
  }
@@ -172,7 +199,7 @@ Draw_fill_pattern_eq(VALUE self, VALUE pattern)
172
199
  Draw *draw;
173
200
 
174
201
  rb_check_frozen(self);
175
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
202
+ draw = get_draw(self);
176
203
 
177
204
  if (draw->info->fill_pattern != NULL)
178
205
  {
@@ -207,7 +234,7 @@ Draw_font_eq(VALUE self, VALUE font)
207
234
  Draw *draw;
208
235
 
209
236
  rb_check_frozen(self);
210
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
237
+ draw = get_draw(self);
211
238
  magick_clone_string(&draw->info->font, StringValueCStr(font));
212
239
 
213
240
  return font;
@@ -226,7 +253,7 @@ Draw_font_family_eq(VALUE self, VALUE family)
226
253
  Draw *draw;
227
254
 
228
255
  rb_check_frozen(self);
229
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
256
+ draw = get_draw(self);
230
257
  magick_clone_string(&draw->info->family, StringValueCStr(family));
231
258
 
232
259
  return family;
@@ -245,7 +272,7 @@ Draw_font_stretch_eq(VALUE self, VALUE stretch)
245
272
  Draw *draw;
246
273
 
247
274
  rb_check_frozen(self);
248
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
275
+ draw = get_draw(self);
249
276
  VALUE_TO_ENUM(stretch, draw->info->stretch, StretchType);
250
277
  return stretch;
251
278
  }
@@ -263,7 +290,7 @@ Draw_font_style_eq(VALUE self, VALUE style)
263
290
  Draw *draw;
264
291
 
265
292
  rb_check_frozen(self);
266
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
293
+ draw = get_draw(self);
267
294
  VALUE_TO_ENUM(style, draw->info->style, StyleType);
268
295
  return style;
269
296
  }
@@ -283,7 +310,7 @@ Draw_font_weight_eq(VALUE self, VALUE weight)
283
310
  size_t w;
284
311
 
285
312
  rb_check_frozen(self);
286
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
313
+ draw = get_draw(self);
287
314
 
288
315
  if (FIXNUM_P(weight))
289
316
  {
@@ -349,7 +376,7 @@ Draw_gravity_eq(VALUE self, VALUE grav)
349
376
  Draw *draw;
350
377
 
351
378
  rb_check_frozen(self);
352
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
379
+ draw = get_draw(self);
353
380
  VALUE_TO_ENUM(grav, draw->info->gravity, GravityType);
354
381
 
355
382
  return grav;
@@ -368,7 +395,7 @@ Draw_kerning_eq(VALUE self, VALUE kerning)
368
395
  Draw *draw;
369
396
 
370
397
  rb_check_frozen(self);
371
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
398
+ draw = get_draw(self);
372
399
  draw->info->kerning = NUM2DBL(kerning);
373
400
  return kerning;
374
401
  }
@@ -386,7 +413,7 @@ Draw_interline_spacing_eq(VALUE self, VALUE spacing)
386
413
  Draw *draw;
387
414
 
388
415
  rb_check_frozen(self);
389
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
416
+ draw = get_draw(self);
390
417
  draw->info->interline_spacing = NUM2DBL(spacing);
391
418
  return spacing;
392
419
  }
@@ -404,7 +431,7 @@ Draw_interword_spacing_eq(VALUE self, VALUE spacing)
404
431
  Draw *draw;
405
432
 
406
433
  rb_check_frozen(self);
407
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
434
+ draw = get_draw(self);
408
435
  draw->info->interword_spacing = NUM2DBL(spacing);
409
436
  return spacing;
410
437
  }
@@ -505,7 +532,7 @@ Draw_marshal_dump(VALUE self)
505
532
  Draw *draw;
506
533
  VALUE ddraw;
507
534
 
508
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
535
+ draw = get_draw(self);
509
536
 
510
537
  // Raise an exception if the Draw has a non-NULL gradient or element_reference field
511
538
  if (draw->info->element_reference.type != UndefinedReference
@@ -566,6 +593,8 @@ Draw_marshal_load(VALUE self, VALUE ddraw)
566
593
 
567
594
  TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
568
595
 
596
+ Check_Type(ddraw, T_HASH);
597
+
569
598
  if (draw->info == NULL)
570
599
  {
571
600
  ImageInfo *image_info;
@@ -636,7 +665,7 @@ Draw_pointsize_eq(VALUE self, VALUE pointsize)
636
665
  Draw *draw;
637
666
 
638
667
  rb_check_frozen(self);
639
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
668
+ draw = get_draw(self);
640
669
  draw->info->pointsize = NUM2DBL(pointsize);
641
670
  return pointsize;
642
671
  }
@@ -656,7 +685,7 @@ Draw_rotation_eq(VALUE self, VALUE deg)
656
685
  AffineMatrix affine, current;
657
686
 
658
687
  rb_check_frozen(self);
659
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
688
+ draw = get_draw(self);
660
689
 
661
690
  degrees = NUM2DBL(deg);
662
691
  if (fabs(degrees) > DBL_EPSILON)
@@ -692,7 +721,7 @@ Draw_stroke_eq(VALUE self, VALUE stroke)
692
721
  Draw *draw;
693
722
 
694
723
  rb_check_frozen(self);
695
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
724
+ draw = get_draw(self);
696
725
  Color_to_PixelColor(&draw->info->stroke, stroke);
697
726
  return stroke;
698
727
  }
@@ -712,7 +741,7 @@ Draw_stroke_pattern_eq(VALUE self, VALUE pattern)
712
741
  Draw *draw;
713
742
 
714
743
  rb_check_frozen(self);
715
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
744
+ draw = get_draw(self);
716
745
 
717
746
  if (draw->info->stroke_pattern != NULL)
718
747
  {
@@ -748,7 +777,7 @@ Draw_stroke_width_eq(VALUE self, VALUE stroke_width)
748
777
  Draw *draw;
749
778
 
750
779
  rb_check_frozen(self);
751
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
780
+ draw = get_draw(self);
752
781
  draw->info->stroke_width = NUM2DBL(stroke_width);
753
782
  return stroke_width;
754
783
  }
@@ -766,7 +795,7 @@ Draw_text_antialias_eq(VALUE self, VALUE text_antialias)
766
795
  Draw *draw;
767
796
 
768
797
  rb_check_frozen(self);
769
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
798
+ draw = get_draw(self);
770
799
  draw->info->text_antialias = (MagickBooleanType) RTEST(text_antialias);
771
800
  return text_antialias;
772
801
  }
@@ -797,7 +826,7 @@ Draw_undercolor_eq(VALUE self, VALUE undercolor)
797
826
  Draw *draw;
798
827
 
799
828
  rb_check_frozen(self);
800
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
829
+ draw = get_draw(self);
801
830
  Color_to_PixelColor(&draw->info->undercolor, undercolor);
802
831
  return undercolor;
803
832
  }
@@ -840,7 +869,7 @@ VALUE Draw_annotate(
840
869
 
841
870
  // Save the affine matrix in case it is modified by
842
871
  // Draw#rotation=
843
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
872
+ draw = get_draw(self);
844
873
  keep = draw->info->affine;
845
874
 
846
875
  image_arg = rm_cur_image(image_arg);
@@ -1050,7 +1079,7 @@ Draw_draw(VALUE self, VALUE image_arg)
1050
1079
  image_arg = rm_cur_image(image_arg);
1051
1080
  image = rm_check_frozen(image_arg);
1052
1081
 
1053
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
1082
+ draw = get_draw(self);
1054
1083
  if (draw->primitives == 0)
1055
1084
  {
1056
1085
  rb_raise(rb_eArgError, "nothing to draw");
@@ -1257,6 +1286,7 @@ Draw_primitive(VALUE self, VALUE primitive)
1257
1286
  Draw *draw;
1258
1287
 
1259
1288
  rb_check_frozen(self);
1289
+ StringValue(primitive);
1260
1290
  TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
1261
1291
 
1262
1292
  if (draw->primitives == (VALUE)0)
@@ -1463,7 +1493,7 @@ PolaroidOptions_initialize(VALUE self)
1463
1493
  ExceptionInfo *exception;
1464
1494
 
1465
1495
  // Default shadow color
1466
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
1496
+ draw = get_draw(self);
1467
1497
 
1468
1498
  exception = AcquireExceptionInfo();
1469
1499
  QueryColorCompliance("gray75", AllCompliance, &draw->shadow_color, exception);
@@ -1525,7 +1555,7 @@ PolaroidOptions_border_color_eq(VALUE self, VALUE border)
1525
1555
  Draw *draw;
1526
1556
 
1527
1557
  rb_check_frozen(self);
1528
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
1558
+ draw = get_draw(self);
1529
1559
  Color_to_PixelColor(&draw->info->border_color, border);
1530
1560
  return border;
1531
1561
  }
@@ -1628,7 +1658,7 @@ get_type_metrics(int argc, VALUE *argv, VALUE self, gvl_function_t fp)
1628
1658
  rb_raise(rb_eArgError, "no text to measure");
1629
1659
  }
1630
1660
 
1631
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
1661
+ draw = get_draw(self);
1632
1662
  #if defined(IMAGEMAGICK_7)
1633
1663
  exception = AcquireExceptionInfo();
1634
1664
  draw->info->text = InterpretImageProperties(NULL, image, text, exception);
@@ -5355,16 +5355,17 @@ VALUE
5355
5355
  Image_delete_profile(VALUE self, VALUE name)
5356
5356
  {
5357
5357
  Image *image = rm_check_frozen(self);
5358
+ char *profile_name = StringValueCStr(name);
5358
5359
 
5359
5360
  #if defined(IMAGEMAGICK_7)
5360
5361
  ExceptionInfo *exception = AcquireExceptionInfo();
5361
5362
 
5362
- GVL_STRUCT_TYPE(ProfileImage) args = { image, StringValueCStr(name), NULL, 0, exception };
5363
+ GVL_STRUCT_TYPE(ProfileImage) args = { image, profile_name, NULL, 0, exception };
5363
5364
  CALL_FUNC_WITHOUT_GVL(GVL_FUNC(ProfileImage), &args);
5364
5365
  CHECK_EXCEPTION();
5365
5366
  DestroyExceptionInfo(exception);
5366
5367
  #else
5367
- GVL_STRUCT_TYPE(ProfileImage) args = { image, StringValueCStr(name), NULL, 0, MagickTrue };
5368
+ GVL_STRUCT_TYPE(ProfileImage) args = { image, profile_name, NULL, 0, MagickTrue };
5368
5369
  CALL_FUNC_WITHOUT_GVL(GVL_FUNC(ProfileImage), &args);
5369
5370
  #endif
5370
5371
  return self;
@@ -5629,6 +5630,41 @@ Image_displace(int argc, VALUE *argv, VALUE self)
5629
5630
  }
5630
5631
 
5631
5632
 
5633
+ /**
5634
+ * Compute columns * rows * map_length for a pixel buffer, raising RangeError on
5635
+ * overflow.
5636
+ *
5637
+ * The product is used to size the buffer that ImageMagick fills based on the
5638
+ * (caller-supplied) columns and rows. If the multiplication wrapped around, the
5639
+ * buffer would be allocated too small and ImageMagick would write out of bounds.
5640
+ *
5641
+ * No Ruby usage (internal function)
5642
+ *
5643
+ * @param columns the number of columns
5644
+ * @param rows the number of rows
5645
+ * @param map_length the number of channels per pixel (length of the map string)
5646
+ * @return columns * rows * map_length
5647
+ * @throw RangeError if the multiplication overflows
5648
+ */
5649
+ static size_t
5650
+ pixel_buffer_count(size_t columns, size_t rows, size_t map_length)
5651
+ {
5652
+ size_t pixels;
5653
+
5654
+ if (columns != 0 && rows > SIZE_MAX / columns)
5655
+ {
5656
+ rb_raise(rb_eRangeError, "pixel buffer dimensions too large (%" RMIuSIZE "x%" RMIuSIZE ")", columns, rows);
5657
+ }
5658
+ pixels = columns * rows;
5659
+ if (map_length != 0 && pixels > SIZE_MAX / map_length)
5660
+ {
5661
+ rb_raise(rb_eRangeError, "pixel buffer dimensions too large (%" RMIuSIZE "x%" RMIuSIZE " map=%" RMIuSIZE ")",
5662
+ columns, rows, map_length);
5663
+ }
5664
+ return pixels * map_length;
5665
+ }
5666
+
5667
+
5632
5668
  /**
5633
5669
  * Extract pixel data from the image and returns it as an array of pixels. The "x", "y", "width" and
5634
5670
  * "height" parameters specify the rectangle to be extracted. The "map" parameter reflects the
@@ -5684,7 +5720,7 @@ Image_dispatch(int argc, VALUE *argv, VALUE self)
5684
5720
  }
5685
5721
 
5686
5722
  // Compute the size of the pixel array and allocate the memory.
5687
- npixels = columns * rows * mapL;
5723
+ npixels = pixel_buffer_count(columns, rows, mapL);
5688
5724
  pixels.v = stg_type == QuantumPixel ? (void *) ALLOC_N(Quantum, npixels)
5689
5725
  : (void *) ALLOC_N(double, npixels);
5690
5726
 
@@ -6635,7 +6671,7 @@ Image_export_pixels(int argc, VALUE *argv, VALUE self)
6635
6671
  }
6636
6672
 
6637
6673
 
6638
- npixels = (long)(cols * rows * strlen(map));
6674
+ npixels = (long)pixel_buffer_count(cols, rows, strlen(map));
6639
6675
  pixels = ALLOC_N(Quantum, npixels);
6640
6676
  if (!pixels) // app recovered from exception
6641
6677
  {
@@ -6803,7 +6839,7 @@ Image_export_pixels_to_str(int argc, VALUE *argv, VALUE self)
6803
6839
  }
6804
6840
 
6805
6841
 
6806
- npixels = cols * rows * strlen(map);
6842
+ npixels = pixel_buffer_count(cols, rows, strlen(map));
6807
6843
  switch (type)
6808
6844
  {
6809
6845
  case CharPixel:
@@ -6832,6 +6868,10 @@ Image_export_pixels_to_str(int argc, VALUE *argv, VALUE self)
6832
6868
 
6833
6869
  // Allocate a string long enough to hold the exported pixel data.
6834
6870
  // Get a pointer to the buffer.
6871
+ if (npixels != 0 && sz > (size_t)LONG_MAX / npixels)
6872
+ {
6873
+ rb_raise(rb_eRangeError, "pixel buffer dimensions too large");
6874
+ }
6835
6875
  string = rb_str_new2("");
6836
6876
  rb_str_resize(string, (long)(sz * npixels));
6837
6877
 
@@ -9055,6 +9095,8 @@ Image_marshal_load(VALUE self, VALUE ary)
9055
9095
 
9056
9096
  TypedData_Get_Struct(self, Image, &rm_image_data_type, image);
9057
9097
 
9098
+ Check_Type(ary, T_ARRAY);
9099
+
9058
9100
  filename = rb_ary_shift(ary);
9059
9101
  blob = rb_ary_shift(ary);
9060
9102
 
@@ -12838,7 +12880,12 @@ Image_properties(VALUE self)
12838
12880
 
12839
12881
  if (rb_block_given_p())
12840
12882
  {
12841
- ary = rb_ary_new2(2);
12883
+ long i;
12884
+
12885
+ // Collect the properties first so that neither the ExceptionInfo nor
12886
+ // the property iterator is held across rb_yield. The block may break
12887
+ // or raise, which would otherwise leak the ExceptionInfo.
12888
+ ary = rb_ary_new();
12842
12889
 
12843
12890
  ResetImagePropertyIterator(image);
12844
12891
  property = GetNextImageProperty(image);
@@ -12849,9 +12896,7 @@ Image_properties(VALUE self)
12849
12896
  #else
12850
12897
  value = GetImageProperty(image, property);
12851
12898
  #endif
12852
- rb_ary_store(ary, 0, rb_str_new2(property));
12853
- rb_ary_store(ary, 1, rb_str_new2(value));
12854
- rb_yield(ary);
12899
+ rb_ary_push(ary, rb_assoc_new(rb_str_new2(property), value ? rb_str_new2(value) : Qnil));
12855
12900
  property = GetNextImageProperty(image);
12856
12901
  }
12857
12902
  #if defined(IMAGEMAGICK_7)
@@ -12861,6 +12906,11 @@ Image_properties(VALUE self)
12861
12906
  rm_check_image_exception(image, RetainOnError);
12862
12907
  #endif
12863
12908
 
12909
+ for (i = 0; i < RARRAY_LEN(ary); i++)
12910
+ {
12911
+ rb_yield(rb_ary_entry(ary, i));
12912
+ }
12913
+
12864
12914
  RB_GC_GUARD(ary);
12865
12915
 
12866
12916
  return self;
@@ -12879,7 +12929,7 @@ Image_properties(VALUE self)
12879
12929
  #else
12880
12930
  value = GetImageProperty(image, property);
12881
12931
  #endif
12882
- rb_hash_aset(attr_hash, rb_str_new2(property), rb_str_new2(value));
12932
+ rb_hash_aset(attr_hash, rb_str_new2(property), value ? rb_str_new2(value) : Qnil);
12883
12933
  property = GetNextImageProperty(image);
12884
12934
  }
12885
12935
  #if defined(IMAGEMAGICK_7)
@@ -51,7 +51,21 @@ rm_kernel_info_destroy(void *kernel)
51
51
  static size_t
52
52
  rm_kernel_info_memsize(const void *ptr)
53
53
  {
54
- return sizeof(KernelInfo);
54
+ const KernelInfo *kernel = (const KernelInfo *)ptr;
55
+ size_t size = 0;
56
+
57
+ // A KernelInfo may be a linked list of kernels, each owning a values array.
58
+ while (kernel)
59
+ {
60
+ size += sizeof(KernelInfo);
61
+ if (kernel->values)
62
+ {
63
+ size += kernel->width * kernel->height * sizeof(*kernel->values);
64
+ }
65
+ kernel = kernel->next;
66
+ }
67
+
68
+ return size;
55
69
  }
56
70
 
57
71
  /**
@@ -105,6 +119,32 @@ KernelInfo_initialize(VALUE self, VALUE kernel_string)
105
119
  }
106
120
 
107
121
 
122
+ /**
123
+ * Return the KernelInfo struct associated with the object, raising an
124
+ * exception if the object has not been initialized (for example, when it was
125
+ * created with KernelInfo.allocate or a previous initialize failed). Without
126
+ * this guard a NULL pointer would be handed to ImageMagick, causing a crash.
127
+ *
128
+ * No Ruby usage (internal function)
129
+ *
130
+ * @param self the KernelInfo object
131
+ * @return the KernelInfo struct
132
+ * @throw RuntimeError if the kernel has not been initialized
133
+ */
134
+ static KernelInfo *
135
+ get_kernel_info(VALUE self)
136
+ {
137
+ KernelInfo *kernel;
138
+
139
+ TypedData_Get_Struct(self, KernelInfo, &rm_kernel_info_data_type, kernel);
140
+ if (!kernel)
141
+ {
142
+ rb_raise(rb_eRuntimeError, "KernelInfo has not been initialized");
143
+ }
144
+ return kernel;
145
+ }
146
+
147
+
108
148
  /**
109
149
  * Adds a given amount of the 'Unity' Convolution Kernel to the given pre-scaled and normalized Kernel.
110
150
  *
@@ -113,7 +153,7 @@ KernelInfo_initialize(VALUE self, VALUE kernel_string)
113
153
  VALUE
114
154
  KernelInfo_unity_add(VALUE self, VALUE scale)
115
155
  {
116
- GVL_STRUCT_TYPE(UnityAddKernelInfo) args = { (KernelInfo*)DATA_PTR(self), NUM2DBL(scale) };
156
+ GVL_STRUCT_TYPE(UnityAddKernelInfo) args = { get_kernel_info(self), NUM2DBL(scale) };
117
157
  CALL_FUNC_WITHOUT_GVL(GVL_FUNC(UnityAddKernelInfo), &args);
118
158
  return Qnil;
119
159
  }
@@ -134,7 +174,7 @@ KernelInfo_scale(VALUE self, VALUE scale, VALUE flags)
134
174
 
135
175
  VALUE_TO_ENUM(flags, geoflags, GeometryFlags);
136
176
 
137
- GVL_STRUCT_TYPE(ScaleKernelInfo) args = { (KernelInfo*)DATA_PTR(self), NUM2DBL(scale), geoflags };
177
+ GVL_STRUCT_TYPE(ScaleKernelInfo) args = { get_kernel_info(self), NUM2DBL(scale), geoflags };
138
178
  CALL_FUNC_WITHOUT_GVL(GVL_FUNC(ScaleKernelInfo), &args);
139
179
  return Qnil;
140
180
  }
@@ -148,7 +188,7 @@ KernelInfo_scale(VALUE self, VALUE scale, VALUE flags)
148
188
  VALUE
149
189
  KernelInfo_scale_geometry(VALUE self, VALUE geometry)
150
190
  {
151
- GVL_STRUCT_TYPE(ScaleGeometryKernelInfo) args = { (KernelInfo*)DATA_PTR(self), StringValueCStr(geometry) };
191
+ GVL_STRUCT_TYPE(ScaleGeometryKernelInfo) args = { get_kernel_info(self), StringValueCStr(geometry) };
152
192
  CALL_FUNC_WITHOUT_GVL(GVL_FUNC(ScaleGeometryKernelInfo), &args);
153
193
  return Qnil;
154
194
  }
@@ -161,7 +201,7 @@ KernelInfo_scale_geometry(VALUE self, VALUE geometry)
161
201
  VALUE
162
202
  KernelInfo_clone(VALUE self)
163
203
  {
164
- KernelInfo *kernel = CloneKernelInfo((KernelInfo*)DATA_PTR(self));
204
+ KernelInfo *kernel = CloneKernelInfo(get_kernel_info(self));
165
205
  if (!kernel)
166
206
  {
167
207
  rb_raise(rb_eNoMemError, "not enough memory to continue");
@@ -473,8 +473,8 @@ Color_Name_to_PixelColor(PixelColor *color, VALUE name_arg)
473
473
  char *name;
474
474
  ExceptionInfo *exception;
475
475
 
476
- exception = AcquireExceptionInfo();
477
476
  name = StringValueCStr(name_arg);
477
+ exception = AcquireExceptionInfo();
478
478
  okay = QueryColorCompliance(name, AllCompliance, color, exception);
479
479
  DestroyExceptionInfo(exception);
480
480
  if (!okay)
@@ -683,15 +683,16 @@ Pixel_from_color(VALUE klass ATTRIBUTE_UNUSED, VALUE name)
683
683
  PixelColor pp;
684
684
  ExceptionInfo *exception;
685
685
  MagickBooleanType okay;
686
+ char *color = StringValueCStr(name);
686
687
 
687
688
  exception = AcquireExceptionInfo();
688
- okay = QueryColorCompliance(StringValueCStr(name), AllCompliance, &pp, exception);
689
+ okay = QueryColorCompliance(color, AllCompliance, &pp, exception);
689
690
  CHECK_EXCEPTION();
690
691
  DestroyExceptionInfo(exception);
691
692
 
692
693
  if (!okay)
693
694
  {
694
- rb_raise(rb_eArgError, "invalid color name: %s", StringValueCStr(name));
695
+ rb_raise(rb_eArgError, "invalid color name: %s", color);
695
696
  }
696
697
 
697
698
  return Pixel_from_PixelColor(&pp);
@@ -739,19 +740,19 @@ Pixel_from_hsla(int argc, VALUE *argv, VALUE klass ATTRIBUTE_UNUSED)
739
740
  break;
740
741
  }
741
742
 
742
- if (alpha && (a < 0.0 || a > 1.0))
743
+ if (alpha && !(a >= 0.0 && a <= 1.0))
743
744
  {
744
745
  rb_raise(rb_eRangeError, "alpha %g out of range [0.0, 1.0]", a);
745
746
  }
746
- if (l < 0.0 || l > 255.0)
747
+ if (!(l >= 0.0 && l <= 255.0))
747
748
  {
748
749
  rb_raise(rb_eRangeError, "lightness %g out of range [0.0, 255.0]", l);
749
750
  }
750
- if (s < 0.0 || s > 255.0)
751
+ if (!(s >= 0.0 && s <= 255.0))
751
752
  {
752
753
  rb_raise(rb_eRangeError, "saturation %g out of range [0.0, 255.0]", s);
753
754
  }
754
- if (h < 0.0 || h >= 360.0)
755
+ if (!(h >= 0.0 && h < 360.0))
755
756
  {
756
757
  rb_raise(rb_eRangeError, "hue %g out of range [0.0, 360.0)", h);
757
758
  }
@@ -1045,6 +1046,9 @@ Pixel_marshal_load(VALUE self, VALUE dpixel)
1045
1046
  Pixel *pixel;
1046
1047
 
1047
1048
  TypedData_Get_Struct(self, Pixel, &rm_pixel_data_type, pixel);
1049
+
1050
+ Check_Type(dpixel, T_HASH);
1051
+
1048
1052
  pixel->red = NUM2QUANTUM(rb_hash_aref(dpixel, CSTR2SYM("red")));
1049
1053
  pixel->green = NUM2QUANTUM(rb_hash_aref(dpixel, CSTR2SYM("green")));
1050
1054
  pixel->blue = NUM2QUANTUM(rb_hash_aref(dpixel, CSTR2SYM("blue")));
@@ -1269,8 +1273,7 @@ Pixel_to_color(int argc, VALUE *argv, VALUE self)
1269
1273
  rm_init_magickpixel(image, &mpp);
1270
1274
  rm_set_magick_pixel_packet(pixel, &mpp);
1271
1275
 
1272
- // Support for hex-format color names moved out of QueryMagickColorname
1273
- // in 6.4.1-9. The 'hex' argument was removed as well.
1276
+ MagickBooleanType okay = MagickTrue;
1274
1277
  if (hex)
1275
1278
  {
1276
1279
  if (compliance == XPMCompliance)
@@ -1286,14 +1289,18 @@ Pixel_to_color(int argc, VALUE *argv, VALUE self)
1286
1289
  }
1287
1290
  else
1288
1291
  {
1289
- QueryColorname(image, &mpp, compliance, name, exception);
1292
+ okay = QueryColorname(image, &mpp, compliance, name, exception);
1290
1293
  }
1291
1294
 
1292
1295
  DestroyImage(image);
1293
1296
  CHECK_EXCEPTION();
1294
1297
  DestroyExceptionInfo(exception);
1295
1298
 
1296
- // Always return a string, even if it's ""
1299
+ if (!okay)
1300
+ {
1301
+ rb_raise(Class_ImageMagickError, "QueryColorname failed (unsupported colorspace)");
1302
+ }
1303
+
1297
1304
  return rb_str_new2(name);
1298
1305
  }
1299
1306
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Magick
4
- VERSION = '7.0.3'
4
+ VERSION = '7.0.5'
5
5
  MIN_RUBY_VERSION = '3.2.0'
6
6
  MIN_IM6_VERSION = '6.9.0'
7
7
  MIN_IM7_VERSION = '7.1.0'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rmagick
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.3
4
+ version: 7.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Hunter
@@ -143,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
143
  version: '0'
144
144
  requirements:
145
145
  - ImageMagick 6.9.0+ (for ImageMagick 6) or 7.1.0+ (for ImageMagick 7)
146
- rubygems_version: 4.0.10
146
+ rubygems_version: 4.0.15
147
147
  specification_version: 4
148
148
  summary: Ruby binding to ImageMagick
149
149
  test_files: []