rmagick4j 0.3.4-java → 0.3.9-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +7 -0
  2. data/History.txt +84 -0
  3. data/LICENSE.txt +31 -0
  4. data/README.txt +25 -0
  5. data/Rakefile +65 -0
  6. data/lib/magick4j.jar +0 -0
  7. data/lib/{RMagick.rb → rmagick.rb} +574 -405
  8. data/lib/rmagick4j/constants.rb +34 -0
  9. data/lib/rmagick4j/draw.rb +124 -0
  10. data/lib/rmagick4j/enum.rb +120 -0
  11. data/lib/rmagick4j/gradient_fill.rb +14 -0
  12. data/lib/rmagick4j/image.rb +351 -0
  13. data/lib/rmagick4j/image_list.rb +25 -0
  14. data/lib/rmagick4j/pixel.rb +170 -0
  15. data/lib/rmagick4j/rmagick4j.rb +15 -430
  16. data/lib/rmagick4j/texture_fill.rb +14 -0
  17. data/lib/rmagick4j/type_metric.rb +8 -0
  18. data/lib/rmagick4j/version.rb +5 -0
  19. data/lib/rvg/clippath.rb +2 -2
  20. data/lib/rvg/container.rb +2 -2
  21. data/lib/rvg/describable.rb +2 -2
  22. data/lib/rvg/embellishable.rb +2 -2
  23. data/lib/rvg/misc.rb +3 -3
  24. data/lib/rvg/paint.rb +7 -2
  25. data/lib/rvg/pathdata.rb +2 -2
  26. data/lib/rvg/rvg.rb +3 -3
  27. data/lib/rvg/stretchable.rb +15 -3
  28. data/lib/rvg/stylable.rb +2 -2
  29. data/lib/rvg/text.rb +2 -2
  30. data/lib/rvg/transformable.rb +2 -2
  31. data/lib/rvg/units.rb +2 -2
  32. data/test/RMagickTestSuite.rb +129 -0
  33. data/test/eyetests/bullseye.rb +151 -0
  34. data/test/eyetests/doc.rb +79 -0
  35. data/test/eyetests/tests/draw_arc_basic.rb +16 -0
  36. data/test/eyetests/tests/draw_circle_affine.rb +19 -0
  37. data/test/eyetests/tests/draw_circle_basic.rb +16 -0
  38. data/test/eyetests/tests/draw_clip_path.rb +44 -0
  39. data/test/eyetests/tests/draw_ellipse_affine.rb +19 -0
  40. data/test/eyetests/tests/draw_ellipse_basic.rb +16 -0
  41. data/test/eyetests/tests/draw_line_affine.rb +24 -0
  42. data/test/eyetests/tests/draw_line_basic.rb +21 -0
  43. data/test/eyetests/tests/draw_multiline_type_metrics.rb +42 -0
  44. data/test/eyetests/tests/draw_pattern_1.rb +35 -0
  45. data/test/eyetests/tests/draw_polygon_affine.rb +22 -0
  46. data/test/eyetests/tests/draw_polygon_basic.rb +19 -0
  47. data/test/eyetests/tests/draw_polyline_affine.rb +19 -0
  48. data/test/eyetests/tests/draw_polyline_basic.rb +18 -0
  49. data/test/eyetests/tests/draw_pop_push.rb +16 -0
  50. data/test/eyetests/tests/draw_pop_push_translate.rb +22 -0
  51. data/test/eyetests/tests/draw_rectangle_affine.rb +16 -0
  52. data/test/eyetests/tests/draw_rectangle_basic.rb +16 -0
  53. data/test/eyetests/tests/draw_rectangle_narrow.rb +18 -0
  54. data/test/eyetests/tests/draw_rmagick_test_01.rb +35 -0
  55. data/test/eyetests/tests/draw_rmagick_test_02.rb +40 -0
  56. data/test/eyetests/tests/draw_rmagick_test_03.rb +17 -0
  57. data/test/eyetests/tests/draw_rmagick_test_04.rb +21 -0
  58. data/test/eyetests/tests/draw_rotate_01.rb +33 -0
  59. data/test/eyetests/tests/draw_roundrectangle_affine.rb +19 -0
  60. data/test/eyetests/tests/draw_roundrectangle_basic.rb +16 -0
  61. data/test/eyetests/tests/draw_scale_01.rb +33 -0
  62. data/test/eyetests/tests/draw_skewx_01.rb +34 -0
  63. data/test/eyetests/tests/draw_skewy_01.rb +33 -0
  64. data/test/eyetests/tests/draw_stroke_miterlimit.rb +21 -0
  65. data/test/eyetests/tests/effect_blur.rb +9 -0
  66. data/test/eyetests/tests/effect_charcoal.rb +9 -0
  67. data/test/eyetests/tests/effect_edge.rb +9 -0
  68. data/test/eyetests/tests/effect_implode.rb +9 -0
  69. data/test/eyetests/tests/effect_negate.rb +9 -0
  70. data/test/eyetests/tests/effect_negate_true.rb +9 -0
  71. data/test/eyetests/tests/effect_normalize.rb +9 -0
  72. data/test/eyetests/tests/effect_shade.rb +9 -0
  73. data/test/eyetests/tests/effect_solarize.rb +10 -0
  74. data/test/eyetests/tests/effect_wave.rb +9 -0
  75. data/test/eyetests/tests/gradient_fill_horizontal_diagonal_fill.rb +9 -0
  76. data/test/eyetests/tests/gradient_fill_horizontal_fill.rb +9 -0
  77. data/test/eyetests/tests/gradient_fill_point_fill.rb +9 -0
  78. data/test/eyetests/tests/gradient_fill_vertical_diagonal_fill.rb +9 -0
  79. data/test/eyetests/tests/gradient_fill_vertical_fill.rb +9 -0
  80. data/test/eyetests/tests/gruff_accumulator_bar.rb +29 -0
  81. data/test/eyetests/tests/gruff_area_1.rb +16 -0
  82. data/test/eyetests/tests/gruff_area_2.rb +27 -0
  83. data/test/eyetests/tests/gruff_bar_1.rb +29 -0
  84. data/test/eyetests/tests/gruff_bar_2.rb +19 -0
  85. data/test/eyetests/tests/gruff_dot_1.rb +19 -0
  86. data/test/eyetests/tests/gruff_line_1.rb +13 -0
  87. data/test/eyetests/tests/gruff_line_2.rb +20 -0
  88. data/test/eyetests/tests/gruff_net_1.rb +16 -0
  89. data/test/eyetests/tests/gruff_net_2.rb +16 -0
  90. data/test/eyetests/tests/gruff_pie_1.rb +21 -0
  91. data/test/eyetests/tests/gruff_pie_2.rb +22 -0
  92. data/test/eyetests/tests/gruff_scene_1.rb +14 -0
  93. data/test/eyetests/tests/gruff_scene_2.rb +14 -0
  94. data/test/eyetests/tests/gruff_sidebar.rb +32 -0
  95. data/test/eyetests/tests/gruff_sidestacked_bar_1.rb +26 -0
  96. data/test/eyetests/tests/gruff_sidestacked_bar_2.rb +26 -0
  97. data/test/eyetests/tests/gruff_spider_1.rb +22 -0
  98. data/test/eyetests/tests/gruff_spider_2.rb +15 -0
  99. data/test/eyetests/tests/gruff_stacked_area_1.rb +23 -0
  100. data/test/eyetests/tests/gruff_stacked_bar_1.rb +23 -0
  101. data/test/eyetests/tests/gruff_stacked_bar_2.rb +26 -0
  102. data/test/eyetests/tests/hatch_fill.rb +9 -0
  103. data/test/eyetests/tests/image_list_flatten_images.rb +15 -0
  104. data/test/eyetests/tests/new_image.rb +31 -0
  105. data/test/eyetests/tests/path_a_command_01.rb +16 -0
  106. data/test/eyetests/tests/path_a_command_02.rb +19 -0
  107. data/test/eyetests/tests/path_c_command_01.rb +16 -0
  108. data/test/eyetests/tests/path_c_command_02.rb +16 -0
  109. data/test/eyetests/tests/path_complex_01.rb +16 -0
  110. data/test/eyetests/tests/path_espiral_01.rb +29 -0
  111. data/test/eyetests/tests/path_h_command_01.rb +16 -0
  112. data/test/eyetests/tests/path_h_command_02.rb +16 -0
  113. data/test/eyetests/tests/path_l_command_01.rb +16 -0
  114. data/test/eyetests/tests/path_l_command_02.rb +16 -0
  115. data/test/eyetests/tests/path_m_command_01.rb +16 -0
  116. data/test/eyetests/tests/path_m_command_02.rb +16 -0
  117. data/test/eyetests/tests/path_m_command_03.rb +16 -0
  118. data/test/eyetests/tests/path_q_command_01.rb +16 -0
  119. data/test/eyetests/tests/path_q_command_02.rb +16 -0
  120. data/test/eyetests/tests/path_q_command_03.rb +25 -0
  121. data/test/eyetests/tests/path_s_command_01.rb +16 -0
  122. data/test/eyetests/tests/path_s_command_02.rb +16 -0
  123. data/test/eyetests/tests/path_star_01.rb +19 -0
  124. data/test/eyetests/tests/path_t_command_01.rb +16 -0
  125. data/test/eyetests/tests/path_t_command_02.rb +16 -0
  126. data/test/eyetests/tests/path_v_command_01.rb +16 -0
  127. data/test/eyetests/tests/path_v_command_02.rb +16 -0
  128. data/test/eyetests/tests/store_pixel_smiley.rb +123 -0
  129. data/test/eyetests/tests/texture_fill.rb +11 -0
  130. data/test/gruff_tests/test/gruff_test_case.rb +123 -0
  131. data/test/gruff_tests/test/monkey_gruff.rb +7 -0
  132. data/test/gruff_tests/test/test_accumulator_bar.rb +50 -0
  133. data/test/gruff_tests/test/test_area.rb +134 -0
  134. data/test/gruff_tests/test/test_bar.rb +295 -0
  135. data/test/gruff_tests/test/test_base.rb +8 -0
  136. data/test/gruff_tests/test/test_bullet.rb +26 -0
  137. data/test/gruff_tests/test/test_dot.rb +273 -0
  138. data/test/gruff_tests/test/test_legend.rb +68 -0
  139. data/test/gruff_tests/test/test_line.rb +554 -0
  140. data/test/gruff_tests/test/test_mini_bar.rb +33 -0
  141. data/test/gruff_tests/test/test_mini_pie.rb +20 -0
  142. data/test/gruff_tests/test/test_mini_side_bar.rb +37 -0
  143. data/test/gruff_tests/test/test_net.rb +230 -0
  144. data/test/gruff_tests/test/test_photo.rb +41 -0
  145. data/test/gruff_tests/test/test_pie.rb +154 -0
  146. data/test/gruff_tests/test/test_scene.rb +100 -0
  147. data/test/gruff_tests/test/test_side_bar.rb +12 -0
  148. data/test/gruff_tests/test/test_sidestacked_bar.rb +89 -0
  149. data/test/gruff_tests/test/test_spider.rb +216 -0
  150. data/test/gruff_tests/test/test_stacked_area.rb +52 -0
  151. data/test/gruff_tests/test/test_stacked_bar.rb +52 -0
  152. data/test/images/clown.jpg +0 -0
  153. data/test/images/texture.jpg +0 -0
  154. data/test/implemented_methods.rb +18 -0
  155. data/test/spec/draw_spec.rb +43 -0
  156. data/test/spec/features/step_definitions/geometry_steps.rb +22 -0
  157. data/test/spec/features/step_definitions/image_filling_steps.rb +49 -0
  158. data/test/spec/features/support/env.rb +3 -0
  159. data/test/spec/image_constants.rb +76 -0
  160. data/test/spec/image_spec.rb +83 -0
  161. data/test/spec/pixel_spec.rb +89 -0
  162. metadata +333 -45
  163. data/lib/RMagick.jar +0 -0
  164. data/lib/jhlabs-filters.jar +0 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9fe85a77a4fd7dbca1d624dc8bcb95da616a9a8
4
+ data.tar.gz: afe8cb688221536949ff56d56ba3e6431dbc9e61
5
+ SHA512:
6
+ metadata.gz: 7181ab773dd7a4faf83bdbe39c9f80339a153aaa15329c765a83ca824fc4658b82fae6c8f00f289ee5a0d42cea27e07af1a9c094b8c9ff8a18f2c7997ffc23f3
7
+ data.tar.gz: c450e9072b1df82bc954cb6b80a60e60be0751760a075b44f2c566881c3f7ac00fcebad868b9b80938a797ffc38f5d1257f203241c0e1f9acc6357dbca2e842a
@@ -0,0 +1,84 @@
1
+ == 0.3.5
2
+
3
+ - Implemented Draw primitives (affice, arc, pattern, path)
4
+
5
+ - Improved Image and ImageList:
6
+ - crop ( http://www.imagemagick.org/RMagick/doc/image1.html#crop )
7
+ - rotate ( http://www.imagemagick.org/RMagick/doc/image3.html#rotate )
8
+ - store_pixels (http://www.imagemagick.org/RMagick/doc/image3.html#store_pixels )
9
+ - flatten_images (http://www.imagemagick.org/RMagick/doc/ilist.html#flatten_images )
10
+
11
+ - Implemented more of Pixel (from_HSL, to_HSL, <=>, cmp, intensity)
12
+
13
+ - Implemented the fill classes (http://www.imagemagick.org/RMagick/doc/struct.html#fill )
14
+
15
+ - Added a side-by-side (MRI vs JRuby) image testing tool named Bullseye
16
+
17
+ - Added 680 color names. It can search, but not retrieve the name correctly capitalized.
18
+
19
+ == 0.3.4
20
+
21
+ - No bugfixes nor new features, just added compatibility with JRuby 1.1.
22
+
23
+ == 0.3.3
24
+
25
+ - This is a bug fix release to support updates to the string byte array conversion changes in recent versions of JRuby. This release was tested against JRuby 1.0.0RC3.
26
+
27
+ == 0.3.2
28
+
29
+ Full RMagick required for RMagick4J is included. The gem also includes JH Labs Filters and SVG Salamander, but they aren't much used yet.
30
+
31
+ Use it like so for now:
32
+
33
+ require 'rubygems'
34
+ gem PLATFORM == 'java' ? 'rmagick4j' : 'rmagick'
35
+ require 'RMagick'
36
+
37
+ Also see the project home page at http://code.google.com/p/rmagick4j/
38
+
39
+ == 0.3.1
40
+
41
+ Functionally equivalent to 0.3 release, but it supports JRuby 0.9.8 now. Also, it's a gem. It works along with a standard rmagick gem already installed (for those who keep gems in one place for multiple Ruby installs). For instance, I've tested this as working under both ruby and jruby:
42
+
43
+ require 'rubygems'
44
+ gem 'rmagick4j'
45
+ gem 'rmagick'
46
+ require 'gruff'
47
+
48
+ I hope to release a full rmagick gem in the near future for those who want to use apps unchanged and have a local GEM_HOME just for jruby.
49
+
50
+ == 0.3.0
51
+
52
+ More complete Draw features. Supports most Gruff Graphs unit tests.
53
+
54
+ == 0.2
55
+
56
+ More I/O support including basic handling of write, to_blob, and from_blob. Also upgraded RMagick libs to 1.14.0 and bundled JRuby to 0.9.1. Also reorganized the directory layout better. Moved JRuby files to its own folder. Moved draw support into magickjr package.
57
+
58
+ == 0.1
59
+
60
+ Hello,
61
+
62
+ I've tagged an "m1" release of RMagickJr. Here are the main good things to say about it:
63
+
64
+ - At varying degrees of quality and hackishness, it runs all these samples: http://rmagick.rubyforge.org/portfolio.html
65
+ - The build.xml works and by default shows a sample picture.
66
+
67
+ Put together, this means that other people might be able to run it, and they might be able to put it to some simple use. Well, except that it doesn't support real data export yet. It just displays pictures.
68
+
69
+ Here are some bad things to say about it:
70
+
71
+ - I've tested only on a Mac so far.
72
+ - Some things are super hacks, and some implementation is super shallow.
73
+ - Some of the pictures don't look quite right.
74
+ - Fixing some of what's off (especially the convolution/blurring) will be nontrivial for me.
75
+ - Some project organization is less than ideal. Still need to understand RubyGems, extensions/ext concepts, and rake better.
76
+ - Not much attention paid to super performance.
77
+ - My progress is slow, but that was expected.
78
+ - Probably a lot more.
79
+
80
+ But it's still progress, and I'm actually reading the pick axe (v2 - I'd looked at v1 online a few years ago), so maybe I'll start grokking the Ruby world better soon.
81
+
82
+ Maybe by m2 or m3 (or sometime), I could try to find a real app using RMagick and try to make it work with my version. For the next moment, though, I'll probably try tackling page 2 or 3 of the "portfolio" samples at the RMagick web site. And eventually go into class by class and method by method depth. Or something. I'm just trying to work with tracer bullets for now.
83
+
84
+ And I might rename the project to "rmagick4j" or "rmagick-jruby" or something at some point. Not sure what's best, so I'm sticking with "jr" for now. And that's an accurate representation for now, anyway.
@@ -0,0 +1,31 @@
1
+ The file observer.rb comes from JRuby's distribution of standard Ruby libraries. The file jruby.jar also comes from the JRuby project.
2
+
3
+ RMagick.rb, clown.jpg, most of rmagick.gemspec, and the contents of rvg come from the RMagick project. Much of the content of the test demos (currently in "RMagickTestSuite.rb") come from the RMagick web site.
4
+
5
+ See these respective projects for the licenses and ownership of these files.
6
+
7
+ Other files lies under MIT license.
8
+
9
+ Copyright (c) 2010 Tom Palmer, Sergio Arbeo, Patrick Hurley, Karl Palmskog
10
+
11
+ Permission is hereby granted, free of charge, to any
12
+ person obtaining a copy of this software and associated
13
+ documentation files (the "Software"), to deal in the
14
+ Software without restriction, including without limitation
15
+ the rights to use, copy, modify, merge, publish,
16
+ distribute, sublicense, and/or sell copies of the
17
+ Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice
21
+ shall be included in all copies or substantial portions of
22
+ the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
25
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
26
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
27
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
28
+ OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
30
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
31
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,25 @@
1
+ RMagick is a Ruby binding to ImageMagick and GraphicsMagick. RMagick4J implements ImageMagick functionality and the C portions of RMagick for use with JRuby.
2
+
3
+ == Authors
4
+
5
+ This project was written by Thomas Palmer, Sergio Rodríguez Arbeo, and Thomas Enebo with lots of help from the JRuby community.
6
+
7
+ == License
8
+
9
+ The file observer.rb comes from JRuby's distribution of standard Ruby libraries. The file jruby.jar also comes from the JRuby project.
10
+
11
+ RMagick.rb, clown.jpg, most of rmagick.gemspec, and the contents of rvg come from the RMagick project. Much of the content of the test demos (currently in "RMagickTestSuite.rb") come from the RMagick web site.
12
+
13
+ See these respective projects for the licenses and ownership of these files.
14
+
15
+ Other files in RMagickJr are hereby placed in the public domain.
16
+
17
+ == Creating
18
+
19
+ To create a gem you should run rake. The useful targets are :clean, :compile, :gem, :release, :test (hoe has more -- see hoe docs). In order to run rake you must have hoe installed.
20
+
21
+ To create a new release, you should:
22
+
23
+ * Add new version entry to History.txt
24
+ * Update lib/rmagick4j/version.rb to contain new version
25
+ * rake release VERSION={{{{YOUR NEW VERSION (e.g. 1.1.1)}}}}
@@ -0,0 +1,65 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'bundler/gem_tasks'
4
+
5
+ task :default => [:test, :gruff_test, :gem]
6
+ task :gem => :build
7
+
8
+ jar_file = File.join(%w(lib magick4j.jar))
9
+
10
+ desc 'Clean up any generated file.'
11
+ task :clean do
12
+ rm_rf 'pkg'
13
+ end
14
+
15
+ desc 'Run gruff unit tests.'
16
+ task :gruff_test do
17
+ FileList['test/gruff_tests/test/test_*.rb'].each do |file|
18
+ puts `ruby #{file}`
19
+ puts ''
20
+ end
21
+ end
22
+
23
+ desc 'Run a live sample using RMagick4j.'
24
+ task :sample do
25
+ load_paths = '-Ijruby -Ilib -Ipkg'
26
+ sh "java #{classpath(jar_file)} org.jruby.Main #{load_paths} test/RMagickTestSuite.rb addWatermark"
27
+ end
28
+
29
+ task :spec do
30
+ require 'spec/rake/spectask'
31
+ desc 'Runs Java Integration Specs'
32
+
33
+ Spec::Rake::SpecTask.new do |t|
34
+ t.spec_opts ||= []
35
+ t.spec_files = if ENV['class'].nil?
36
+ FileList['test/spec/**']
37
+ else
38
+ File.join('test', 'spec', ENV['class']+'_spec.rb')
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ task :stories do
45
+ if ENV['file'].nil?
46
+ FileList['test/spec/stories/**/*_runner.rb'].each do |runner|
47
+ require runner
48
+ end
49
+ else
50
+ require File.join('test', 'spec', 'stories', ENV['file']+'_runner.rb')
51
+ end
52
+ end
53
+
54
+ %w(package install_gem debug_gem).each { |t| task t => :compile }
55
+
56
+ # helper methods below
57
+
58
+ def classpath(extra_jars=nil)
59
+ jruby_cpath = Java::java.lang.System.getProperty 'java.class.path'
60
+ path = jruby_cpath ? jruby_cpath.split(File::PATH_SEPARATOR) : []
61
+ path << FileList['lib/*.jar']
62
+ path << extra_jars.split(File::PATH_SEPARATOR) if extra_jars
63
+ "-cp #{path.flatten.join(File::PATH_SEPARATOR)}"
64
+ end
65
+
Binary file
@@ -1,15 +1,15 @@
1
- # $Id: RMagick.rb,v 1.51 2007/01/20 23:13:50 rmagick Exp $
1
+ # $Id: RMagick.rb,v 1.80 2009/01/02 21:08:14 rmagick Exp $
2
2
  #==============================================================================
3
- # Copyright (C) 2007 by Timothy P. Hunter
3
+ # Copyright (C) 2008 by Timothy P. Hunter
4
4
  # Name: RMagick.rb
5
5
  # Author: Tim Hunter
6
6
  # Purpose: Extend Ruby to interface with ImageMagick.
7
- # Notes: RMagick.so defines the classes. The code below adds methods
7
+ # Notes: RMagick2.so defines the classes. The code below adds methods
8
8
  # to the classes.
9
9
  #==============================================================================
10
10
 
11
- #require 'RMagick.so'
12
- require "rmagick4j/rmagick4j"
11
+ require File.join(File.dirname(__FILE__), 'rmagick4j', 'rmagick4j.rb')
12
+
13
13
  module Magick
14
14
  @@formats = nil
15
15
 
@@ -23,79 +23,106 @@ def Magick.formats(&block)
23
23
  end
24
24
  end
25
25
 
26
+ class << self
27
+ attr_writer :trace_proc
28
+ end
26
29
 
27
30
  # Geometry class and related enum constants
28
31
  class GeometryValue < Enum
29
32
  # no methods
30
33
  end
31
34
 
32
- PercentGeometry = GeometryValue.new(:PercentGeometry, 1)
33
- AspectGeometry = GeometryValue.new(:AspectGeometry, 2)
34
- LessGeometry = GeometryValue.new(:LessGeometry, 3)
35
- GreaterGeometry = GeometryValue.new(:GreaterGeometry, 4)
36
- AreaGeometry = GeometryValue.new(:AreaGeometry, 5)
35
+ PercentGeometry = GeometryValue.new(:PercentGeometry, 1).freeze
36
+ AspectGeometry = GeometryValue.new(:AspectGeometry, 2).freeze
37
+ LessGeometry = GeometryValue.new(:LessGeometry, 3).freeze
38
+ GreaterGeometry = GeometryValue.new(:GreaterGeometry, 4).freeze
39
+ AreaGeometry = GeometryValue.new(:AreaGeometry, 5).freeze
40
+ MinimumGeometry = GeometryValue.new(:MinimumGeometry, 6).freeze
37
41
 
38
42
  class Geometry
39
- FLAGS = ['', '%', '!', '<', '>', '@']
43
+ FLAGS = ['', '%', '!', '<', '>', '@', '^']
40
44
  RFLAGS = { '%' => PercentGeometry,
41
45
  '!' => AspectGeometry,
42
46
  '<' => LessGeometry,
43
47
  '>' => GreaterGeometry,
44
- '@' => AreaGeometry }
48
+ '@' => AreaGeometry,
49
+ '^' => MinimumGeometry }
45
50
 
46
51
  attr_accessor :width, :height, :x, :y, :flag
47
52
 
48
53
  def initialize(width=nil, height=nil, x=nil, y=nil, flag=nil)
54
+ raise(ArgumentError, "width set to #{width.to_s}") if width.is_a? GeometryValue
55
+ raise(ArgumentError, "height set to #{height.to_s}") if height.is_a? GeometryValue
56
+ raise(ArgumentError, "x set to #{x.to_s}") if x.is_a? GeometryValue
57
+ raise(ArgumentError, "y set to #{y.to_s}") if y.is_a? GeometryValue
49
58
 
50
59
  # Support floating-point width and height arguments so Geometry
51
60
  # objects can be used to specify Image#density= arguments.
52
- if width == nil
53
- @width = 0
54
- elsif width.to_f >= 0.0
55
- @width = width.to_f
56
- else
57
- Kernel.raise ArgumentError, "width must be >= 0: #{width}"
61
+ if width && width.to_f >= 0.0
62
+ @width = width.to_f
63
+ elsif width
64
+ Kernel.raise ArgumentError, "width must be >= 0: #{width}"
58
65
  end
59
- if height == nil
60
- @height = 0
61
- elsif height.to_f >= 0.0
62
- @height = height.to_f
63
- else
64
- Kernel.raise ArgumentError, "height must be >= 0: #{height}"
66
+
67
+ if height && height.to_f >= 0.0
68
+ @height = height.to_f
69
+ elsif height
70
+ Kernel.raise ArgumentError, "height must be >= 0: #{height}"
65
71
  end
66
72
 
67
73
  @x = x.to_i
68
74
  @y = y.to_i
69
75
  @flag = flag
76
+
70
77
  end
71
78
 
72
79
  # Construct an object from a geometry string
73
- RE = /\A(\d*)(?:x(\d+))?([-+]\d+)?([-+]\d+)?([%!<>@]?)\Z/
80
+ W = /(\d+\.\d+%?)|(\d*%?)/
81
+ H = W
82
+ X = /(?:([-+]\d+))?/
83
+ Y = X
84
+ RE = /\A#{W}x?#{H}#{X}#{Y}([!<>@\^]?)\Z/
74
85
 
75
86
  def Geometry.from_s(str)
76
- Kernel.raise(ArgumentError, "no geometry string specified") unless str
77
-
78
87
  m = RE.match(str)
79
88
  if m
80
- width = m[1].to_i
81
- height = m[2].to_i
82
- x = m[3].to_i
83
- y = m[4].to_i
84
- flag = RFLAGS[m[5]]
89
+ width = m[1].nil? && m[2].empty? ? nil : (m[1] || m[2]).to_f
90
+ height = m[3].nil? && m[4].empty? ? nil : (m[3] || m[4]).to_f
91
+ x = m[5].to_i
92
+ y = m[6].to_i
93
+ flag = RFLAGS[m[7]]
85
94
  else
86
95
  Kernel.raise ArgumentError, "invalid geometry format"
87
96
  end
97
+ if str['%']
98
+ flag = PercentGeometry
99
+ end
88
100
  Geometry.new(width, height, x, y, flag)
89
101
  end
90
102
 
91
103
  # Convert object to a geometry string
92
104
  def to_s
93
105
  str = ''
94
- str << sprintf("%g", @width) if @width > 0
95
- str << 'x' if (@width > 0 || @height > 0)
96
- str << sprintf("%g", @height) if @height > 0
106
+ if @width && @width > 0
107
+ fmt = @width.truncate == @width ? "%d" : "%.2f"
108
+ str << sprintf(fmt, @width)
109
+ str << '%' if @flag == PercentGeometry
110
+ end
111
+
112
+ if (@width && @width > 0 && @flag != PercentGeometry) || (@height && @height > 0)
113
+ str << 'x'
114
+ end
115
+
116
+ if @height && @height > 0
117
+ fmt = @height.truncate == @height ? "%d" : "%.2f"
118
+ str << sprintf(fmt, @height)
119
+ str << '%' if @flag == PercentGeometry
120
+ end
97
121
  str << sprintf("%+d%+d", @x, @y) if (@x != 0 || @y != 0)
98
- str << FLAGS[@flag.to_i]
122
+ if @flag != PercentGeometry
123
+ str << FLAGS[@flag.to_i]
124
+ end
125
+ str
99
126
  end
100
127
  end
101
128
 
@@ -250,7 +277,7 @@ class Draw
250
277
  def define_clip_path(name)
251
278
  begin
252
279
  push('defs')
253
- push('clip-path ', name)
280
+ push('clip-path', name)
254
281
  push('graphic-context')
255
282
  yield
256
283
  ensure
@@ -333,6 +360,30 @@ class Draw
333
360
  primitive "gravity #{GRAVITY_NAMES[grav.to_i]}"
334
361
  end
335
362
 
363
+ # IM 6.4.8-3 and later
364
+ def interword_spacing(space)
365
+ begin
366
+ Float(space)
367
+ rescue ArgumentError
368
+ Kernel.raise ArgumentError, "invalid value for interword_spacing"
369
+ rescue TypeError
370
+ Kernel.raise TypeError, "can't convert #{space.class} into Float"
371
+ end
372
+ primitive "interword-spacing #{space}"
373
+ end
374
+
375
+ # IM 6.4.8-3 and later
376
+ def kerning(space)
377
+ begin
378
+ Float(space)
379
+ rescue ArgumentError
380
+ Kernel.raise ArgumentError, "invalid value for kerning"
381
+ rescue TypeError
382
+ Kernel.raise TypeError, "can't convert #{space.class} into Float"
383
+ end
384
+ primitive "kerning #{space}"
385
+ end
386
+
336
387
  # Draw a line
337
388
  def line(startX, startY, endX, endY)
338
389
  primitive "line " + sprintf("%g,%g %g,%g", startX, startY, endX, endY)
@@ -424,7 +475,7 @@ class Draw
424
475
  primitive "pop graphic-context"
425
476
  else
426
477
  # to_s allows a Symbol to be used instead of a String
427
- primitive "pop " + what.to_s
478
+ primitive "pop " + what.map {|w| w.to_s}.join(' ')
428
479
  end
429
480
  end
430
481
 
@@ -438,7 +489,7 @@ class Draw
438
489
  primitive "push graphic-context"
439
490
  else
440
491
  # to_s allows a Symbol to be used instead of a String
441
- primitive "push " + what.to_s
492
+ primitive "push " + what.map {|w| w.to_s}.join(' ')
442
493
  end
443
494
  end
444
495
 
@@ -612,7 +663,7 @@ module IPTC
612
663
  end
613
664
 
614
665
  module Application
615
- #Record_Version = "2:00" abends with IM 6.2.9
666
+ Record_Version = "2:00"
616
667
  Object_Type_Reference = "2:03"
617
668
  Object_Name = "2:05"
618
669
  Title = "2:05"
@@ -703,9 +754,12 @@ end # module Magick::IPTC
703
754
  class Image
704
755
  include Comparable
705
756
 
757
+ alias_method :affinity, :remap
758
+
706
759
  # Provide an alternate version of Draw#annotate, for folks who
707
760
  # want to find it in this class.
708
761
  def annotate(draw, width, height, x, y, text, &block)
762
+ check_destroyed
709
763
  draw.annotate(self, width, height, x, y, text, &block)
710
764
  self
711
765
  end
@@ -746,26 +800,19 @@ class Image
746
800
  self
747
801
  end
748
802
 
749
- # Force an image to exact dimensions without changing the aspect ratio.
750
- # Resize and crop if necessary. (Thanks to Jerett Taylor!)
751
- def crop_resized(ncols, nrows, gravity=CenterGravity)
752
- copy.crop_resized!(ncols, nrows, gravity)
753
- end
754
-
755
- def crop_resized!(ncols, nrows, gravity=CenterGravity)
756
- if ncols != columns || nrows != rows
757
- scale = [ncols/columns.to_f, nrows/rows.to_f].max
758
- resize!(scale*columns+0.5, scale*rows+0.5)
759
- end
760
- crop!(gravity, ncols, nrows, true) if ncols != columns || nrows != rows
761
- self
762
- end
763
-
764
803
  # Used by ImageList methods - see ImageList#cur_image
765
804
  def cur_image
766
805
  self
767
806
  end
768
807
 
808
+ # Thanks to Russell Norris!
809
+ def each_pixel
810
+ get_pixels(0, 0, columns, rows).each_with_index do |p, n|
811
+ yield(p, n%columns, n/columns)
812
+ end
813
+ self
814
+ end
815
+
769
816
  # Retrieve EXIF data by entry or all. If one or more entry names specified,
770
817
  # return the values associated with the entries. If no entries specified,
771
818
  # return all entries and values. The return value is an array of [name,value]
@@ -778,6 +825,7 @@ class Image
778
825
  exif_data.split("\n").each { |exif| ary.push(exif.split('=')) }
779
826
  end
780
827
  else
828
+ get_exif_by_entry() # ensure properties is populated with exif data
781
829
  entry.each do |name|
782
830
  rval = self["EXIF:#{name}"]
783
831
  ary.push([name, rval])
@@ -799,8 +847,9 @@ class Image
799
847
  end
800
848
  end
801
849
  else
850
+ get_exif_by_number() # ensure properties is populated with exif data
802
851
  tag.each do |num|
803
- rval = self["EXIF:#{'#%04X' % num}"]
852
+ rval = self['#%04X' % num.to_i]
804
853
  hash[num] = rval == 'unknown' ? nil : rval
805
854
  end
806
855
  end
@@ -841,7 +890,7 @@ class Image
841
890
  def level(black_point=0.0, white_point=nil, gamma=nil)
842
891
  black_point = Float(black_point)
843
892
 
844
- white_point ||= Magick::MaxRGB - black_point
893
+ white_point ||= Magick::QuantumRange - black_point
845
894
  white_point = Float(white_point)
846
895
 
847
896
  gamma_arg = gamma
@@ -851,7 +900,7 @@ class Image
851
900
  if gamma.abs > 10.0 || white_point.abs <= 10.0 || white_point.abs < gamma.abs
852
901
  gamma, white_point = white_point, gamma
853
902
  unless gamma_arg
854
- white_point = Magick::MaxRGB - black_point
903
+ white_point = Magick::QuantumRange - black_point
855
904
  end
856
905
  end
857
906
 
@@ -915,15 +964,37 @@ class Image
915
964
  resize(width, height)
916
965
  end
917
966
 
967
+ # Force an image to exact dimensions without changing the aspect ratio.
968
+ # Resize and crop if necessary. (Thanks to Jerett Taylor!)
969
+ def resize_to_fill(ncols, nrows=nil, gravity=CenterGravity)
970
+ copy.resize_to_fill!(ncols, nrows, gravity)
971
+ end
972
+
973
+ def resize_to_fill!(ncols, nrows=nil, gravity=CenterGravity)
974
+ nrows ||= ncols
975
+ if ncols != columns || nrows != rows
976
+ scale = [ncols/columns.to_f, nrows/rows.to_f].max
977
+ resize!(scale*columns+0.5, scale*rows+0.5)
978
+ end
979
+ crop!(gravity, ncols, nrows, true) if ncols != columns || nrows != rows
980
+ self
981
+ end
982
+
983
+ # Preserve aliases used < RMagick 2.0.1
984
+ alias_method :crop_resized, :resize_to_fill
985
+ alias_method :crop_resized!, :resize_to_fill!
986
+
918
987
  # Convenience method to resize retaining the aspect ratio.
919
988
  # (Thanks to Robert Manni!)
920
- def resize_to_fit(cols, rows)
989
+ def resize_to_fit(cols, rows=nil)
990
+ rows ||= cols
921
991
  change_geometry(Geometry.new(cols, rows)) do |ncols, nrows|
922
992
  resize(ncols, nrows)
923
993
  end
924
994
  end
925
995
 
926
- def resize_to_fit!(cols, rows)
996
+ def resize_to_fit!(cols, rows=nil)
997
+ rows ||= cols
927
998
  change_geometry(Geometry.new(cols, rows)) do |ncols, nrows|
928
999
  resize!(ncols, nrows)
929
1000
  end
@@ -963,6 +1034,7 @@ class Image
963
1034
  attr_accessor :dirty
964
1035
 
965
1036
  def initialize(img, x, y, width, height)
1037
+ img.check_destroyed
966
1038
  if width <= 0 || height <= 0
967
1039
  Kernel.raise ArgumentError, "invalid geometry (#{width}x#{height}+#{x}+#{y})"
968
1040
  end
@@ -1194,24 +1266,21 @@ class Image
1194
1266
 
1195
1267
  end # class Magick::Image
1196
1268
 
1197
- class ImageList < Array
1269
+ class ImageList
1198
1270
 
1199
1271
  include Comparable
1272
+ include Enumerable
1273
+ attr_reader :scene
1200
1274
 
1201
- undef_method :assoc
1202
- undef_method :flatten! # These methods are undefined
1203
- undef_method :flatten # because they're not useful
1204
- undef_method :join # for an ImageList object
1205
- undef_method :pack
1206
- undef_method :rassoc
1207
- undef_method :transpose if Array.instance_methods(false).include? 'transpose'
1208
- undef_method :zip if Array.instance_methods(false).include? 'zip'
1275
+ private
1209
1276
 
1210
- attr_reader :scene
1277
+ def get_current()
1278
+ return @images[@scene].__id__ rescue nil
1279
+ end
1211
1280
 
1212
1281
  protected
1213
1282
 
1214
- def is_a_image(obj)
1283
+ def is_an_image(obj)
1215
1284
  unless obj.kind_of? Magick::Image
1216
1285
  Kernel.raise ArgumentError, "Magick::Image required (#{obj.class} given)"
1217
1286
  end
@@ -1219,33 +1288,36 @@ protected
1219
1288
  end
1220
1289
 
1221
1290
  # Ensure array is always an array of Magick::Image objects
1222
- def is_a_image_array(ary)
1291
+ def is_an_image_array(ary)
1223
1292
  unless ary.respond_to? :each
1224
1293
  Kernel.raise ArgumentError, "Magick::ImageList or array of Magick::Images required (#{ary.class} given)"
1225
1294
  end
1226
- ary.each { |obj| is_a_image obj }
1295
+ ary.each { |obj| is_an_image obj }
1227
1296
  true
1228
1297
  end
1229
1298
 
1230
- # Find old current image, update @scene
1231
- # cfid is the id of the old current image.
1232
- def set_cf(cfid)
1233
- if length == 0
1234
- @scene = nil
1299
+ # Find old current image, update scene number
1300
+ # current is the id of the old current image.
1301
+ def set_current(current)
1302
+ if length() == 0
1303
+ self.scene = nil
1235
1304
  return
1236
1305
  # Don't bother looking for current image
1237
- elsif @scene == nil || @scene >= length
1238
- @scene = length - 1
1306
+ elsif scene() == nil || scene() >= length()
1307
+ self.scene = length() - 1
1239
1308
  return
1240
- elsif cfid != nil
1309
+ elsif current != nil
1310
+ # Find last instance of "current" in the list.
1311
+ # If "current" isn't in the list, set current to last image.
1312
+ self.scene = length() - 1
1241
1313
  each_with_index do |f,i|
1242
- if f.__id__ == cfid
1243
- @scene = i
1244
- return
1314
+ if f.__id__ == current
1315
+ self.scene = i
1245
1316
  end
1246
1317
  end
1318
+ return
1247
1319
  end
1248
- @scene = length - 1
1320
+ self.scene = length() - 1
1249
1321
  end
1250
1322
 
1251
1323
  public
@@ -1253,10 +1325,10 @@ public
1253
1325
  # Allow scene to be set to nil
1254
1326
  def scene=(n)
1255
1327
  if n.nil?
1256
- Kernel.raise IndexError, "scene number out of bounds" unless length == 0
1328
+ Kernel.raise IndexError, "scene number out of bounds" unless @images.length == 0
1257
1329
  @scene = nil
1258
1330
  return @scene
1259
- elsif length == 0
1331
+ elsif @images.length == 0
1260
1332
  Kernel.raise IndexError, "scene number out of bounds"
1261
1333
  end
1262
1334
 
@@ -1268,307 +1340,46 @@ public
1268
1340
  return @scene
1269
1341
  end
1270
1342
 
1271
- def [](*args)
1272
- if (args.length > 1) || args[0].kind_of?(Range)
1273
- self.class.new.replace super
1274
- else
1275
- super
1276
- end
1277
- end
1278
-
1279
- def []=(*args)
1280
- if args.length == 3 # f[start,length] = [f1,f2...]
1281
- args[2].kind_of?(Magick::Image) || is_a_image_array(args[2])
1282
- super
1283
- args[0] = args[0] + length if (args[0] < 0)
1284
- args[1] = length - args[0] if (args[0] + args[1] > length)
1285
- if args[2].kind_of?(Magick::Image)
1286
- @scene = args[0]
1287
- else
1288
- @scene = args[0] + args[2].length - 1
1343
+ # All the binary operators work the same way.
1344
+ # 'other' should be either an ImageList or an Array
1345
+ %w{& + - |}.each do |op|
1346
+ module_eval <<-END_BINOPS
1347
+ def #{op}(other)
1348
+ ilist = self.class.new
1349
+ begin
1350
+ a = other #{op} @images
1351
+ rescue TypeError
1352
+ Kernel.raise ArgumentError, "Magick::ImageList expected, got " + other.class.to_s
1353
+ end
1354
+ current = get_current()
1355
+ a.each do |image|
1356
+ is_an_image image
1357
+ ilist << image
1358
+ end
1359
+ ilist.set_current current
1360
+ return ilist
1289
1361
  end
1290
- elsif args[0].kind_of? Range # f[first..last] = [f1,f2...]
1291
- args[1].kind_of?(Magick::Image) || is_a_image_array(args[1])
1292
- super
1293
- @scene = args[0].end
1294
- else # f[index] = f1
1295
- is_a_image args[1]
1296
- super # index can be negative
1297
- @scene = args[0] < 0 ? length + args[0] : args[0]
1298
- end
1299
- args.last # return value is always assigned value
1300
- end
1301
-
1302
- def &(other)
1303
- is_a_image_array other
1304
- cfid = self[@scene].__id__ rescue nil
1305
- a = self.class.new.replace super
1306
- a.set_cf cfid
1307
- return a
1362
+ END_BINOPS
1308
1363
  end
1309
1364
 
1310
1365
  def *(n)
1311
1366
  unless n.kind_of? Integer
1312
1367
  Kernel.raise ArgumentError, "Integer required (#{n.class} given)"
1313
1368
  end
1314
- cfid = self[@scene].__id__ rescue nil
1315
- a = self.class.new.replace super
1316
- a.set_cf cfid
1317
- return a
1318
- end
1319
-
1320
- def +(other)
1321
- cfid = self[@scene].__id__ rescue nil
1322
- a = self.class.new.replace super
1323
- a.set_cf cfid
1324
- return a
1325
- end
1326
-
1327
- def -(other)
1328
- is_a_image_array other
1329
- cfid = self[@scene].__id__ rescue nil
1330
- a = self.class.new.replace super
1331
- a.set_cf cfid
1332
- return a
1369
+ current = get_current()
1370
+ ilist = self.class.new
1371
+ (@images * n).each {|image| ilist << image}
1372
+ ilist.set_current current
1373
+ return ilist
1333
1374
  end
1334
1375
 
1335
1376
  def <<(obj)
1336
- is_a_image obj
1337
- a = super
1338
- @scene = length-1
1339
- return a
1340
- end
1341
-
1342
- def |(other)
1343
- is_a_image_array other
1344
- cfid = self[@scene].__id__ rescue nil
1345
- a = self.class.new.replace super
1346
- a.set_cf cfid
1347
- return a
1348
- end
1349
-
1350
- def clear
1351
- @scene = nil
1352
- super
1353
- end
1354
-
1355
- def collect(&block)
1356
- cfid = self[@scene].__id__ rescue nil
1357
- a = self.class.new.replace super
1358
- a.set_cf cfid
1359
- return a
1360
- end
1361
-
1362
- def collect!(&block)
1363
- super
1364
- is_a_image_array self
1377
+ is_an_image obj
1378
+ @images << obj
1379
+ @scene = @images.length - 1
1365
1380
  self
1366
1381
  end
1367
1382
 
1368
- def compact
1369
- cfid = self[@scene].__id__ rescue nil
1370
- a = self.class.new.replace super
1371
- a.set_cf cfid
1372
- return a
1373
- end
1374
-
1375
- def compact!
1376
- cfid = self[@scene].__id__ rescue nil
1377
- a = super # returns nil if no changes were made
1378
- set_cf cfid
1379
- return a
1380
- end
1381
-
1382
- def concat(other)
1383
- is_a_image_array other
1384
- a = super
1385
- @scene = length-1
1386
- return a
1387
- end
1388
-
1389
- def delete(obj, &block)
1390
- is_a_image obj
1391
- cfid = self[@scene].__id__ rescue nil
1392
- a = super
1393
- set_cf cfid
1394
- return a
1395
- end
1396
-
1397
- def delete_at(ndx)
1398
- cfid = self[@scene].__id__ rescue nil
1399
- a = super
1400
- set_cf cfid
1401
- return a
1402
- end
1403
-
1404
- def delete_if(&block)
1405
- cfid = self[@scene].__id__ rescue nil
1406
- a = super
1407
- set_cf cfid
1408
- return a
1409
- end
1410
-
1411
- def fill(*args, &block)
1412
- is_a_image args[0] unless block_given?
1413
- cfid = self[@scene].__id__ rescue nil
1414
- super
1415
- is_a_image_array self
1416
- set_cf cfid
1417
- return self
1418
- end
1419
-
1420
- def find_all(&block)
1421
- cfid = self[@scene].__id__ rescue nil
1422
- a = super
1423
- a.set_cf cfid
1424
- return a
1425
- end
1426
-
1427
- if self.superclass.instance_methods(true).include? 'insert' then
1428
- def insert(*args)
1429
- Kernel.raise(ArgumentError, "can't insert nil") unless args.length > 1
1430
- is_a_image_array args[1,args.length-1]
1431
- cfid = self[@scene].__id__ rescue nil
1432
- super
1433
- set_cf cfid
1434
- return self
1435
- end
1436
- end
1437
-
1438
- # Enumerable (or Array) has a #map method that conflicts with our
1439
- # own #map method. RMagick.so has defined a synonym for that #map
1440
- # called Array#__ary_map__. Here, we define Magick::ImageList#__map__
1441
- # to allow the use of the Enumerable/Array#map method on ImageList objects.
1442
- def __map__(&block)
1443
- cfid = self[@scene].__id__ rescue nil
1444
- ensure_image = Proc.new do |img|
1445
- rv = block.call(img)
1446
- is_a_image rv
1447
- return rv
1448
- end
1449
- a = self.class.new.replace __ary_map__(&ensure_image)
1450
- a.set_cf cfid
1451
- return a
1452
- end
1453
-
1454
- def map!(&block)
1455
- ensure_image = Proc.new do |img|
1456
- rv = block.call(img)
1457
- is_a_image rv
1458
- return rv
1459
- end
1460
- super(&ensure_image)
1461
- end
1462
-
1463
- def pop
1464
- cfid = self[@scene].__id__ rescue nil
1465
- a = super # can return nil
1466
- set_cf cfid
1467
- return a
1468
- end
1469
-
1470
- def push(*objs)
1471
- objs.each { |o| is_a_image o }
1472
- super
1473
- @scene = length - 1
1474
- self
1475
- end
1476
-
1477
- def reject(&block)
1478
- cfid = self[@scene].__id__ rescue nil
1479
- a = self.class.new.replace super
1480
- a.set_cf cfid
1481
- return a
1482
- end
1483
-
1484
- def reject!(&block)
1485
- cfid = self[@scene].__id__ rescue nil
1486
- a = super # can return nil
1487
- set_cf cfid
1488
- return a
1489
- end
1490
-
1491
- def replace(other)
1492
- is_a_image_array other
1493
- # Since replace gets called so frequently when @scene == nil
1494
- # test for it instead of letting rescue catch it.
1495
- cfid = nil
1496
- if @scene then
1497
- cfid = self[@scene].__id__ rescue nil
1498
- end
1499
- super
1500
- # set_cf will fail if the new list has fewer images
1501
- # than the scene number indicates.
1502
- @scene = self.length == 0 ? nil : 0
1503
- set_cf cfid
1504
- self
1505
- end
1506
-
1507
- def reverse
1508
- cfid = self[@scene].__id__ rescue nil
1509
- a = self.class.new.replace super
1510
- a.set_cf cfid
1511
- return a
1512
- end
1513
-
1514
- def reverse!
1515
- cfid = self[@scene].__id__ rescue nil
1516
- a = super
1517
- set_cf cfid
1518
- return a
1519
- end
1520
-
1521
- def select(&block)
1522
- cfid = self[@scene].__id__ rescue nil
1523
- a = self.class.new.replace super
1524
- a.set_cf cfid
1525
- return a
1526
- end
1527
-
1528
- def shift
1529
- cfid = self[@scene].__id__ rescue nil
1530
- a = super
1531
- set_cf cfid
1532
- return a
1533
- end
1534
-
1535
- def slice(*args)
1536
- self[*args]
1537
- end
1538
-
1539
- def slice!(*args)
1540
- cfid = self[@scene].__id__ rescue nil
1541
- if args.length > 1 || args[0].kind_of?(Range)
1542
- a = self.class.new.replace super
1543
- else
1544
- a = super
1545
- end
1546
- set_cf cfid
1547
- return a
1548
- end
1549
-
1550
- def uniq
1551
- cfid = self[@scene].__id__ rescue nil
1552
- a = self.class.new.replace super
1553
- a.set_cf cfid
1554
- return a
1555
- end
1556
-
1557
- def uniq!(*args)
1558
- cfid = self[@scene].__id__ rescue nil
1559
- a = super
1560
- set_cf cfid
1561
- return a
1562
- end
1563
-
1564
- # @scene -> new object
1565
- def unshift(obj)
1566
- is_a_image obj
1567
- a = super
1568
- @scene = 0
1569
- return a
1570
- end
1571
-
1572
1383
  # Compare ImageLists
1573
1384
  # Compare each image in turn until the result of a comparison
1574
1385
  # is not 0. If all comparisons return 0, then
@@ -1595,16 +1406,78 @@ public
1595
1406
  return self.length <=> other.length
1596
1407
  end
1597
1408
 
1409
+ def [](*args)
1410
+ a = @images[*args]
1411
+ if a.respond_to?(:each) then
1412
+ ilist = self.class.new
1413
+ a.each {|image| ilist << image}
1414
+ a = ilist
1415
+ end
1416
+ return a
1417
+ end
1418
+
1419
+ def []=(*args)
1420
+ obj = @images.[]=(*args)
1421
+ if obj && obj.respond_to?(:each) then
1422
+ is_an_image_array(obj)
1423
+ set_current obj.last.__id__
1424
+ elsif obj
1425
+ is_an_image(obj)
1426
+ set_current obj.__id__
1427
+ else
1428
+ set_current nil
1429
+ end
1430
+ return obj
1431
+ end
1432
+
1433
+ [:at, :each, :each_index, :empty?, :fetch,
1434
+ :first, :hash, :include?, :index, :length, :rindex, :sort!].each do |mth|
1435
+ module_eval <<-END_SIMPLE_DELEGATES
1436
+ def #{mth}(*args, &block)
1437
+ @images.#{mth}(*args, &block)
1438
+ end
1439
+ END_SIMPLE_DELEGATES
1440
+ end
1441
+ alias_method :size, :length
1442
+
1443
+ # Array#nitems is not available in 1.9
1444
+ if Array.instance_methods.include?("nitems")
1445
+ def nitems()
1446
+ @images.nitems()
1447
+ end
1448
+ end
1449
+
1450
+ def clear
1451
+ @scene = nil
1452
+ @images.clear
1453
+ end
1454
+
1598
1455
  def clone
1599
1456
  ditto = dup
1600
1457
  ditto.freeze if frozen?
1601
1458
  return ditto
1602
1459
  end
1603
1460
 
1461
+ # override Enumerable#collect
1462
+ def collect(&block)
1463
+ current = get_current()
1464
+ a = @images.collect(&block)
1465
+ ilist = self.class.new
1466
+ a.each {|image| ilist << image}
1467
+ ilist.set_current current
1468
+ return ilist
1469
+ end
1470
+
1471
+ def collect!(&block)
1472
+ @images.collect!(&block)
1473
+ is_an_image_array @images
1474
+ self
1475
+ end
1476
+
1604
1477
  # Make a deep copy
1605
1478
  def copy
1606
1479
  ditto = self.class.new
1607
- each { |f| ditto << f.copy }
1480
+ @images.each { |f| ditto << f.copy }
1608
1481
  ditto.scene = @scene
1609
1482
  ditto.taint if tainted?
1610
1483
  return ditto
@@ -1615,7 +1488,38 @@ public
1615
1488
  if ! @scene
1616
1489
  Kernel.raise IndexError, "no images in this list"
1617
1490
  end
1618
- self[@scene]
1491
+ @images[@scene]
1492
+ end
1493
+
1494
+ # ImageList#map took over the "map" name. Use alternatives.
1495
+ alias_method :__map__, :collect
1496
+ alias_method :map!, :collect!
1497
+ alias_method :__map__!, :collect!
1498
+
1499
+ # ImageMagic used affinity in 6.4.3, switch to remap in 6.4.4.
1500
+ alias_method :affinity, :remap
1501
+
1502
+ def compact
1503
+ current = get_current()
1504
+ ilist = self.class.new
1505
+ a = @images.compact
1506
+ a.each {|image| ilist << image}
1507
+ ilist.set_current current
1508
+ return ilist
1509
+ end
1510
+
1511
+ def compact!
1512
+ current = get_current()
1513
+ a = @images.compact! # returns nil if no changes were made
1514
+ set_current current
1515
+ return a.nil? ? nil : self
1516
+ end
1517
+
1518
+ def concat(other)
1519
+ is_an_image_array other
1520
+ other.each {|image| @images << image}
1521
+ @scene = length-1
1522
+ return self
1619
1523
  end
1620
1524
 
1621
1525
  # Set same delay for all images
@@ -1623,40 +1527,87 @@ public
1623
1527
  if Integer(d) < 0
1624
1528
  raise ArgumentError, "delay must be greater than or equal to 0"
1625
1529
  end
1626
- each { |f| f.delay = Integer(d) }
1530
+ @images.each { |f| f.delay = Integer(d) }
1627
1531
  end
1628
1532
 
1629
- def ticks_per_second=(t)
1630
- if Integer(t) < 0
1631
- Kernel.raise ArgumentError, "ticks_per_second must be greater than or equal to 0"
1632
- end
1633
- each { |f| f.ticks_per_second = Integer(t) }
1533
+ def delete(obj, &block)
1534
+ is_an_image obj
1535
+ current = get_current()
1536
+ a = @images.delete(obj, &block)
1537
+ set_current current
1538
+ return a
1539
+ end
1540
+
1541
+ def delete_at(ndx)
1542
+ current = get_current()
1543
+ a = @images.delete_at(ndx)
1544
+ set_current current
1545
+ return a
1546
+ end
1547
+
1548
+ def delete_if(&block)
1549
+ current = get_current()
1550
+ @images.delete_if(&block)
1551
+ set_current current
1552
+ self
1634
1553
  end
1635
1554
 
1636
1555
  def dup
1637
1556
  ditto = self.class.new
1638
- each {|img| ditto << img}
1557
+ @images.each {|img| ditto << img}
1639
1558
  ditto.scene = @scene
1640
1559
  ditto.taint if tainted?
1641
1560
  return ditto
1642
1561
  end
1643
1562
 
1563
+ def eql?(other)
1564
+ is_an_image_array other
1565
+ eql = other.eql?(@images)
1566
+ begin # "other" is another ImageList
1567
+ eql &&= @scene == other.scene
1568
+ rescue NoMethodError
1569
+ # "other" is a plain Array
1570
+ end
1571
+ return eql
1572
+ end
1573
+
1574
+ def fill(*args, &block)
1575
+ is_an_image args[0] unless block_given?
1576
+ current = get_current()
1577
+ @images.fill(*args, &block)
1578
+ is_an_image_array self
1579
+ set_current current
1580
+ self
1581
+ end
1582
+
1583
+ # Override Enumerable's find_all
1584
+ def find_all(&block)
1585
+ current = get_current()
1586
+ a = @images.find_all(&block)
1587
+ ilist = self.class.new
1588
+ a.each {|image| ilist << image}
1589
+ ilist.set_current current
1590
+ return ilist
1591
+ end
1592
+ alias_method :select, :find_all
1593
+
1644
1594
  def from_blob(*blobs, &block)
1645
1595
  if (blobs.length == 0)
1646
1596
  Kernel.raise ArgumentError, "no blobs given"
1647
1597
  end
1648
1598
  blobs.each { |b|
1649
- Magick::Image.from_blob(b, &block).each { |n| self << n }
1599
+ Magick::Image.from_blob(b, &block).each { |n| @images << n }
1650
1600
  }
1651
1601
  @scene = length - 1
1652
1602
  self
1653
1603
  end
1654
1604
 
1655
1605
  # Initialize new instances
1656
- def initialize(*filenames)
1606
+ def initialize(*filenames, &block)
1607
+ @images = []
1657
1608
  @scene = nil
1658
1609
  filenames.each { |f|
1659
- Magick::Image.read(f).each { |n| self << n }
1610
+ Magick::Image.read(f, &block).each { |n| @images << n }
1660
1611
  }
1661
1612
  if length > 0
1662
1613
  @scene = length - 1 # last image in array
@@ -1664,11 +1615,19 @@ public
1664
1615
  self
1665
1616
  end
1666
1617
 
1618
+ def insert(index, *args)
1619
+ args.each {|image| is_an_image image}
1620
+ current = get_current()
1621
+ @images.insert(index, *args)
1622
+ set_current current
1623
+ return self
1624
+ end
1625
+
1667
1626
  # Call inspect for all the images
1668
1627
  def inspect
1669
- ins = '['
1670
- each {|image| ins << image.inspect << "\n"}
1671
- ins.chomp("\n") + "]\nscene=#{@scene}"
1628
+ img = []
1629
+ @images.each {|image| img << image.inspect }
1630
+ img = "[" + img.join(",\n") + "]\nscene=#{@scene}"
1672
1631
  end
1673
1632
 
1674
1633
  # Set the number of iterations of an animated GIF
@@ -1677,10 +1636,36 @@ public
1677
1636
  if n < 0 || n > 65535
1678
1637
  Kernel.raise ArgumentError, "iterations must be between 0 and 65535"
1679
1638
  end
1680
- each {|f| f.iterations=n}
1639
+ @images.each {|f| f.iterations=n}
1681
1640
  self
1682
1641
  end
1683
1642
 
1643
+ def last(*args)
1644
+ if args.length == 0
1645
+ a = @images.last
1646
+ else
1647
+ a = @images.last(*args)
1648
+ ilist = self.class.new
1649
+ a.each {|img| ilist << img}
1650
+ @scene = a.length - 1
1651
+ a = ilist
1652
+ end
1653
+ return a
1654
+ end
1655
+
1656
+ # Custom marshal/unmarshal for Ruby 1.8.
1657
+ def marshal_dump()
1658
+ ary = [@scene]
1659
+ @images.each {|i| ary << Marshal.dump(i)}
1660
+ ary
1661
+ end
1662
+
1663
+ def marshal_load(ary)
1664
+ @scene = ary.shift
1665
+ @images = []
1666
+ ary.each {|a| @images << Marshal.load(a)}
1667
+ end
1668
+
1684
1669
  # The ImageList class supports the Magick::Image class methods by simply sending
1685
1670
  # the method to the current image. If the method isn't explicitly supported,
1686
1671
  # send it to the current image in the array. If there are no images, send
@@ -1688,7 +1673,7 @@ public
1688
1673
  def method_missing(methID, *args, &block)
1689
1674
  begin
1690
1675
  if @scene
1691
- self[@scene].send(methID, *args, &block)
1676
+ @images[@scene].send(methID, *args, &block)
1692
1677
  else
1693
1678
  super
1694
1679
  end
@@ -1700,47 +1685,230 @@ public
1700
1685
  end
1701
1686
  end
1702
1687
 
1703
- # Ensure respond_to? answers correctly when we are delegating to Image
1704
- alias_method :__respond_to__?, :respond_to?
1705
- def respond_to?(methID, priv=false)
1706
- return true if __respond_to__?(methID, priv)
1707
- if @scene
1708
- self[@scene].respond_to?(methID, priv)
1709
- else
1710
- super
1711
- end
1712
- end
1713
-
1714
1688
  # Create a new image and add it to the end
1715
1689
  def new_image(cols, rows, *fill, &info_blk)
1716
1690
  self << Magick::Image.new(cols, rows, *fill, &info_blk)
1717
1691
  end
1718
1692
 
1693
+ def partition(&block)
1694
+ a = @images.partition(&block)
1695
+ t = self.class.new
1696
+ a[0].each { |img| t << img}
1697
+ t.set_current nil
1698
+ f = self.class.new
1699
+ a[1].each { |img| f << img}
1700
+ f.set_current nil
1701
+ [t, f]
1702
+ end
1703
+
1719
1704
  # Ping files and concatenate the new images
1720
1705
  def ping(*files, &block)
1721
1706
  if (files.length == 0)
1722
1707
  Kernel.raise ArgumentError, "no files given"
1723
1708
  end
1724
1709
  files.each { |f|
1725
- Magick::Image.ping(f, &block).each { |n| self << n }
1710
+ Magick::Image.ping(f, &block).each { |n| @images << n }
1726
1711
  }
1727
1712
  @scene = length - 1
1728
1713
  self
1729
1714
  end
1730
1715
 
1716
+ def pop
1717
+ current = get_current()
1718
+ a = @images.pop # can return nil
1719
+ set_current current
1720
+ return a
1721
+ end
1722
+
1723
+ def push(*objs)
1724
+ objs.each do |image|
1725
+ is_an_image image
1726
+ @images << image
1727
+ end
1728
+ @scene = length - 1
1729
+ self
1730
+ end
1731
+
1731
1732
  # Read files and concatenate the new images
1732
1733
  def read(*files, &block)
1733
1734
  if (files.length == 0)
1734
1735
  Kernel.raise ArgumentError, "no files given"
1735
1736
  end
1736
1737
  files.each { |f|
1737
- Magick::Image.read(f, &block).each { |n| self << n }
1738
+ Magick::Image.read(f, &block).each { |n| @images << n }
1738
1739
  }
1739
1740
  @scene = length - 1
1740
1741
  self
1741
1742
  end
1743
+
1744
+ # override Enumerable's reject
1745
+ def reject(&block)
1746
+ current = get_current()
1747
+ ilist = self.class.new
1748
+ a = @images.reject(&block)
1749
+ a.each {|image| ilist << image}
1750
+ ilist.set_current current
1751
+ return ilist
1752
+ end
1753
+
1754
+ def reject!(&block)
1755
+ current = get_current()
1756
+ a = @images.reject!(&block)
1757
+ @images = a if !a.nil?
1758
+ set_current current
1759
+ return a.nil? ? nil : self
1760
+ end
1761
+
1762
+ def replace(other)
1763
+ is_an_image_array other
1764
+ current = get_current()
1765
+ @images.clear
1766
+ other.each {|image| @images << image}
1767
+ @scene = self.length == 0 ? nil : 0
1768
+ set_current current
1769
+ self
1770
+ end
1771
+
1772
+ # Ensure respond_to? answers correctly when we are delegating to Image
1773
+ alias_method :__respond_to__?, :respond_to?
1774
+ def respond_to?(methID, priv=false)
1775
+ return true if __respond_to__?(methID, priv)
1776
+ if @scene
1777
+ @images[@scene].respond_to?(methID, priv)
1778
+ else
1779
+ super
1780
+ end
1781
+ end
1782
+
1783
+ def reverse
1784
+ current = get_current()
1785
+ a = self.class.new
1786
+ @images.reverse_each {|image| a << image}
1787
+ a.set_current current
1788
+ return a
1789
+ end
1790
+
1791
+ def reverse!
1792
+ current = get_current()
1793
+ @images.reverse!
1794
+ set_current current
1795
+ self
1796
+ end
1797
+
1798
+ def reverse_each
1799
+ @images.reverse_each {|image| yield(image)}
1800
+ self
1801
+ end
1802
+
1803
+ def shift
1804
+ current = get_current()
1805
+ a = @images.shift
1806
+ set_current current
1807
+ return a
1808
+ end
1809
+
1810
+ def slice(*args)
1811
+ current = get_current()
1812
+ slice = @images.slice(*args)
1813
+ if slice
1814
+ ilist = self.class.new
1815
+ if slice.respond_to?(:each) then
1816
+ slice.each {|image| ilist << image}
1817
+ else
1818
+ ilist << slice
1819
+ end
1820
+ else
1821
+ ilist = nil
1822
+ end
1823
+ return ilist
1824
+ end
1825
+
1826
+ def slice!(*args)
1827
+ current = get_current()
1828
+ a = @images.slice!(*args)
1829
+ set_current current
1830
+ return a
1831
+ end
1832
+
1833
+ def ticks_per_second=(t)
1834
+ if Integer(t) < 0
1835
+ Kernel.raise ArgumentError, "ticks_per_second must be greater than or equal to 0"
1836
+ end
1837
+ @images.each { |f| f.ticks_per_second = Integer(t) }
1838
+ end
1839
+
1840
+ def to_a
1841
+ a = Array.new
1842
+ @images.each {|image| a << image}
1843
+ return a
1844
+ end
1845
+
1846
+ def uniq
1847
+ current = get_current()
1848
+ a = self.class.new
1849
+ @images.uniq.each {|image| a << image}
1850
+ a.set_current current
1851
+ return a
1852
+ end
1853
+
1854
+ def uniq!(*args)
1855
+ current = get_current()
1856
+ a = @images.uniq!
1857
+ set_current current
1858
+ return a.nil? ? nil : self
1859
+ end
1860
+
1861
+ # @scene -> new object
1862
+ def unshift(obj)
1863
+ is_an_image obj
1864
+ @images.unshift(obj)
1865
+ @scene = 0
1866
+ self
1867
+ end
1868
+
1869
+ def values_at(*args)
1870
+ a = @images.values_at(*args)
1871
+ a = self.class.new
1872
+ @images.values_at(*args).each {|image| a << image}
1873
+ a.scene = a.length - 1
1874
+ return a
1875
+ end
1876
+ alias_method :indexes, :values_at
1877
+ alias_method :indices, :values_at
1878
+
1742
1879
  end # Magick::ImageList
1743
1880
 
1881
+
1882
+ # Collects non-specific optional method arguments
1883
+ class OptionalMethodArguments
1884
+ def initialize(img)
1885
+ @img = img
1886
+ end
1887
+
1888
+ # miscellaneous options like -verbose
1889
+ def method_missing(mth, val)
1890
+ @img.define(mth.to_s.tr('_', '-'), val)
1891
+ end
1892
+
1893
+ # set(key, val) corresponds to -set option:key val
1894
+ def define(key, val = nil)
1895
+ @img.define(key, val)
1896
+ end
1897
+
1898
+ # accepts Pixel object or color name
1899
+ def highlight_color=(color)
1900
+ color = @img.to_color(color) if color.respond_to?(:to_color)
1901
+ @img.define("highlight-color", color)
1902
+ end
1903
+
1904
+ # accepts Pixel object or color name
1905
+ def lowlight_color=(color)
1906
+ color = @img.to_color(color) if color.respond_to?(:to_color)
1907
+ @img.define("lowlight-color", color)
1908
+ end
1909
+ end
1910
+
1911
+
1744
1912
  # Example fill class. Fills the image with the specified background
1745
1913
  # color, then crosshatches with the specified crosshatch color.
1746
1914
  # @dist is the number of pixels between hatch lines.
@@ -1766,3 +1934,4 @@ class HatchFill
1766
1934
  end
1767
1935
 
1768
1936
  end # Magick
1937
+