rmagick 5.4.4 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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