rmagick 7.0.4 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6b67e7280c692114f508e96e6ddcf8d554825ba3705e917af4484158aba940f
4
- data.tar.gz: 2ec01a3108eda0eebe35603ae94f675b0966343d5ccb8b2461706b67ea4f3e2c
3
+ metadata.gz: c56286daf220fd8db82fce268ce2116705e192b643641cc88b4d7e53b6a46d1a
4
+ data.tar.gz: 1a060762de65e6bf6a384a7f10c3036f85d6876ec89c1be54fede6ea4f20e604
5
5
  SHA512:
6
- metadata.gz: 1494b9956d04b5f569a39df7e436cae2cc361b093d8fc4339e7b6f56f893e0782f0e506d24faf807d8cc88c7fff697894b39f29cf651666ff1398d8bf421ed4a
7
- data.tar.gz: 06e999110504c4ab2fc1c0ddbd9e43b7415c70173780e127d25132ad0d1e5f172622a445f61922800994ef6aed543f141d984602430f0db8ce0b48fafb2974b0
6
+ metadata.gz: c7ebbec352d94fdeb8873353c8c13a8d3432b2f89c26c05a8520ee56353c1daedde3717429ad6ec1b9c66a9d9ca71eb51c498833ea0e7419fb572f38642d4fcd
7
+ data.tar.gz: c7a7941f288dd513f5ab88d009011c07575fc07e95c772fd3950db9d8828738c7ab49e6fa3484a4ead018ecbe0a002b260f4e0c670c70647aac11419465f09a5
data/CHANGELOG.md CHANGED
@@ -3,6 +3,54 @@
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.1.0
7
+
8
+ > [!IMPORTANT]
9
+ > `Draw#annotate` and `Draw#get_type_metrics` no longer interpret the text they are given.
10
+ > A `%[...]` or `%x` escape in it is now drawn as written instead of being replaced by an image property.
11
+ > Everything those escapes provided is available directly from Ruby -- `Image#columns`, `Image#rows`, `Image#format`, `Image#filesize`, `Image#filename`, `Image#[]`, `Image#artifact`, `Image#channel_mean`, `Image#pixel_color` and `Image#fx` -- so build the string in Ruby and pass the result.
12
+ >
13
+ > The interpolation was undocumented, and it handed any caller that passed user-supplied text an expression evaluator, a pixel and metadata reader, and an unbounded CPU sink. It also corrupted ordinary captions: `"%d items"` was drawn as the directory the image had been read from.
14
+
15
+ Breaking Changes
16
+
17
+ * Draw annotation text as given instead of interpreting it (#1843)
18
+ * Draw text starting with '@' instead of reading it from that file (#1837)
19
+ * Validate RVG path data against the SVG path grammar (#1839)
20
+ * Escape values and quote the clip-path and encoding names in the MVG program (#1841)
21
+ * Reject embedded NUL bytes in pathname arguments (#1827)
22
+
23
+ Improvements
24
+
25
+ * Add Image#artifact to read the artifacts Image#define writes (#1842)
26
+ * Fix grammar, typos, and content errors in the documentation (#1824)
27
+
28
+ Bug Fixes
29
+
30
+ * Fix RVG text being quoted twice and the added quotes being drawn (#1840)
31
+ * Fix MVG injection in Draw#text from unescaped backslashes (#1838)
32
+ * Fix memory leak in ImageList#composite_layers with an unusable source list (#1836)
33
+ * Fix heap over-read in Image#import_pixels with a long or empty map (#1835)
34
+ * Fix SEGV from integer overflow in Image#import_pixels geometry (#1834)
35
+ * Fix heap over-read in Image#recolor (#1833)
36
+ * Fix SEGV in Draw#marshal_load with a non-String pattern (#1832)
37
+ * Fix use-after-free of cloned images in images_from_imagelist() (#1831)
38
+ * Fix double free of the interpreted text in Draw#get_type_metrics (#1830)
39
+ * Fix double free of the annotation text in Draw#annotate (#1829)
40
+ * Fix SEGV in Info#stroke_width= and Info#attenuate= with a large Float (#1828)
41
+ * Fix Magick#set_log_event_mask() (#1826)
42
+ * Fix copy_options() using the option value as the artifact key (#1823)
43
+ * Fix unchecked SetImageArtifact() calls (#1822)
44
+
45
+ ## RMagick 7.0.5
46
+
47
+ Bug Fixes
48
+
49
+ * Fix heap overflow from integer overflow in dispatch/export_pixels geometry (#1816)
50
+ * Fix SEGV in Image/Pixel/Draw #marshal_load on a non-collection argument (#1815)
51
+ * Fix SEGV when a Draw method is called on an uninitialized object (#1814)
52
+ * Fix SEGV in Draw#primitive on non-String argument (#1813)
53
+
6
54
  ## RMagick 7.0.4
7
55
 
8
56
  Bug Fixes
data/Rakefile CHANGED
@@ -188,6 +188,12 @@ end
188
188
  if RUBY_PLATFORM.include?('linux')
189
189
  require 'ruby_memcheck'
190
190
  require 'ruby_memcheck/rspec/rake_task'
191
+
192
+ RubyMemcheck.config(
193
+ binary_name: 'RMagick2',
194
+ valgrind_suppressions_dir: 'spec/valgrind'
195
+ )
196
+
191
197
  namespace :spec do
192
198
  RubyMemcheck::RSpec::RakeTask.new(valgrind: :compile)
193
199
  end
@@ -123,7 +123,7 @@ module RMagick
123
123
  $LDFLAGS += " #{ldflags} #{rpath}"
124
124
 
125
125
  unless try_link("int main() { }")
126
- # if linker does not recognizes '-Wl,-rpath,somewhere' option, it revert to original option
126
+ # if linker does not recognize '-Wl,-rpath,somewhere' option, it reverts to original option
127
127
  $LDFLAGS = "#{original_ldflags} #{ldflags}"
128
128
  end
129
129
  end
@@ -344,7 +344,7 @@ module RMagick
344
344
  end
345
345
 
346
346
  def print_summary
347
- summary = <<~"END_SUMMARY"
347
+ summary = <<~END_SUMMARY
348
348
  #{'=' * 70}
349
349
  #{Time.now.strftime('%a %d %b %y %T')}
350
350
  This installation of RMagick #{RMAGICK_VERS} is configured for
@@ -312,7 +312,7 @@ Magick_limit_resource(int argc, VALUE *argv, VALUE klass)
312
312
 
313
313
  /**
314
314
  * Set the amount of free memory allocated for the pixel cache. Once this
315
- * threshold is exceeded, all subsequent pixels cache operations are to/from
315
+ * threshold is exceeded, all subsequent pixel cache operations are to/from
316
316
  * disk.
317
317
  *
318
318
  * @param threshold [Numeric] the number of megabytes to set.
@@ -346,23 +346,45 @@ Magick_set_cache_threshold(VALUE klass, VALUE threshold)
346
346
  * - "user"
347
347
  * - "x11"
348
348
  *
349
- * Multiple events can be specified as the aruments. Event names may be capitalized.
349
+ * Multiple events can be specified as the arguments. Event names may be capitalized.
350
350
  *
351
- * @param args [String] the mask of log event.
351
+ * @param args [Array<String>] one or more log event types (comma-separated lists and/or multiple arguments).
352
+ * @raise [ArgumentError] if an event name is invalid
352
353
  */
353
354
  VALUE
354
355
  Magick_set_log_event_mask(int argc, VALUE *argv, VALUE klass)
355
356
  {
357
+ VALUE events;
356
358
  int x;
357
359
 
358
360
  if (argc == 0)
359
361
  {
360
362
  rb_raise(rb_eArgError, "wrong number of arguments (at least 1 required)");
361
363
  }
364
+
365
+ // SetLogEventMask() does not provide a way to check if it failed
366
+ // since it returns the old mask.
362
367
  for (x = 0; x < argc; x++)
363
368
  {
364
- SetLogEventMask(StringValueCStr(argv[x]));
369
+ const char *event = StringValueCStr(argv[x]);
370
+ if (ParseCommandOption(MagickLogEventOptions, MagickTrue, event) == -1)
371
+ {
372
+ rb_raise(rb_eArgError, "invalid log event type: %s", event);
373
+ }
374
+ }
375
+
376
+ // SetLogEventMask() replaces the mask on each call rather than adding to it,
377
+ // so multiple events must be passed as a single comma-separated list.
378
+ events = rb_str_dup(argv[0]);
379
+ for (x = 1; x < argc; x++)
380
+ {
381
+ rb_str_cat_cstr(events, ",");
382
+ rb_str_append(events, argv[x]);
365
383
  }
384
+ SetLogEventMask(StringValueCStr(events));
385
+
386
+ RB_GC_GUARD(events);
387
+
366
388
  return klass;
367
389
  }
368
390
 
@@ -108,10 +108,10 @@ extern "C" {
108
108
  #define NUM2QUANTUM(n) (Quantum)NUM2UINT((n)) /**< Quantum <- Ruby Numeric conversion */
109
109
  #elif (MAGICKCORE_QUANTUM_DEPTH == 32)
110
110
  #define QUANTUM2NUM(q) UINT2NUM((q)) /**< Quantum -> Ruby Numeric conversion */
111
- #define NUM2QUANTUM(n) (Quantum)NUM2UINT((n)) /**< Quntum <- Ruby Numeric conversion */
111
+ #define NUM2QUANTUM(n) (Quantum)NUM2UINT((n)) /**< Quantum <- Ruby Numeric conversion */
112
112
  #elif (MAGICKCORE_QUANTUM_DEPTH == 64)
113
113
  #define QUANTUM2NUM(q) ULL2NUM((q)) /**< Quantum -> Ruby Numeric conversion */
114
- #define NUM2QUANTUM(n) (Quantum)NUM2ULL((n)) /**< Quntum <- Ruby Numeric conversion */
114
+ #define NUM2QUANTUM(n) (Quantum)NUM2ULL((n)) /**< Quantum <- Ruby Numeric conversion */
115
115
  #else
116
116
  #error Specified MAGICKCORE_QUANTUM_DEPTH is not supported.
117
117
  #endif
@@ -247,7 +247,7 @@ typedef enum {
247
247
  //! Draw#text_anchor AnchorType argument
248
248
  typedef enum {
249
249
  StartAnchor = 1, /**< start */
250
- MiddleAnchor = 2, /**< midle */
250
+ MiddleAnchor = 2, /**< middle */
251
251
  EndAnchor = 3 /**< end */
252
252
  } AnchorType;
253
253
 
@@ -813,6 +813,7 @@ extern VALUE Image_affine_transform(VALUE, VALUE);
813
813
  extern VALUE Image_alpha(int, VALUE *, VALUE);
814
814
  extern VALUE Image_alpha_q(VALUE);
815
815
  extern VALUE Image_aref(VALUE, VALUE);
816
+ extern VALUE Image_artifact(VALUE, VALUE);
816
817
  extern VALUE Image_aset(VALUE, VALUE, VALUE);
817
818
  extern VALUE Image_auto_gamma_channel(int, VALUE *, VALUE);
818
819
  extern VALUE Image_auto_level_channel(int, VALUE *, VALUE);
@@ -1163,6 +1164,7 @@ extern VALUE rm_check_ary_type(VALUE ary);
1163
1164
  extern Image *rm_check_destroyed(VALUE);
1164
1165
  extern Image *rm_check_frozen(VALUE);
1165
1166
  extern char *rm_str2cstr(VALUE, size_t *);
1167
+ extern char *rm_path2cstr(VALUE, size_t *);
1166
1168
  extern int rm_check_num2dbl(VALUE);
1167
1169
  extern double rm_fuzz_to_dbl(VALUE);
1168
1170
  extern Quantum rm_app2quantum(VALUE);
@@ -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
  }
@@ -473,6 +500,8 @@ Image *str_to_image(VALUE str)
473
500
  Info *info;
474
501
  ExceptionInfo *exception;
475
502
 
503
+ StringValue(str);
504
+
476
505
  info = CloneImageInfo(NULL);
477
506
  exception = AcquireExceptionInfo();
478
507
  GVL_STRUCT_TYPE(BlobToImage) args = { info, RSTRING_PTR(str), (size_t)RSTRING_LEN(str), exception };
@@ -505,7 +534,7 @@ Draw_marshal_dump(VALUE self)
505
534
  Draw *draw;
506
535
  VALUE ddraw;
507
536
 
508
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
537
+ draw = get_draw(self);
509
538
 
510
539
  // Raise an exception if the Draw has a non-NULL gradient or element_reference field
511
540
  if (draw->info->element_reference.type != UndefinedReference
@@ -566,6 +595,8 @@ Draw_marshal_load(VALUE self, VALUE ddraw)
566
595
 
567
596
  TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
568
597
 
598
+ Check_Type(ddraw, T_HASH);
599
+
569
600
  if (draw->info == NULL)
570
601
  {
571
602
  ImageInfo *image_info;
@@ -636,7 +667,7 @@ Draw_pointsize_eq(VALUE self, VALUE pointsize)
636
667
  Draw *draw;
637
668
 
638
669
  rb_check_frozen(self);
639
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
670
+ draw = get_draw(self);
640
671
  draw->info->pointsize = NUM2DBL(pointsize);
641
672
  return pointsize;
642
673
  }
@@ -656,7 +687,7 @@ Draw_rotation_eq(VALUE self, VALUE deg)
656
687
  AffineMatrix affine, current;
657
688
 
658
689
  rb_check_frozen(self);
659
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
690
+ draw = get_draw(self);
660
691
 
661
692
  degrees = NUM2DBL(deg);
662
693
  if (fabs(degrees) > DBL_EPSILON)
@@ -692,7 +723,7 @@ Draw_stroke_eq(VALUE self, VALUE stroke)
692
723
  Draw *draw;
693
724
 
694
725
  rb_check_frozen(self);
695
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
726
+ draw = get_draw(self);
696
727
  Color_to_PixelColor(&draw->info->stroke, stroke);
697
728
  return stroke;
698
729
  }
@@ -712,7 +743,7 @@ Draw_stroke_pattern_eq(VALUE self, VALUE pattern)
712
743
  Draw *draw;
713
744
 
714
745
  rb_check_frozen(self);
715
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
746
+ draw = get_draw(self);
716
747
 
717
748
  if (draw->info->stroke_pattern != NULL)
718
749
  {
@@ -748,7 +779,7 @@ Draw_stroke_width_eq(VALUE self, VALUE stroke_width)
748
779
  Draw *draw;
749
780
 
750
781
  rb_check_frozen(self);
751
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
782
+ draw = get_draw(self);
752
783
  draw->info->stroke_width = NUM2DBL(stroke_width);
753
784
  return stroke_width;
754
785
  }
@@ -766,7 +797,7 @@ Draw_text_antialias_eq(VALUE self, VALUE text_antialias)
766
797
  Draw *draw;
767
798
 
768
799
  rb_check_frozen(self);
769
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
800
+ draw = get_draw(self);
770
801
  draw->info->text_antialias = (MagickBooleanType) RTEST(text_antialias);
771
802
  return text_antialias;
772
803
  }
@@ -797,7 +828,7 @@ Draw_undercolor_eq(VALUE self, VALUE undercolor)
797
828
  Draw *draw;
798
829
 
799
830
  rb_check_frozen(self);
800
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
831
+ draw = get_draw(self);
801
832
  Color_to_PixelColor(&draw->info->undercolor, undercolor);
802
833
  return undercolor;
803
834
  }
@@ -807,7 +838,7 @@ Draw_undercolor_eq(VALUE self, VALUE undercolor)
807
838
  * Annotates an image with text.
808
839
  *
809
840
  * - Additional Draw attribute methods may be called in the optional block,
810
- * which is executed in the context of an Draw object.
841
+ * which is executed in the context of a Draw object.
811
842
  *
812
843
  * @param image_arg [Magick::Image, Magick::ImageList] Either an imagelist or an image. If an
813
844
  * imagelist, uses the current image.
@@ -840,7 +871,7 @@ VALUE Draw_annotate(
840
871
 
841
872
  // Save the affine matrix in case it is modified by
842
873
  // Draw#rotation=
843
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
874
+ draw = get_draw(self);
844
875
  keep = draw->info->affine;
845
876
 
846
877
  image_arg = rm_cur_image(image_arg);
@@ -853,29 +884,15 @@ VALUE Draw_annotate(
853
884
  rb_yield(self);
854
885
  }
855
886
 
856
- // Translate & store in Draw structure
887
+ // Store in Draw structure. The text is drawn as given: it is not run
888
+ // through InterpretImageProperties(), so a `%[...]` or `%x` escape in it is
889
+ // not expanded. Everything those escapes provide is available directly from
890
+ // Ruby -- Image#columns, Image#filename, Image#artifact and so on.
857
891
  embed_text = StringValueCStr(text);
892
+ draw->info->text = ConstantString(embed_text);
858
893
  #if defined(IMAGEMAGICK_7)
859
894
  exception = AcquireExceptionInfo();
860
- draw->info->text = InterpretImageProperties(NULL, image, embed_text, exception);
861
- if (rm_should_raise_exception(exception, RetainExceptionRetention))
862
- {
863
- if (draw->info->text)
864
- {
865
- magick_free(draw->info->text);
866
- }
867
- rm_raise_exception(exception);
868
- }
869
- #else
870
- draw->info->text = InterpretImageProperties(NULL, image, embed_text);
871
895
  #endif
872
- if (!draw->info->text)
873
- {
874
- #if defined(IMAGEMAGICK_7)
875
- DestroyExceptionInfo(exception);
876
- #endif
877
- rb_raise(rb_eArgError, "no text");
878
- }
879
896
 
880
897
  // Create geometry string, copy to Draw structure, overriding
881
898
  // any previously existing value.
@@ -1050,7 +1067,7 @@ Draw_draw(VALUE self, VALUE image_arg)
1050
1067
  image_arg = rm_cur_image(image_arg);
1051
1068
  image = rm_check_frozen(image_arg);
1052
1069
 
1053
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
1070
+ draw = get_draw(self);
1054
1071
  if (draw->primitives == 0)
1055
1072
  {
1056
1073
  rb_raise(rb_eArgError, "nothing to draw");
@@ -1118,7 +1135,7 @@ Draw_dup(VALUE self)
1118
1135
  * imagelist, uses the current image.
1119
1136
  * @param text [String] The string to be rendered.
1120
1137
  *
1121
- * @return [Magick::TypeMetric] The information for a specific string if rendered on a image.
1138
+ * @return [Magick::TypeMetric] The information for a specific string if rendered on an image.
1122
1139
  */
1123
1140
  VALUE
1124
1141
  Draw_get_type_metrics(
@@ -1145,7 +1162,7 @@ Draw_get_type_metrics(
1145
1162
  * imagelist, uses the current image.
1146
1163
  * @param text [String] The string to be rendered.
1147
1164
  *
1148
- * @return [Magick::TypeMetric] The information for a specific string if rendered on a image.
1165
+ * @return [Magick::TypeMetric] The information for a specific string if rendered on an image.
1149
1166
  */
1150
1167
  VALUE
1151
1168
  Draw_get_multiline_type_metrics(
@@ -1257,6 +1274,7 @@ Draw_primitive(VALUE self, VALUE primitive)
1257
1274
  Draw *draw;
1258
1275
 
1259
1276
  rb_check_frozen(self);
1277
+ StringValue(primitive);
1260
1278
  TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
1261
1279
 
1262
1280
  if (draw->primitives == (VALUE)0)
@@ -1310,7 +1328,7 @@ Draw_mark(void *drawptr)
1310
1328
 
1311
1329
 
1312
1330
  /**
1313
- * Free the memory associated with an Draw object.
1331
+ * Free the memory associated with a Draw object.
1314
1332
  *
1315
1333
  * No Ruby usage (internal function)
1316
1334
  *
@@ -1371,7 +1389,7 @@ new_DrawOptions(void)
1371
1389
  /**
1372
1390
  * Create a DrawOptions object.
1373
1391
  *
1374
- * - The DrawOptions class is the same as the Draw class except is has only
1392
+ * - The DrawOptions class is the same as the Draw class except it has only
1375
1393
  * the attribute writer functions
1376
1394
  *
1377
1395
  * @return [Magick::Image::DrawOptions] a new DrawOptions object
@@ -1463,7 +1481,7 @@ PolaroidOptions_initialize(VALUE self)
1463
1481
  ExceptionInfo *exception;
1464
1482
 
1465
1483
  // Default shadow color
1466
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
1484
+ draw = get_draw(self);
1467
1485
 
1468
1486
  exception = AcquireExceptionInfo();
1469
1487
  QueryColorCompliance("gray75", AllCompliance, &draw->shadow_color, exception);
@@ -1525,7 +1543,7 @@ PolaroidOptions_border_color_eq(VALUE self, VALUE border)
1525
1543
  Draw *draw;
1526
1544
 
1527
1545
  rb_check_frozen(self);
1528
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
1546
+ draw = get_draw(self);
1529
1547
  Color_to_PixelColor(&draw->info->border_color, border);
1530
1548
  return border;
1531
1549
  }
@@ -1628,30 +1646,12 @@ get_type_metrics(int argc, VALUE *argv, VALUE self, gvl_function_t fp)
1628
1646
  rb_raise(rb_eArgError, "no text to measure");
1629
1647
  }
1630
1648
 
1631
- TypedData_Get_Struct(self, Draw, &rm_draw_data_type, draw);
1632
- #if defined(IMAGEMAGICK_7)
1633
- exception = AcquireExceptionInfo();
1634
- draw->info->text = InterpretImageProperties(NULL, image, text, exception);
1635
- if (rm_should_raise_exception(exception, RetainExceptionRetention))
1636
- {
1637
- if (draw->info->text)
1638
- {
1639
- magick_free(draw->info->text);
1640
- }
1641
- rm_raise_exception(exception);
1642
- }
1643
- #else
1644
- draw->info->text = InterpretImageProperties(NULL, image, text);
1645
- #endif
1646
- if (!draw->info->text)
1647
- {
1648
- #if defined(IMAGEMAGICK_7)
1649
- DestroyExceptionInfo(exception);
1650
- #endif
1651
- rb_raise(rb_eArgError, "no text to measure");
1652
- }
1649
+ draw = get_draw(self);
1650
+ // Measured as given: see the comment in Draw_annotate().
1651
+ draw->info->text = ConstantString(text);
1653
1652
 
1654
1653
  #if defined(IMAGEMAGICK_7)
1654
+ exception = AcquireExceptionInfo();
1655
1655
  GVL_STRUCT_TYPE(get_type_metrics) args = { image, draw->info, &metrics, exception };
1656
1656
  #else
1657
1657
  GVL_STRUCT_TYPE(get_type_metrics) args = { image, draw->info, &metrics };
@@ -219,7 +219,7 @@ Enum_spaceship(VALUE self, VALUE other)
219
219
  /**
220
220
  * Bitwise OR for enums
221
221
  *
222
- * @param another [Magick::Enum] the another enum
222
+ * @param another [Magick::Enum] the other enum
223
223
  * @return [Magick::Enum] new Enum instance
224
224
  */
225
225
  VALUE
@@ -361,7 +361,7 @@ Enum_type_values(VALUE klass)
361
361
  *
362
362
  * @param klass the class type
363
363
  * @param value the value for enum
364
- * @return a enumerator
364
+ * @return an enumerator
365
365
  */
366
366
 
367
367
  VALUE
@@ -541,7 +541,7 @@ CompressionType_find(CompressionType ct)
541
541
 
542
542
 
543
543
  /**
544
- * Returns a DisposeType enum object for the specified value..new.
544
+ * Returns a DisposeType enum object for the specified value.
545
545
  *
546
546
  * No Ruby usage (internal function)
547
547
  *
@@ -661,7 +661,7 @@ PixelInterpolateMethod_find(PixelInterpolateMethod interpolate)
661
661
 
662
662
 
663
663
  /**
664
- * Construct an RenderingIntent enum object for the specified value.
664
+ * Construct a RenderingIntent enum object for the specified value.
665
665
  *
666
666
  * No Ruby usage (internal function)
667
667
  *
@@ -785,7 +785,7 @@ StyleType_find(StyleType style)
785
785
  *
786
786
  * No Ruby usage (internal function)
787
787
  *
788
- * @param style theVirtualPixelMethod
788
+ * @param style the VirtualPixelMethod
789
789
  * @return a new VirtualPixelMethod enumerator
790
790
  */
791
791
  VALUE