rmagick 5.4.4 → 6.0.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/ImageMagick6/devcontainer.json +1 -1
  3. data/.devcontainer/devcontainer.json +1 -1
  4. data/.github/workflows/ci.yml +41 -31
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +36 -9
  7. data/.rubocop_todo.yml +369 -187
  8. data/CHANGELOG.md +77 -0
  9. data/Gemfile +14 -0
  10. data/README.md +3 -3
  11. data/Rakefile +12 -1
  12. data/before_install_linux.sh +1 -11
  13. data/before_install_osx.sh +5 -7
  14. data/ext/RMagick/extconf.rb +58 -68
  15. data/ext/RMagick/rmagick.h +7 -12
  16. data/ext/RMagick/rmdraw.cpp +10 -20
  17. data/ext/RMagick/rmfill.cpp +4 -4
  18. data/ext/RMagick/rmilist.cpp +10 -2
  19. data/ext/RMagick/rmimage.cpp +342 -344
  20. data/ext/RMagick/rminfo.cpp +22 -21
  21. data/ext/RMagick/rmkinfo.cpp +5 -18
  22. data/ext/RMagick/rmmain.cpp +42 -91
  23. data/ext/RMagick/rmmontage.cpp +5 -5
  24. data/ext/RMagick/rmpixel.cpp +3 -3
  25. data/ext/RMagick/rmutil.cpp +58 -89
  26. data/lib/rmagick/version.rb +3 -3
  27. data/lib/rmagick.rb +1 -1
  28. data/lib/rmagick_internal.rb +111 -103
  29. data/lib/rvg/container.rb +3 -3
  30. data/lib/rvg/embellishable.rb +7 -3
  31. data/lib/rvg/misc.rb +15 -15
  32. data/lib/rvg/rvg.rb +6 -6
  33. data/lib/rvg/stretchable.rb +2 -2
  34. data/lib/rvg/stylable.rb +2 -2
  35. data/lib/rvg/transformable.rb +1 -1
  36. data/lib/rvg/units.rb +1 -0
  37. data/rmagick.gemspec +2 -15
  38. data/sig/rmagick/_draw_common_methods.rbs +64 -0
  39. data/sig/rmagick/_image_common_methods.rbs +387 -0
  40. data/sig/rmagick/draw.rbs +38 -0
  41. data/sig/rmagick/draw_attribute.rbs +28 -0
  42. data/sig/rmagick/enum.rbs +820 -0
  43. data/sig/rmagick/error.rbs +11 -0
  44. data/sig/rmagick/fill.rbs +21 -0
  45. data/sig/rmagick/geometry.rbs +14 -0
  46. data/sig/rmagick/image.rbs +196 -0
  47. data/sig/rmagick/image_list.rbs +183 -0
  48. data/sig/rmagick/iptc.rbs +101 -0
  49. data/sig/rmagick/kernel_info.rbs +12 -0
  50. data/sig/rmagick/optional_method_arguments.rbs +10 -0
  51. data/sig/rmagick/pixel.rbs +46 -0
  52. data/sig/rmagick/struct.rbs +90 -0
  53. data/sig/rmagick.rbs +43 -0
  54. data/sig/rvg/clippath.rbs +34 -0
  55. data/sig/rvg/container.rbs +78 -0
  56. data/sig/rvg/deep_equal.rbs +48 -0
  57. data/sig/rvg/describable.rbs +30 -0
  58. data/sig/rvg/embellishable.rbs +226 -0
  59. data/sig/rvg/misc.rbs +145 -0
  60. data/sig/rvg/paint.rbs +55 -0
  61. data/sig/rvg/pathdata.rbs +77 -0
  62. data/sig/rvg/rvg.rbs +125 -0
  63. data/sig/rvg/stretchable.rbs +56 -0
  64. data/sig/rvg/stylable.rbs +66 -0
  65. data/sig/rvg/text.rbs +118 -0
  66. data/sig/rvg/transformable.rbs +59 -0
  67. data/sig/rvg/units.rbs +33 -0
  68. metadata +38 -134
@@ -10,7 +10,7 @@
10
10
  # to the classes.
11
11
  #==============================================================================
12
12
 
13
- if RUBY_PLATFORM =~ /mingw/i
13
+ if RUBY_PLATFORM.match?(/mingw/i)
14
14
  begin
15
15
  require 'ruby_installer'
16
16
  ENV['PATH'].split(File::PATH_SEPARATOR).grep(/ImageMagick/i).each do |path|
@@ -51,11 +51,11 @@ module Magick
51
51
  # p Magick.formats
52
52
  # => {"3FR"=>" r-+", "3G2"=>" r-+", "3GP"=>" r-+", "A"=>"*rw+",
53
53
  # ...
54
- def formats
54
+ def formats(&block)
55
55
  formats = init_formats
56
56
 
57
- if block_given?
58
- formats.each { |k, v| yield k, v }
57
+ if block
58
+ formats.each(&block)
59
59
  self
60
60
  else
61
61
  formats
@@ -140,7 +140,7 @@ module Magick
140
140
 
141
141
  # Convert object to a geometry string
142
142
  def to_s
143
- str = String.new
143
+ str = +''
144
144
  if @width > 0
145
145
  fmt = @width.truncate == @width ? '%d' : '%.2f'
146
146
  str << sprintf(fmt, @width)
@@ -226,18 +226,29 @@ module Magick
226
226
  private
227
227
 
228
228
  def enquote(str)
229
- if str.length > 2 && /\A(?:\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})\z/.match(str)
229
+ str = to_string(str)
230
+ if str.length > 2 && /\A(?:"[^\"]+"|'[^\']+'|\{[^\}]+\})\z/.match(str)
230
231
  str
231
232
  else
232
233
  '"' + str + '"'
233
234
  end
234
235
  end
235
236
 
236
- def check_opacity(opacity)
237
- return if opacity.is_a?(String) && opacity['%']
237
+ def to_opacity(opacity)
238
+ return opacity if opacity.is_a?(String) && opacity.end_with?('%')
238
239
 
239
240
  value = Float(opacity)
240
241
  Kernel.raise ArgumentError, 'opacity must be >= 0 and <= 1.0' if value < 0 || value > 1.0
242
+
243
+ value
244
+ end
245
+
246
+ def to_string(obj)
247
+ return obj if obj.is_a?(String)
248
+ return obj.to_s if obj.is_a?(Symbol)
249
+ return obj.to_str if obj.respond_to?(:to_str)
250
+
251
+ Kernel.raise TypeError, "no implicit conversion of #{obj.class} into String"
241
252
  end
242
253
 
243
254
  public
@@ -266,7 +277,7 @@ module Magick
266
277
 
267
278
  # Draw a bezier curve.
268
279
  def bezier(*points)
269
- if points.length.zero?
280
+ if points.empty?
270
281
  Kernel.raise ArgumentError, 'no points specified'
271
282
  elsif points.length.odd?
272
283
  Kernel.raise ArgumentError, 'odd number of arguments specified'
@@ -281,17 +292,19 @@ module Magick
281
292
 
282
293
  # Invoke a clip-path defined by def_clip_path.
283
294
  def clip_path(name)
284
- primitive "clip-path #{name}"
295
+ primitive "clip-path #{to_string(name)}"
285
296
  end
286
297
 
287
298
  # Define the clipping rule.
288
299
  def clip_rule(rule)
300
+ rule = to_string(rule)
289
301
  Kernel.raise ArgumentError, "Unknown clipping rule #{rule}" unless %w[evenodd nonzero].include?(rule.downcase)
290
302
  primitive "clip-rule #{rule}"
291
303
  end
292
304
 
293
305
  # Define the clip units
294
306
  def clip_units(unit)
307
+ unit = to_string(unit)
295
308
  Kernel.raise ArgumentError, "Unknown clip unit #{unit}" unless %w[userspace userspaceonuse objectboundingbox].include?(unit.downcase)
296
309
  primitive "clip-units #{unit}"
297
310
  end
@@ -320,7 +333,7 @@ module Magick
320
333
  # (pop) graphic-context".
321
334
  def define_clip_path(name)
322
335
  push('defs')
323
- push("clip-path \"#{name}\"")
336
+ push("clip-path #{enquote(name)}")
324
337
  push('graphic-context')
325
338
  yield
326
339
  ensure
@@ -340,7 +353,7 @@ module Magick
340
353
  # Let anything through, but the only defined argument
341
354
  # is "UTF-8". All others are apparently ignored.
342
355
  def encoding(encoding)
343
- primitive "encoding #{encoding}"
356
+ primitive "encoding #{to_string(encoding)}"
344
357
  end
345
358
 
346
359
  # Specify object fill, a color name or pattern name
@@ -352,22 +365,23 @@ module Magick
352
365
 
353
366
  # Specify fill opacity (use "xx%" to indicate percentage)
354
367
  def fill_opacity(opacity)
355
- check_opacity(opacity)
368
+ opacity = to_opacity(opacity)
356
369
  primitive "fill-opacity #{opacity}"
357
370
  end
358
371
 
359
372
  def fill_rule(rule)
373
+ rule = to_string(rule)
360
374
  Kernel.raise ArgumentError, "Unknown fill rule #{rule}" unless %w[evenodd nonzero].include?(rule.downcase)
361
375
  primitive "fill-rule #{rule}"
362
376
  end
363
377
 
364
378
  # Specify text drawing font
365
379
  def font(name)
366
- primitive "font \'#{name}\'"
380
+ primitive "font #{enquote(name)}"
367
381
  end
368
382
 
369
383
  def font_family(name)
370
- primitive "font-family \'#{name}\'"
384
+ primitive "font-family #{enquote(name)}"
371
385
  end
372
386
 
373
387
  def font_stretch(stretch)
@@ -405,38 +419,17 @@ module Magick
405
419
 
406
420
  # IM 6.5.5-8 and later
407
421
  def interline_spacing(space)
408
- begin
409
- Float(space)
410
- rescue ArgumentError
411
- Kernel.raise ArgumentError, 'invalid value for interline_spacing'
412
- rescue TypeError
413
- Kernel.raise TypeError, "can't convert #{space.class} into Float"
414
- end
415
- primitive "interline-spacing #{space}"
422
+ primitive "interline-spacing #{Float(space)}"
416
423
  end
417
424
 
418
425
  # IM 6.4.8-3 and later
419
426
  def interword_spacing(space)
420
- begin
421
- Float(space)
422
- rescue ArgumentError
423
- Kernel.raise ArgumentError, 'invalid value for interword_spacing'
424
- rescue TypeError
425
- Kernel.raise TypeError, "can't convert #{space.class} into Float"
426
- end
427
- primitive "interword-spacing #{space}"
427
+ primitive "interword-spacing #{Float(space)}"
428
428
  end
429
429
 
430
430
  # IM 6.4.8-3 and later
431
431
  def kerning(space)
432
- begin
433
- Float(space)
434
- rescue ArgumentError
435
- Kernel.raise ArgumentError, 'invalid value for kerning'
436
- rescue TypeError
437
- Kernel.raise TypeError, "can't convert #{space.class} into Float"
438
- end
439
- primitive "kerning #{space}"
432
+ primitive "kerning #{Float(space)}"
440
433
  end
441
434
 
442
435
  # Draw a line
@@ -447,7 +440,7 @@ module Magick
447
440
  # Specify drawing fill and stroke opacities. If the value is a string
448
441
  # ending with a %, the number will be multiplied by 0.01.
449
442
  def opacity(opacity)
450
- check_opacity(opacity)
443
+ opacity = to_opacity(opacity)
451
444
  primitive "opacity #{opacity}"
452
445
  end
453
446
 
@@ -455,7 +448,7 @@ module Magick
455
448
  # primitive requires that the commands be surrounded by quotes or
456
449
  # apostrophes. Here we simply use apostrophes.
457
450
  def path(cmds)
458
- primitive "path '" + cmds + "'"
451
+ primitive "path #{enquote(cmds)}"
459
452
  end
460
453
 
461
454
  # Define a pattern. In the block, call primitive methods to
@@ -463,7 +456,7 @@ module Magick
463
456
  # as the argument to the 'fill' or 'stroke' methods
464
457
  def pattern(name, x, y, width, height)
465
458
  push('defs')
466
- push("pattern #{name} " + sprintf('%g %g %g %g', x, y, width, height))
459
+ push("pattern #{to_string(name)} " + sprintf('%g %g %g %g', x, y, width, height))
467
460
  push('graphic-context')
468
461
  yield
469
462
  ensure
@@ -486,7 +479,7 @@ module Magick
486
479
 
487
480
  # Draw a polygon
488
481
  def polygon(*points)
489
- if points.length.zero?
482
+ if points.empty?
490
483
  Kernel.raise ArgumentError, 'no points specified'
491
484
  elsif points.length.odd?
492
485
  Kernel.raise ArgumentError, 'odd number of points specified'
@@ -496,7 +489,7 @@ module Magick
496
489
 
497
490
  # Draw a polyline
498
491
  def polyline(*points)
499
- if points.length.zero?
492
+ if points.empty?
500
493
  Kernel.raise ArgumentError, 'no points specified'
501
494
  elsif points.length.odd?
502
495
  Kernel.raise ArgumentError, 'odd number of points specified'
@@ -511,11 +504,10 @@ module Magick
511
504
  # pop('pattern')
512
505
 
513
506
  def pop(*what)
514
- if what.length.zero?
507
+ if what.empty?
515
508
  primitive 'pop graphic-context'
516
509
  else
517
- # to_s allows a Symbol to be used instead of a String
518
- primitive 'pop ' + what.map(&:to_s).join(' ')
510
+ primitive 'pop ' + what.map { |x| to_string(x) }.join(' ')
519
511
  end
520
512
  end
521
513
 
@@ -525,11 +517,10 @@ module Magick
525
517
  # push('gradient')
526
518
  # push('pattern')
527
519
  def push(*what)
528
- if what.length.zero?
520
+ if what.empty?
529
521
  primitive 'push graphic-context'
530
522
  else
531
- # to_s allows a Symbol to be used instead of a String
532
- primitive 'push ' + what.map(&:to_s).join(' ')
523
+ primitive 'push ' + what.map { |x| to_string(x) }.join(' ')
533
524
  end
534
525
  end
535
526
 
@@ -582,10 +573,10 @@ module Magick
582
573
 
583
574
  # Specify a stroke dash pattern
584
575
  def stroke_dasharray(*list)
585
- if list.length.zero?
576
+ if list.empty?
586
577
  primitive 'stroke-dasharray none'
587
578
  else
588
- list.each do |x|
579
+ list.map! { |x| Float(x) }.each do |x|
589
580
  Kernel.raise ArgumentError, "dash array elements must be > 0 (#{x} given)" if x <= 0
590
581
  end
591
582
  primitive "stroke-dasharray #{list.join(',')}"
@@ -598,16 +589,19 @@ module Magick
598
589
  end
599
590
 
600
591
  def stroke_linecap(value)
592
+ value = to_string(value)
601
593
  Kernel.raise ArgumentError, "Unknown linecap type: #{value}" unless %w[butt round square].include?(value.downcase)
602
594
  primitive "stroke-linecap #{value}"
603
595
  end
604
596
 
605
597
  def stroke_linejoin(value)
598
+ value = to_string(value)
606
599
  Kernel.raise ArgumentError, "Unknown linejoin type: #{value}" unless %w[round miter bevel].include?(value.downcase)
607
600
  primitive "stroke-linejoin #{value}"
608
601
  end
609
602
 
610
603
  def stroke_miterlimit(value)
604
+ value = Float(value)
611
605
  Kernel.raise ArgumentError, 'miterlimit must be >= 1' if value < 1
612
606
  primitive "stroke-miterlimit #{value}"
613
607
  end
@@ -615,7 +609,7 @@ module Magick
615
609
  # Specify opacity of stroke drawing color
616
610
  # (use "xx%" to indicate percentage)
617
611
  def stroke_opacity(opacity)
618
- check_opacity(opacity)
612
+ opacity = to_opacity(opacity)
619
613
  primitive "stroke-opacity #{opacity}"
620
614
  end
621
615
 
@@ -626,8 +620,9 @@ module Magick
626
620
 
627
621
  # Draw text at position x,y. Add quotes to text that is not already quoted.
628
622
  def text(x, y, text)
629
- Kernel.raise ArgumentError, 'missing text argument' if text.to_s.empty?
630
- if text.length > 2 && /\A(?:\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})\z/.match(text)
623
+ text = to_string(text)
624
+ Kernel.raise ArgumentError, 'missing text argument' if text.empty?
625
+ if text.length > 2 && /\A(?:"[^\"]+"|'[^\']+'|\{[^\}]+\})\z/.match(text)
631
626
  # text already quoted
632
627
  elsif !text['\'']
633
628
  text = '\'' + text + '\''
@@ -674,6 +669,7 @@ module Magick
674
669
 
675
670
  # Define IPTC record number:dataset tags for use with Image#get_iptc_dataset
676
671
  module IPTC
672
+ # rubocop:disable Naming/ConstantName
677
673
  module Envelope
678
674
  Model_Version = '1:00'
679
675
  Destination = '1:05'
@@ -771,6 +767,7 @@ module Magick
771
767
  module Post_ObjectData_Descriptor
772
768
  Confirmed_ObjectData_Size = '9:10'
773
769
  end
770
+ # rubocop:enable Naming/ConstantName
774
771
  end # module Magick::IPTC
775
772
 
776
773
  # Ruby-level Magick::Image methods
@@ -842,9 +839,9 @@ module Magick
842
839
  # arrays.
843
840
  def get_exif_by_entry(*entry)
844
841
  ary = []
845
- if entry.length.zero?
842
+ if entry.empty?
846
843
  exif_data = self['EXIF:*']
847
- exif_data.split("\n").each { |exif| ary.push(exif.split('=')) } if exif_data
844
+ exif_data&.split("\n")&.each { |exif| ary.push(exif.split('=')) }
848
845
  else
849
846
  get_exif_by_entry # ensure properties is populated with exif data
850
847
  entry.each do |name|
@@ -858,14 +855,12 @@ module Magick
858
855
  # Retrieve EXIF data by tag number or all tag/value pairs. The return value is a hash.
859
856
  def get_exif_by_number(*tag)
860
857
  hash = {}
861
- if tag.length.zero?
858
+ if tag.empty?
862
859
  exif_data = self['EXIF:!']
863
- if exif_data
864
- exif_data.split("\n").each do |exif|
865
- tag, value = exif.split('=')
866
- tag = tag[1, 4].hex
867
- hash[tag] = value
868
- end
860
+ exif_data&.split("\n")&.each do |exif|
861
+ tag, value = exif.split('=')
862
+ tag = tag[1, 4].hex
863
+ hash[tag] = value
869
864
  end
870
865
  else
871
866
  get_exif_by_number # ensure properties is populated with exif data
@@ -1080,13 +1075,13 @@ module Magick
1080
1075
  %i[red green blue opacity].each do |c|
1081
1076
  module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
1082
1077
  def #{c}
1083
- return collect { |p| p.#{c} }
1078
+ return collect { |p| p.#{c} }
1084
1079
  end
1085
1080
  def #{c}=(v)
1086
- each { |p| p.#{c} = v }
1087
- changed
1088
- notify_observers(self)
1089
- nil
1081
+ each { |p| p.#{c} = v }
1082
+ changed
1083
+ notify_observers(self)
1084
+ v
1090
1085
  end
1091
1086
  END_EVAL
1092
1087
  end
@@ -1293,10 +1288,10 @@ module Magick
1293
1288
  # Allow scene to be set to nil
1294
1289
  def scene=(n)
1295
1290
  if n.nil?
1296
- Kernel.raise IndexError, 'scene number out of bounds' unless @images.length.zero?
1291
+ Kernel.raise IndexError, 'scene number out of bounds' unless @images.empty?
1297
1292
  @scene = nil
1298
1293
  return
1299
- elsif @images.length.zero?
1294
+ elsif @images.empty?
1300
1295
  Kernel.raise IndexError, 'scene number out of bounds'
1301
1296
  end
1302
1297
 
@@ -1310,17 +1305,11 @@ module Magick
1310
1305
  %w[& + - |].each do |op|
1311
1306
  module_eval <<-END_BINOPS, __FILE__, __LINE__ + 1
1312
1307
  def #{op}(other)
1308
+ assert_image_array(other)
1313
1309
  ilist = self.class.new
1314
- begin
1315
- a = other #{op} @images
1316
- rescue TypeError
1317
- Kernel.raise ArgumentError, "Magick::ImageList expected, got " + other.class.to_s
1318
- end
1310
+ a = other #{op} @images
1319
1311
  current = get_current()
1320
- a.each do |image|
1321
- assert_image image
1322
- ilist << image
1323
- end
1312
+ a.each { |image| ilist << image }
1324
1313
  ilist.set_current current
1325
1314
  return ilist
1326
1315
  end
@@ -1349,16 +1338,18 @@ module Magick
1349
1338
  # return if A.scene != B.scene
1350
1339
  # return A.length <=> B.length
1351
1340
  def <=>(other)
1352
- Kernel.raise TypeError, "#{self.class} required (#{other.class} given)" unless other.is_a? self.class
1341
+ return unless other.is_a? self.class
1342
+
1353
1343
  size = [length, other.length].min
1354
1344
  size.times do |x|
1355
1345
  r = self[x] <=> other[x]
1356
1346
  return r unless r.zero?
1357
1347
  end
1348
+
1358
1349
  return 0 if @scene.nil? && other.scene.nil?
1350
+ return if @scene.nil? && !other.scene.nil?
1351
+ return if !@scene.nil? && other.scene.nil?
1359
1352
 
1360
- Kernel.raise TypeError, "cannot convert nil into #{other.scene.class}" if @scene.nil? && !other.scene.nil?
1361
- Kernel.raise TypeError, "cannot convert nil into #{scene.class}" if !@scene.nil? && other.scene.nil?
1362
1353
  r = scene <=> other.scene
1363
1354
  return r unless r.zero?
1364
1355
 
@@ -1377,7 +1368,7 @@ module Magick
1377
1368
 
1378
1369
  def []=(*args)
1379
1370
  obj = @images.[]=(*args)
1380
- if obj && obj.respond_to?(:each)
1371
+ if obj.respond_to?(:each)
1381
1372
  assert_image_array(obj)
1382
1373
  set_current obj.last.__id__
1383
1374
  elsif obj
@@ -1390,7 +1381,7 @@ module Magick
1390
1381
 
1391
1382
  %i[
1392
1383
  at each each_index empty? fetch
1393
- first hash include? index length rindex sort!
1384
+ first hash include? index length rindex
1394
1385
  ].each do |mth|
1395
1386
  module_eval <<-END_SIMPLE_DELEGATES, __FILE__, __LINE__ + 1
1396
1387
  def #{mth}(*args, &block)
@@ -1400,6 +1391,11 @@ module Magick
1400
1391
  end
1401
1392
  alias size length
1402
1393
 
1394
+ def sort!(*args, &block)
1395
+ @images.sort!(*args, &block)
1396
+ self
1397
+ end
1398
+
1403
1399
  def clear
1404
1400
  @scene = nil
1405
1401
  @images.clear
@@ -1447,7 +1443,7 @@ module Magick
1447
1443
  alias map! collect!
1448
1444
  alias __map__! collect!
1449
1445
 
1450
- # ImageMagic used affinity in 6.4.3, switch to remap in 6.4.4.
1446
+ # ImageMagick used affinity in 6.4.3, switch to remap in 6.4.4.
1451
1447
  alias affinity remap
1452
1448
 
1453
1449
  def compact
@@ -1510,7 +1506,12 @@ module Magick
1510
1506
  end
1511
1507
 
1512
1508
  def eql?(other)
1513
- assert_image_array other
1509
+ begin
1510
+ assert_image_array other
1511
+ rescue ArgumentError
1512
+ return false
1513
+ end
1514
+
1514
1515
  eql = other.eql?(@images)
1515
1516
  begin # "other" is another ImageList
1516
1517
  eql &&= @scene == other.scene
@@ -1521,7 +1522,7 @@ module Magick
1521
1522
  end
1522
1523
 
1523
1524
  def fill(*args, &block)
1524
- assert_image args[0] unless block_given?
1525
+ assert_image args[0] unless block
1525
1526
  current = get_current
1526
1527
  @images.fill(*args, &block)
1527
1528
  assert_image_array self
@@ -1541,7 +1542,7 @@ module Magick
1541
1542
  alias select find_all
1542
1543
 
1543
1544
  def from_blob(*blobs, &block)
1544
- Kernel.raise ArgumentError, 'no blobs given' if blobs.length.zero?
1545
+ Kernel.raise ArgumentError, 'no blobs given' if blobs.empty?
1545
1546
  blobs.each do |b|
1546
1547
  Magick::Image.from_blob(b, &block).each { |n| @images << n }
1547
1548
  end
@@ -1570,9 +1571,8 @@ module Magick
1570
1571
 
1571
1572
  # Call inspect for all the images
1572
1573
  def inspect
1573
- img = []
1574
- @images.each { |image| img << image.inspect }
1575
- img = '[' + img.join(",\n") + "]\nscene=#{@scene}"
1574
+ img = @images.map(&:inspect)
1575
+ '[' + img.join(",\n") + "]\nscene=#{@scene}"
1576
1576
  end
1577
1577
 
1578
1578
  # Set the number of iterations of an animated GIF
@@ -1583,7 +1583,7 @@ module Magick
1583
1583
  end
1584
1584
 
1585
1585
  def last(*args)
1586
- if args.length.zero?
1586
+ if args.empty?
1587
1587
  a = @images.last
1588
1588
  else
1589
1589
  a = @images.last(*args)
@@ -1614,7 +1614,9 @@ module Magick
1614
1614
  # it up the line. Catch a NameError and emit a useful message.
1615
1615
  def method_missing(meth_id, *args, &block)
1616
1616
  if @scene
1617
- @images[@scene].send(meth_id, *args, &block)
1617
+ img = @images[@scene]
1618
+ new_img = img.public_send(meth_id, *args, &block)
1619
+ img.object_id == new_img.object_id ? self : new_img
1618
1620
  else
1619
1621
  super
1620
1622
  end
@@ -1643,7 +1645,7 @@ module Magick
1643
1645
 
1644
1646
  # Ping files and concatenate the new images
1645
1647
  def ping(*files, &block)
1646
- Kernel.raise ArgumentError, 'no files given' if files.length.zero?
1648
+ Kernel.raise ArgumentError, 'no files given' if files.empty?
1647
1649
  files.each do |f|
1648
1650
  Magick::Image.ping(f, &block).each { |n| @images << n }
1649
1651
  end
@@ -1669,7 +1671,7 @@ module Magick
1669
1671
 
1670
1672
  # Read files and concatenate the new images
1671
1673
  def read(*files, &block)
1672
- Kernel.raise ArgumentError, 'no files given' if files.length.zero?
1674
+ Kernel.raise ArgumentError, 'no files given' if files.empty?
1673
1675
  files.each do |f|
1674
1676
  Magick::Image.read(f, &block).each { |n| @images << n }
1675
1677
  end
@@ -1732,8 +1734,8 @@ module Magick
1732
1734
  self
1733
1735
  end
1734
1736
 
1735
- def reverse_each
1736
- @images.reverse_each { |image| yield(image) }
1737
+ def reverse_each(&block)
1738
+ @images.reverse_each(&block)
1737
1739
  self
1738
1740
  end
1739
1741
 
@@ -1772,9 +1774,7 @@ module Magick
1772
1774
  end
1773
1775
 
1774
1776
  def to_a
1775
- a = []
1776
- @images.each { |image| a << image }
1777
- a
1777
+ @images.map { |image| image }
1778
1778
  end
1779
1779
 
1780
1780
  def uniq
@@ -1801,7 +1801,6 @@ module Magick
1801
1801
  end
1802
1802
 
1803
1803
  def values_at(*args)
1804
- a = @images.values_at(*args)
1805
1804
  a = self.class.new
1806
1805
  @images.values_at(*args).each { |image| a << image }
1807
1806
  a.scene = a.length - 1
@@ -1809,6 +1808,15 @@ module Magick
1809
1808
  end
1810
1809
  alias indexes values_at
1811
1810
  alias indices values_at
1811
+
1812
+ def destroy!
1813
+ @images.each(&:destroy!)
1814
+ self
1815
+ end
1816
+
1817
+ def destroyed?
1818
+ @images.all?(&:destroyed?)
1819
+ end
1812
1820
  end # Magick::ImageList
1813
1821
 
1814
1822
  class Pixel
@@ -1852,7 +1860,7 @@ module Magick
1852
1860
  class HatchFill
1853
1861
  def initialize(bgcolor, hatchcolor = 'white', dist = 10)
1854
1862
  @bgcolor = bgcolor
1855
- @hatchpixel = Pixel.from_color(hatchcolor)
1863
+ @hatchpixel = hatchcolor.is_a?(Pixel) ? hatchcolor : Pixel.from_color(hatchcolor)
1856
1864
  @dist = dist
1857
1865
  end
1858
1866
 
data/lib/rvg/container.rb CHANGED
@@ -108,11 +108,11 @@ module Magick
108
108
  # If the element is not a group, defs, symbol, or rvg,
109
109
  # wrap a group around it so it can get a transform and
110
110
  # possibly a new viewport.
111
- if !element.respond_to?(:ref)
111
+ if element.respond_to?(:ref)
112
+ @element = element.deep_copy
113
+ else
112
114
  @element = Group.new
113
115
  @element << element.deep_copy
114
- else
115
- @element = element.deep_copy
116
116
  end
117
117
  @element.ref(x, y, width, height)
118
118
  end
@@ -109,7 +109,7 @@ module Magick
109
109
  short = n > 0 ? y_coords : x_coords
110
110
  olen = short.length
111
111
  n.abs.times { |x| short << short[x % olen] }
112
- points = x_coords.zip(y_coords).flatten
112
+ points = x_coords.zip(y_coords).flatten!
113
113
  end
114
114
  n = points.length
115
115
  raise ArgumentError, "insufficient/odd number of points specified: #{n}" if n < 4 || n.odd?
@@ -162,6 +162,8 @@ module Magick
162
162
  (@width - @image.columns * scale) / 2.0
163
163
  when /\AxMax/
164
164
  @width - @image.columns * scale
165
+ else
166
+ 0
165
167
  end
166
168
 
167
169
  ty = case @align
@@ -171,6 +173,8 @@ module Magick
171
173
  (@height - @image.rows * scale) / 2.0
172
174
  when /YMax\z/
173
175
  @height - @image.rows * scale
176
+ else
177
+ 0
174
178
  end
175
179
  [tx, ty]
176
180
  end
@@ -182,7 +186,7 @@ module Magick
182
186
  width = @width
183
187
  height = @height
184
188
  elsif @meet_or_slice == 'meet'
185
- scale = [@width / @image.columns, @height / @image.rows].min
189
+ scale = [@width / @image.columns, @height / @image.rows].min || 1.0
186
190
  width = @image.columns
187
191
  height = @image.rows
188
192
  else
@@ -193,7 +197,7 @@ module Magick
193
197
  end
194
198
 
195
199
  gc.clip_path(name)
196
- scale = [@width / @image.columns, @height / @image.rows].max
200
+ scale = [@width / @image.columns, @height / @image.rows].max || 1.0
197
201
  width = @image.columns
198
202
  height = @image.rows
199
203
  end