rmagick 7.1.5 → 7.1.7

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: b0652dce5387352787bef0e59b1548a5c36b6f80a66b8ec9ab4c7f03828f5d0f
4
- data.tar.gz: 6d286a5f5649816c5cf1f821969783fb6ebef9f5a81b4502719f498869f926f9
3
+ metadata.gz: 66dc89800cb00f2289dabc151894c15c87bfb01d231e59a65e416ea340891806
4
+ data.tar.gz: a77148f0f14029e5eaab407e4c7a92b2f001c3d1b7d2a3bccaed2895f76a73a8
5
5
  SHA512:
6
- metadata.gz: 4ab4ce5e26eed8275df1cdc1130da0c5bb717fdca8f472c89b26a5aea37579a17e9bc4d9a34aa0c272a4b26242c03c2acbd9b690484b503ddfdf7220fc075cf2
7
- data.tar.gz: c5ee3eddbed492432ae70f34680a3d9a768fec6ba33bd3c97eca98262f29fd81d2037f56f8e8018ee0afc0a43896ad7186ee5f779da559f9d14ccc05aa28c3cb
6
+ metadata.gz: d39124bed163f3af7ac90f2a40476735e653a957307e9c4bb88c96f13899c6644d7af005c7a7546028bec6652c0cc0f5af2f18c3fcbc0148d660c16fa3543cbd
7
+ data.tar.gz: eb6b1420cf8b1d112931dc4467163817eac4ca3f87ca4e52b7b7d0e4eef322ab062554eb9e71545553ea2352a512d208e68512a0994b98ce6da3edbad09ec589
data/CHANGELOG.md CHANGED
@@ -3,6 +3,37 @@
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.7
7
+
8
+ Bug Fixes
9
+
10
+ * Fix installing the gem with the system Ruby on Ubuntu 26.04, whose LDFLAGS contain '%' (#1927)
11
+
12
+ ## RMagick 7.1.6
13
+
14
+ > [!IMPORTANT]
15
+ > A `Magick::KernelInfo` kernel string starting with `@` now raises `ArgumentError`.
16
+ >
17
+ > `KernelInfo.new`, and `Image#morphology` and `#morphology_channel` when given a string kernel, passed the string to ImageMagick, which reads the kernel from the file a string starting with `@` names. A kernel string taken from user input could therefore read any file the process can open: a file holding a kernel definition changed the result image, and with ImageMagick 7 the error told whether the path exists. The message is "the kernel must not name a file with '@'", as for the other values that reject `@`.
18
+
19
+ Breaking Changes
20
+
21
+ * Reject a KernelInfo kernel string beginning with '@' instead of reading that file (#1895)
22
+
23
+ Improvements
24
+
25
+ * Add Magick.resource_usage to read how much of a resource ImageMagick uses (#1880)
26
+ * Add the methods, classes and fields missing from the API reference, and fix the entries that disagreed with the code (#1881, #1883-#1891, #1893, #1897, #1899)
27
+
28
+ Bug Fixes
29
+
30
+ * Fix RBS signatures that disagree with the implementation (#1901)
31
+ * Fix clone of Image, Draw, Pixel, KernelInfo and ImageList rejecting the freeze keyword (#1900)
32
+ * Fix resample and resize sharpening the image at blur 1.0 with ImageMagick 7 (#1898)
33
+ * Fix KernelInfo.builtin leaving out ImageMagick's default arguments (#1896)
34
+ * Fix mutating a frozen Magick::KernelInfo and a leak in KernelInfo#initialize (#1894)
35
+ * Fix TypeMetric#underline_thickness returning the underline position (#1892)
36
+
6
37
  ## RMagick 7.1.5
7
38
 
8
39
  > [!IMPORTANT]
@@ -134,7 +134,7 @@ module RMagick
134
134
  def exit_failure(msg)
135
135
  msg = "ERROR: #{msg}"
136
136
 
137
- Logging.message msg
137
+ Logging.message "%s", msg
138
138
 
139
139
  @stdout.puts "\n\n"
140
140
  if ENV['NO_COLOR']
@@ -172,11 +172,11 @@ module RMagick
172
172
  return if packages.empty?
173
173
 
174
174
  msg = "\nDetected ImageMagick packages:\n"
175
- Logging.message msg
176
- message msg
175
+ Logging.message "%s", msg
176
+ message "%s", msg
177
177
  package_paths = packages.map { |package| "- #{PKGConfig.package_config(package).pc_path}" }.join("\n")
178
- Logging.message package_paths + "\n\n"
179
- message package_paths + "\n\n"
178
+ Logging.message "%s", package_paths + "\n\n"
179
+ message "%s", package_paths + "\n\n"
180
180
 
181
181
  if installed_im6_packages.any? && installed_im7_packages.any?
182
182
  checking_for('forced use of ImageMagick 6') do
@@ -192,8 +192,8 @@ module RMagick
192
192
 
193
193
  if packages.length > 1
194
194
  msg = "\nWarning: Found more than one ImageMagick installation. This could cause problems at runtime.\n\n"
195
- Logging.message msg
196
- message msg
195
+ Logging.message "%s", msg
196
+ message "%s", msg
197
197
  end
198
198
 
199
199
  packages.first
@@ -201,8 +201,8 @@ module RMagick
201
201
 
202
202
  def search_paths_for_windows
203
203
  msg = 'searching PATH for the ImageMagick library...'
204
- Logging.message msg
205
- message msg + "\n"
204
+ Logging.message "%s", msg
205
+ message "%s", msg + "\n"
206
206
 
207
207
  found = false
208
208
  dir_paths = {}
@@ -261,7 +261,7 @@ module RMagick
261
261
  # Ensure minimum ImageMagick version
262
262
  # Check minimum ImageMagick version if possible
263
263
  checking_for("outdated ImageMagick version") do
264
- Logging.message("Detected ImageMagick version: #{$magick_version}\n")
264
+ Logging.message("%s", "Detected ImageMagick version: #{$magick_version}\n")
265
265
 
266
266
  required_version = im_version_at_least?('7.0.0') ? Magick::MIN_IM7_VERSION : Magick::MIN_IM6_VERSION
267
267
 
@@ -354,8 +354,8 @@ module RMagick
354
354
 
355
355
  END_SUMMARY
356
356
 
357
- Logging.message summary
358
- message summary
357
+ Logging.message "%s", summary
358
+ message "%s", summary
359
359
  end
360
360
  end
361
361
  end
@@ -363,8 +363,8 @@ end
363
363
  extconf = RMagick::Extconf.new
364
364
  at_exit do
365
365
  msg = "Configured compile options: #{extconf.configured_compile_options}"
366
- Logging.message msg
367
- message msg + "\n"
366
+ Logging.message "%s", msg
367
+ message "%s", msg + "\n"
368
368
  end
369
369
  extconf.create_makefile_file
370
370
  extconf.create_compile_flags_txt
@@ -196,35 +196,24 @@ Magick_init_formats(VALUE klass ATTRIBUTE_UNUSED)
196
196
 
197
197
 
198
198
  /**
199
- * Get/set resource limits. If a limit is specified the old limit is set to the
200
- * new value. Either way the current/old limit is returned.
201
- *
202
- * @overload limit_resource(resource)
203
- * Get resource limits.
204
- * @param resource [String, Symbol] the type of resource
199
+ * Convert the name of a resource to its ResourceType.
205
200
  *
206
- * @overload limit_resource(resource, limit)
207
- * Set resource limits.
208
- * @param resource [String, Symbol] the type of resource
209
- * @param limit [Numeric] the new limit number
201
+ * No Ruby usage (internal function)
210
202
  *
211
- * @return [Numeric] the old limit.
203
+ * @param resource the name of the resource, a String or Symbol
204
+ * @return the resource type, or UndefinedResource for nil or an empty string
212
205
  */
213
- VALUE
214
- Magick_limit_resource(int argc, VALUE *argv, VALUE klass)
206
+ static ResourceType
207
+ resource_type(VALUE resource)
215
208
  {
216
- VALUE resource, limit;
217
209
  ResourceType res = UndefinedResource;
218
210
  char *str;
219
211
  ID id;
220
- MagickSizeType cur_limit;
221
-
222
- rb_scan_args(argc, argv, "11", &resource, &limit);
223
212
 
224
213
  switch (TYPE(resource))
225
214
  {
226
215
  case T_NIL:
227
- return klass;
216
+ break;
228
217
 
229
218
  case T_SYMBOL:
230
219
  id = (ID)SYM2ID(resource);
@@ -262,7 +251,7 @@ Magick_limit_resource(int argc, VALUE *argv, VALUE klass)
262
251
  str = StringValueCStr(resource);
263
252
  if (*str == '\0')
264
253
  {
265
- return klass;
254
+ break;
266
255
  }
267
256
  else if (rm_strcasecmp("area", str) == 0)
268
257
  {
@@ -297,6 +286,40 @@ Magick_limit_resource(int argc, VALUE *argv, VALUE klass)
297
286
 
298
287
  RB_GC_GUARD(resource);
299
288
 
289
+ return res;
290
+ }
291
+
292
+
293
+ /**
294
+ * Get/set resource limits. If a limit is specified the old limit is set to the
295
+ * new value. Either way the current/old limit is returned.
296
+ *
297
+ * @overload limit_resource(resource)
298
+ * Get resource limits.
299
+ * @param resource [String, Symbol] the type of resource
300
+ *
301
+ * @overload limit_resource(resource, limit)
302
+ * Set resource limits.
303
+ * @param resource [String, Symbol] the type of resource
304
+ * @param limit [Numeric] the new limit number
305
+ *
306
+ * @return [Numeric] the old limit.
307
+ */
308
+ VALUE
309
+ Magick_limit_resource(int argc, VALUE *argv, VALUE klass)
310
+ {
311
+ VALUE resource, limit;
312
+ ResourceType res;
313
+ MagickSizeType cur_limit;
314
+
315
+ rb_scan_args(argc, argv, "11", &resource, &limit);
316
+
317
+ res = resource_type(resource);
318
+ if (res == UndefinedResource)
319
+ {
320
+ return klass;
321
+ }
322
+
300
323
  cur_limit = GetMagickResourceLimit(res);
301
324
 
302
325
  if (argc > 1)
@@ -310,6 +333,37 @@ Magick_limit_resource(int argc, VALUE *argv, VALUE klass)
310
333
  }
311
334
 
312
335
 
336
+ /**
337
+ * Get the amount of a resource that ImageMagick is using now. The memory, map
338
+ * and disk resources are in bytes. Most of them are the pixel caches of all
339
+ * images, including those of Image objects that are no longer referenced but
340
+ * have not been garbage collected yet. ImageMagick also counts blobs that it
341
+ * maps into memory and a few internal buffers, but not other memory it
342
+ * allocates.
343
+ *
344
+ * The area resource is the number of pixels of the last pixel cache that was
345
+ * checked against its limit, not a total.
346
+ *
347
+ * @param resource [String, Symbol] the type of resource
348
+ * @return [Numeric] the amount in use
349
+ * @see limit_resource
350
+ * @example
351
+ * GC.start if Magick.resource_usage(:memory) > 1024**3
352
+ */
353
+ VALUE
354
+ Magick_resource_usage(VALUE klass ATTRIBUTE_UNUSED, VALUE resource)
355
+ {
356
+ ResourceType res = resource_type(resource);
357
+
358
+ if (res == UndefinedResource)
359
+ {
360
+ rb_raise(rb_eArgError, "no resource given");
361
+ }
362
+
363
+ return ULL2NUM(GetMagickResource(res));
364
+ }
365
+
366
+
313
367
  /**
314
368
  * Set the amount of free memory allocated for the pixel cache. Once this
315
369
  * threshold is exceeded, all subsequent pixel cache operations are to/from
@@ -555,6 +555,7 @@ extern VALUE Magick_colors(VALUE);
555
555
  extern VALUE Magick_fonts(VALUE);
556
556
  extern VALUE Magick_init_formats(VALUE);
557
557
  extern VALUE Magick_limit_resource(int, VALUE *, VALUE);
558
+ extern VALUE Magick_resource_usage(VALUE, VALUE);
558
559
  extern VALUE Magick_set_cache_threshold(VALUE, VALUE);
559
560
  extern VALUE Magick_set_log_event_mask(int, VALUE *, VALUE);
560
561
  extern VALUE Magick_set_log_format(VALUE, VALUE);
@@ -587,10 +588,8 @@ ATTR_WRITER(Draw, tile)
587
588
  ATTR_WRITER(Draw, undercolor)
588
589
  extern VALUE Draw_alloc(VALUE);
589
590
  extern VALUE Draw_annotate(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE);
590
- extern VALUE Draw_clone(VALUE);
591
591
  extern VALUE Draw_composite(int, VALUE *, VALUE);
592
592
  extern VALUE Draw_draw(VALUE, VALUE);
593
- extern VALUE Draw_dup(VALUE);
594
593
  extern VALUE Draw_get_multiline_type_metrics(int, VALUE *, VALUE);
595
594
  extern VALUE Draw_get_type_metrics(int, VALUE *, VALUE);
596
595
  extern VALUE Draw_init_copy(VALUE, VALUE);
@@ -725,7 +724,7 @@ extern VALUE KernelInfo_initialize(VALUE, VALUE);
725
724
  extern VALUE KernelInfo_unity_add(VALUE, VALUE);
726
725
  extern VALUE KernelInfo_scale(VALUE, VALUE, VALUE);
727
726
  extern VALUE KernelInfo_scale_geometry(VALUE, VALUE);
728
- extern VALUE KernelInfo_clone(VALUE);
727
+ extern VALUE KernelInfo_init_copy(VALUE, VALUE);
729
728
 
730
729
  extern VALUE KernelInfo_builtin(VALUE, VALUE, VALUE);
731
730
 
@@ -840,7 +839,6 @@ extern VALUE Image_channel_mean(int, VALUE *, VALUE);
840
839
  extern VALUE Image_channel_entropy(int, VALUE *, VALUE);
841
840
  extern VALUE Image_charcoal(int, VALUE *, VALUE);
842
841
  extern VALUE Image_chop(VALUE, VALUE, VALUE, VALUE, VALUE);
843
- extern VALUE Image_clone(VALUE);
844
842
  extern VALUE Image_clut_channel(int, VALUE *, VALUE);
845
843
  extern VALUE Image_color_flood_fill(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE);
846
844
  extern VALUE Image_color_histogram(VALUE);
@@ -882,7 +880,6 @@ extern VALUE Image_dissolve(int, VALUE *, VALUE);
882
880
  extern VALUE Image_distort(int, VALUE *, VALUE);
883
881
  extern VALUE Image_distortion_channel(int, VALUE *, VALUE);
884
882
  extern VALUE Image__dump(VALUE, VALUE);
885
- extern VALUE Image_dup(VALUE);
886
883
  extern VALUE Image_each_profile(VALUE);
887
884
  extern VALUE Image_edge(int, VALUE *, VALUE);
888
885
  extern VALUE Image_emboss(int, VALUE *, VALUE);
@@ -1053,8 +1050,6 @@ ATTR_ACCESSOR(Pixel, yellow)
1053
1050
  ATTR_ACCESSOR(Pixel, black)
1054
1051
  extern VALUE Pixel_alloc(VALUE);
1055
1052
  extern VALUE Pixel_case_eq(VALUE, VALUE);
1056
- extern VALUE Pixel_clone(VALUE);
1057
- extern VALUE Pixel_dup(VALUE);
1058
1053
  extern VALUE Pixel_eql_q(VALUE, VALUE);
1059
1054
  extern VALUE Pixel_fcmp(int, VALUE *, VALUE);
1060
1055
  extern VALUE Pixel_from_color(VALUE, VALUE);
@@ -1010,26 +1010,6 @@ VALUE Draw_annotate(
1010
1010
  }
1011
1011
 
1012
1012
 
1013
- /**
1014
- * Clones this object.
1015
- *
1016
- * @return [Magick::Draw] the cloned object
1017
- */
1018
- VALUE
1019
- Draw_clone(VALUE self)
1020
- {
1021
- VALUE clone;
1022
-
1023
- clone = Draw_dup(self);
1024
- if (OBJ_FROZEN(self))
1025
- {
1026
- OBJ_FREEZE(clone);
1027
- }
1028
-
1029
- RB_GC_GUARD(clone);
1030
-
1031
- return clone;
1032
- }
1033
1013
 
1034
1014
 
1035
1015
  /**
@@ -1172,26 +1152,6 @@ Draw_draw(VALUE self, VALUE image_arg)
1172
1152
  }
1173
1153
 
1174
1154
 
1175
- /**
1176
- * Duplicate a Draw object.
1177
- *
1178
- * - Constructs a new Draw object, then calls initialize_copy.
1179
- *
1180
- * @return [Magick::Draw] the duplicated object
1181
- */
1182
- VALUE
1183
- Draw_dup(VALUE self)
1184
- {
1185
- Draw *draw;
1186
- VALUE dup;
1187
-
1188
- draw = ALLOC(Draw);
1189
- memset(draw, 0, sizeof(Draw));
1190
- dup = TypedData_Wrap_Struct(CLASS_OF(self), &rm_draw_data_type, draw);
1191
- RB_GC_GUARD(dup);
1192
-
1193
- return rb_funcall(dup, rm_ID_initialize_copy, 1, self);
1194
- }
1195
1155
 
1196
1156
 
1197
1157
  /**
@@ -2714,27 +2714,6 @@ Image_chromaticity_eq(VALUE self, VALUE chroma)
2714
2714
  }
2715
2715
 
2716
2716
 
2717
- /**
2718
- * Same as {Magick::Image#dup} except the frozen state of the original is propagated to the new
2719
- * copy.
2720
- *
2721
- * @return [Magick::Image] a clone of this object
2722
- */
2723
- VALUE
2724
- Image_clone(VALUE self)
2725
- {
2726
- VALUE clone;
2727
-
2728
- clone = Image_dup(self);
2729
- if (OBJ_FROZEN(self))
2730
- {
2731
- OBJ_FREEZE(clone);
2732
- }
2733
-
2734
- RB_GC_GUARD(clone);
2735
-
2736
- return clone;
2737
- }
2738
2717
 
2739
2718
 
2740
2719
  /**
@@ -3897,7 +3876,8 @@ composite_channel(int bang, int argc, VALUE *argv, VALUE self)
3897
3876
 
3898
3877
 
3899
3878
  /**
3900
- * Composite the source over the destination image channel as dictated by the affine transform.
3879
+ * Composite the source over the destination image, changing only the specified channels of the
3880
+ * destination. The arguments before the channels are the same as those of {Image#composite}.
3901
3881
  *
3902
3882
  * @overload composite_channel(image, x_off, y_off, composite_op, channel = Magick::AllChannels)
3903
3883
  * @param image [Magick::Image, Magick::ImageList] Either an imagelist or an image. If an
@@ -3970,8 +3950,8 @@ Image_composite_channel(int argc, VALUE *argv, VALUE self)
3970
3950
 
3971
3951
 
3972
3952
  /**
3973
- * Composite the source over the destination image channel as dictated by the affine transform.
3974
- * In-place form of {Image#composite_channel}.
3953
+ * Composite the source over the destination image, changing only the specified channels of the
3954
+ * destination. In-place form of {Image#composite_channel}.
3975
3955
  *
3976
3956
  * @overload composite_channel!(image, x_off, y_off, composite_op, channel = Magick::AllChannels)
3977
3957
  * @param image [Magick::Image, Magick::ImageList] Either an imagelist or an image. If an
@@ -4033,7 +4013,7 @@ Image_composite_channel(int argc, VALUE *argv, VALUE self)
4033
4013
  * @param composite_op [Magick::CompositeOperator] the composite operator
4034
4014
  * @param *channels [Magick::ChannelType] one or more ChannelType arguments.
4035
4015
  *
4036
- * @return [Magick::Image] a new image
4016
+ * @return [Magick::Image] self
4037
4017
  * @see Image#composite_channel
4038
4018
  * @see Image#composite!
4039
4019
  */
@@ -6222,22 +6202,6 @@ Image__dump(VALUE self, VALUE depth ATTRIBUTE_UNUSED)
6222
6202
  }
6223
6203
 
6224
6204
 
6225
- /**
6226
- * Duplicates an image.
6227
- *
6228
- * @return [Magick::Image] a new image
6229
- */
6230
- VALUE
6231
- Image_dup(VALUE self)
6232
- {
6233
- VALUE dup;
6234
-
6235
- rm_check_destroyed(self);
6236
- dup = TypedData_Wrap_Struct(CLASS_OF(self), &rm_image_data_type, NULL);
6237
- RB_GC_GUARD(dup);
6238
-
6239
- return rb_funcall(dup, rm_ID_initialize_copy, 1, self);
6240
- }
6241
6205
 
6242
6206
 
6243
6207
  /**
@@ -8697,11 +8661,12 @@ Image_level2(int argc, VALUE *argv, VALUE self)
8697
8661
  /**
8698
8662
  * Similar to {Image#level2} but applies to a single channel only.
8699
8663
  *
8700
- * @overload level_channel(aChannelType, black = 0.0, white = 1.0, gamma = Magick::QuantumRange)
8664
+ * @overload level_channel(aChannelType, black = 0.0, white = Magick::QuantumRange - black, gamma = 1.0)
8701
8665
  * @param aChannelType [Magick::ChannelType] A ChannelType value.
8702
8666
  * @param black [Numeric] A black point level in the range 0..QuantumRange.
8703
8667
  * @param white [Numeric] A white point level in the range 0..QuantumRange.
8704
- * @param gamma [Numeric] A gamma correction in the range 0.0 - 10.0.
8668
+ * @param gamma [Numeric] A gamma correction. Unlike with {Image#level}, a value greater than 10.0 is
8669
+ * used as given.
8705
8670
  * @return [Magick::Image] a new image
8706
8671
  * @see Image#level2
8707
8672
  */
@@ -12065,35 +12030,71 @@ Image_rendering_intent_eq(VALUE self, VALUE ri)
12065
12030
 
12066
12031
  #if defined(IMAGEMAGICK_7)
12067
12032
  /**
12068
- * Create new blurred image.
12033
+ * Return the image to resize or resample with the given blur factor.
12034
+ *
12035
+ * ImageMagick 7 dropped the blur argument of ResizeImage() and ResampleImage(). Their filter
12036
+ * reads the factor from the "filter:blur" artifact instead, as ImageMagick 6 did on top of the
12037
+ * argument, so the factor is set there, multiplied by any "filter:blur" the image already has.
12038
+ * A factor of 1.0 leaves the filter as it is.
12069
12039
  *
12070
12040
  * No Ruby usage (internal function)
12071
12041
  *
12072
12042
  * @param image the image
12073
- * @param blur the blur
12074
- * @return NULL if not apply blur, otherwise a new image
12043
+ * @param blur the blur factor: > 1.0 blurs and < 1.0 sharpens
12044
+ * @return the image itself when blur is 1.0, otherwise a clone that shares its pixels and has
12045
+ * the artifact set, which the caller destroys
12075
12046
  */
12076
12047
  static Image*
12077
- blurred_image(Image* image, double blur)
12048
+ image_with_filter_blur(Image* image, double blur)
12078
12049
  {
12079
- ExceptionInfo *exception;
12080
- Image *new_image;
12050
+ Image *clone;
12051
+ const char *artifact;
12052
+ char value[MaxTextExtent];
12081
12053
 
12082
- exception = AcquireExceptionInfo();
12083
- if (blur > 1.0)
12054
+ if (blur == 1.0)
12084
12055
  {
12085
- GVL_STRUCT_TYPE(BlurImage) args = { image, blur, blur, exception };
12086
- new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(BlurImage), &args);
12056
+ return image;
12087
12057
  }
12088
- else
12058
+
12059
+ artifact = GetImageArtifact(image, "filter:blur");
12060
+ if (artifact)
12089
12061
  {
12090
- GVL_STRUCT_TYPE(SharpenImage) args = { image, blur, blur, exception };
12091
- new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SharpenImage), &args);
12062
+ blur *= InterpretLocaleValue(artifact, (char **)NULL);
12092
12063
  }
12093
- rm_check_exception(exception, new_image, DestroyOnError);
12094
- DestroyExceptionInfo(exception);
12064
+ snprintf(value, sizeof(value), "%.17g", blur);
12095
12065
 
12096
- return new_image;
12066
+ clone = rm_clone_image(image);
12067
+ if (!SetImageArtifact(clone, "filter:blur", value))
12068
+ {
12069
+ DestroyImage(clone);
12070
+ rb_raise(rb_eNoMemError, "not enough memory to continue");
12071
+ }
12072
+ return clone;
12073
+ }
12074
+
12075
+
12076
+ /**
12077
+ * Give the result of a resize or resample the "filter:blur" artifact of the original image, or
12078
+ * none, instead of the one image_with_filter_blur() set on the image it was made from.
12079
+ *
12080
+ * No Ruby usage (internal function)
12081
+ *
12082
+ * @param result the result image
12083
+ * @param image the original image
12084
+ */
12085
+ static void
12086
+ restore_filter_blur(Image* result, Image* image)
12087
+ {
12088
+ const char *artifact = GetImageArtifact(image, "filter:blur");
12089
+
12090
+ if (artifact)
12091
+ {
12092
+ (void) SetImageArtifact(result, "filter:blur", artifact);
12093
+ }
12094
+ else
12095
+ {
12096
+ (void) DeleteImageArtifact(result, "filter:blur");
12097
+ }
12097
12098
  }
12098
12099
  #endif
12099
12100
 
@@ -12178,12 +12179,22 @@ resample(int bang, int argc, VALUE *argv, VALUE self)
12178
12179
  break;
12179
12180
  }
12180
12181
 
12182
+ #if defined(IMAGEMAGICK_7)
12183
+ // Before AcquireExceptionInfo(), since it can raise
12184
+ Image *source = image_with_filter_blur(image, blur);
12185
+ #endif
12181
12186
  exception = AcquireExceptionInfo();
12182
12187
  #if defined(IMAGEMAGICK_7)
12183
- Image *preprocess = blurred_image(image, blur);
12184
- GVL_STRUCT_TYPE(ResampleImage) args = { preprocess, x_resolution, y_resolution, filter, exception };
12188
+ GVL_STRUCT_TYPE(ResampleImage) args = { source, x_resolution, y_resolution, filter, exception };
12185
12189
  new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(ResampleImage), &args);
12186
- DestroyImage(preprocess);
12190
+ if (source != image)
12191
+ {
12192
+ if (new_image)
12193
+ {
12194
+ restore_filter_blur(new_image, image);
12195
+ }
12196
+ DestroyImage(source);
12197
+ }
12187
12198
  #else
12188
12199
  GVL_STRUCT_TYPE(ResampleImage) args = { image, x_resolution, y_resolution, filter, blur, exception };
12189
12200
  new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(ResampleImage), &args);
@@ -12213,12 +12224,12 @@ resample(int bang, int argc, VALUE *argv, VALUE self)
12213
12224
  * the original resolution of the image must be specified via the density attribute prior to
12214
12225
  * specifying the resample resolution.
12215
12226
  *
12216
- * @overload resample(x_resolution = 72.0, y_resolution = 72.0, filter = self.filter, blur = self.blur)
12227
+ * @overload resample(x_resolution = 72.0, y_resolution = x_resolution, filter = self.filter, blur = 1.0)
12217
12228
  * @param x_resolution [Numeric] the target horizontal resolution.
12218
12229
  * @param y_resolution [Numeric] the target vertical resolution.
12219
12230
  * @param filter [Magick::FilterType] the filter type
12220
- * @param blur [Numeric] the blur size
12221
- * @return [Magick] a new image
12231
+ * @param blur [Numeric] the blur factor of the filter: > 1.0 blurs and < 1.0 sharpens
12232
+ * @return [Magick::Image] a new image
12222
12233
  * @see Image#resample!
12223
12234
  */
12224
12235
  VALUE
@@ -12233,12 +12244,12 @@ Image_resample(int argc, VALUE *argv, VALUE self)
12233
12244
  * Resample image to specified horizontal resolution, vertical resolution, filter and blur factor.
12234
12245
  * In-place form of {Image#resample}.
12235
12246
  *
12236
- * @overload resample!(x_resolution = 72.0, y_resolution = 72.0, filter = self.filter, blur = self.blur)
12247
+ * @overload resample!(x_resolution = 72.0, y_resolution = x_resolution, filter = self.filter, blur = 1.0)
12237
12248
  * @param x_resolution [Numeric] the target horizontal resolution.
12238
12249
  * @param y_resolution [Numeric] the target vertical resolution.
12239
12250
  * @param filter [Magick::FilterType] the filter type
12240
- * @param blur [Numeric] the blur size
12241
- * @return [Magick] a new image
12251
+ * @param blur [Numeric] the blur factor of the filter: > 1.0 blurs and < 1.0 sharpens
12252
+ * @return [Magick::Image] self
12242
12253
  * @see Image#resample
12243
12254
  */
12244
12255
  VALUE
@@ -12319,14 +12330,21 @@ resize(int bang, int argc, VALUE *argv, VALUE self)
12319
12330
  break;
12320
12331
  }
12321
12332
 
12333
+ #if defined(IMAGEMAGICK_7)
12334
+ // Before AcquireExceptionInfo(), since it can raise
12335
+ Image *source = image_with_filter_blur(image, blur);
12336
+ #endif
12322
12337
  exception = AcquireExceptionInfo();
12323
12338
  #if defined(IMAGEMAGICK_7)
12324
- Image *preprocess = (argc == 4) ? blurred_image(image, blur) : image;
12325
- GVL_STRUCT_TYPE(ResizeImage) args = { preprocess, columns, rows, filter, exception };
12339
+ GVL_STRUCT_TYPE(ResizeImage) args = { source, columns, rows, filter, exception };
12326
12340
  new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(ResizeImage), &args);
12327
- if (argc == 4)
12341
+ if (source != image)
12328
12342
  {
12329
- DestroyImage(preprocess);
12343
+ if (new_image)
12344
+ {
12345
+ restore_filter_blur(new_image, image);
12346
+ }
12347
+ DestroyImage(source);
12330
12348
  }
12331
12349
  #else
12332
12350
  GVL_STRUCT_TYPE(ResizeImage) args = { image, columns, rows, filter, blur, exception };
@@ -12359,7 +12377,7 @@ resize(int bang, int argc, VALUE *argv, VALUE self)
12359
12377
  * @param cols [Numeric] The desired width
12360
12378
  * @param rows [Numeric] The desired height.
12361
12379
  * @param filter [Magick::FilterType] the filter type
12362
- * @param blur [Numeric] the blur size
12380
+ * @param blur [Numeric] the blur factor of the filter: > 1.0 blurs and < 1.0 sharpens
12363
12381
  *
12364
12382
  * @return [Magick::Image] a new image
12365
12383
  * @see Image#resize!
@@ -12385,7 +12403,7 @@ Image_resize(int argc, VALUE *argv, VALUE self)
12385
12403
  * @param cols [Numeric] The desired width
12386
12404
  * @param rows [Numeric] The desired height.
12387
12405
  * @param filter [Magick::FilterType] the filter type
12388
- * @param blur [Numeric] the blur size
12406
+ * @param blur [Numeric] the blur factor of the filter: > 1.0 blurs and < 1.0 sharpens
12389
12407
  *
12390
12408
  * @return [Magick::Image] a new image
12391
12409
  * @see Image#resize!
@@ -14603,8 +14621,8 @@ Image_ticks_per_second_eq(VALUE self, VALUE tps)
14603
14621
  * @param red_alpha [Numeric] the red value
14604
14622
  * @param green_alpha [Numeric] the green value
14605
14623
  * @param blue_alpha [Numeric] the blue value
14606
- * @param alpha_alpha [Numeric] the alpha value
14607
- * @return a new image
14624
+ * @param alpha_alpha [Numeric] accepted but ignored: TintImage leaves the alpha channel unchanged
14625
+ * @return [Magick::Image] a new image
14608
14626
  */
14609
14627
  VALUE
14610
14628
  Image_tint(int argc, VALUE *argv, VALUE self)
@@ -15255,7 +15273,8 @@ VALUE Image_image_type_eq(VALUE self, VALUE image_type)
15255
15273
 
15256
15274
 
15257
15275
  /**
15258
- * Removes an artifact from the image and returns its value.
15276
+ * Removes an artifact from the image. The same as {Image#define} with a nil value, except that it
15277
+ * returns self and that the name must be a String.
15259
15278
  *
15260
15279
  * @param artifact [String] the artifact
15261
15280
  * @return [Magick::Image] self