rmagick4j 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. data/History.txt +84 -0
  2. data/LICENSE.txt +9 -0
  3. data/Manifest.txt +142 -0
  4. data/README.txt +25 -0
  5. data/Rakefile +109 -0
  6. data/lib/RMagick.rb +1861 -0
  7. data/lib/jhlabs-filters.jar +0 -0
  8. data/lib/magick4j.jar +0 -0
  9. data/lib/rmagick4j/constants.rb +21 -0
  10. data/lib/rmagick4j/draw.rb +86 -0
  11. data/lib/rmagick4j/enum.rb +120 -0
  12. data/lib/rmagick4j/gradient_fill.rb +14 -0
  13. data/lib/rmagick4j/image.rb +289 -0
  14. data/lib/rmagick4j/image_list.rb +21 -0
  15. data/lib/rmagick4j/pixel.rb +170 -0
  16. data/lib/rmagick4j/rmagick4j.rb +19 -0
  17. data/lib/rmagick4j/texture_fill.rb +14 -0
  18. data/lib/rmagick4j/type_metric.rb +8 -0
  19. data/lib/rmagick4j/version.rb +5 -0
  20. data/lib/rvg/clippath.rb +48 -0
  21. data/lib/rvg/container.rb +131 -0
  22. data/lib/rvg/deep_equal.rb +56 -0
  23. data/lib/rvg/describable.rb +53 -0
  24. data/lib/rvg/embellishable.rb +417 -0
  25. data/lib/rvg/misc.rb +739 -0
  26. data/lib/rvg/paint.rb +55 -0
  27. data/lib/rvg/pathdata.rb +131 -0
  28. data/lib/rvg/rvg.rb +283 -0
  29. data/lib/rvg/stretchable.rb +168 -0
  30. data/lib/rvg/stylable.rb +118 -0
  31. data/lib/rvg/text.rb +187 -0
  32. data/lib/rvg/transformable.rb +133 -0
  33. data/lib/rvg/units.rb +66 -0
  34. data/lib/svgsalamander.jar +0 -0
  35. data/test/RMagickTestSuite.rb +129 -0
  36. data/test/eyetests/bullseye.rb +150 -0
  37. data/test/eyetests/tests/draw_arc_basic.rb +16 -0
  38. data/test/eyetests/tests/draw_circle_affine.rb +19 -0
  39. data/test/eyetests/tests/draw_circle_basic.rb +16 -0
  40. data/test/eyetests/tests/draw_ellipse_affine.rb +19 -0
  41. data/test/eyetests/tests/draw_ellipse_basic.rb +16 -0
  42. data/test/eyetests/tests/draw_line_affine.rb +24 -0
  43. data/test/eyetests/tests/draw_line_basic.rb +20 -0
  44. data/test/eyetests/tests/draw_pattern_1.rb +35 -0
  45. data/test/eyetests/tests/draw_polygon_affine.rb +21 -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_rectangle_affine.rb +16 -0
  50. data/test/eyetests/tests/draw_rectangle_basic.rb +16 -0
  51. data/test/eyetests/tests/draw_rmagick_test_01.rb +35 -0
  52. data/test/eyetests/tests/draw_rmagick_test_02.rb +40 -0
  53. data/test/eyetests/tests/draw_rmagick_test_03.rb +17 -0
  54. data/test/eyetests/tests/draw_rmagick_test_04.rb +21 -0
  55. data/test/eyetests/tests/draw_roundrectangle_affine.rb +19 -0
  56. data/test/eyetests/tests/draw_roundrectangle_basic.rb +16 -0
  57. data/test/eyetests/tests/gradient_fill_horizontal_diagonal_fill.rb +9 -0
  58. data/test/eyetests/tests/gradient_fill_horizontal_fill.rb +9 -0
  59. data/test/eyetests/tests/gradient_fill_point_fill.rb +9 -0
  60. data/test/eyetests/tests/gradient_fill_vertical_diagonal_fill.rb +9 -0
  61. data/test/eyetests/tests/gradient_fill_vertical_fill.rb +9 -0
  62. data/test/eyetests/tests/gruff_accumulator_bar.rb +29 -0
  63. data/test/eyetests/tests/gruff_area_1.rb +16 -0
  64. data/test/eyetests/tests/gruff_area_2.rb +27 -0
  65. data/test/eyetests/tests/gruff_bar_1.rb +29 -0
  66. data/test/eyetests/tests/gruff_bar_2.rb +19 -0
  67. data/test/eyetests/tests/gruff_line_1.rb +13 -0
  68. data/test/eyetests/tests/gruff_line_2.rb +20 -0
  69. data/test/eyetests/tests/gruff_net_1.rb +16 -0
  70. data/test/eyetests/tests/gruff_net_2.rb +16 -0
  71. data/test/eyetests/tests/gruff_pie_1.rb +21 -0
  72. data/test/eyetests/tests/gruff_pie_2.rb +22 -0
  73. data/test/eyetests/tests/gruff_scene_1.rb +14 -0
  74. data/test/eyetests/tests/gruff_scene_2.rb +14 -0
  75. data/test/eyetests/tests/gruff_sidebar.rb +32 -0
  76. data/test/eyetests/tests/gruff_sidestacked_bar_1.rb +26 -0
  77. data/test/eyetests/tests/gruff_sidestacked_bar_2.rb +26 -0
  78. data/test/eyetests/tests/gruff_spider_1.rb +22 -0
  79. data/test/eyetests/tests/gruff_spider_2.rb +15 -0
  80. data/test/eyetests/tests/gruff_stacked_bar_1.rb +23 -0
  81. data/test/eyetests/tests/gruff_stacked_bar_2.rb +26 -0
  82. data/test/eyetests/tests/hatch_fill.rb +9 -0
  83. data/test/eyetests/tests/image_list_flatten_images.rb +15 -0
  84. data/test/eyetests/tests/new_image.rb +24 -0
  85. data/test/eyetests/tests/path_a_command_01.rb +16 -0
  86. data/test/eyetests/tests/path_a_command_02.rb +19 -0
  87. data/test/eyetests/tests/path_c_command_01.rb +16 -0
  88. data/test/eyetests/tests/path_c_command_02.rb +16 -0
  89. data/test/eyetests/tests/path_complex_01.rb +16 -0
  90. data/test/eyetests/tests/path_espiral_01.rb +28 -0
  91. data/test/eyetests/tests/path_h_command_01.rb +16 -0
  92. data/test/eyetests/tests/path_h_command_02.rb +16 -0
  93. data/test/eyetests/tests/path_l_command_01.rb +16 -0
  94. data/test/eyetests/tests/path_l_command_02.rb +16 -0
  95. data/test/eyetests/tests/path_m_command_01.rb +16 -0
  96. data/test/eyetests/tests/path_m_command_02.rb +16 -0
  97. data/test/eyetests/tests/path_m_command_03.rb +16 -0
  98. data/test/eyetests/tests/path_q_command_01.rb +16 -0
  99. data/test/eyetests/tests/path_q_command_02.rb +16 -0
  100. data/test/eyetests/tests/path_q_command_03.rb +25 -0
  101. data/test/eyetests/tests/path_s_command_01.rb +16 -0
  102. data/test/eyetests/tests/path_s_command_02.rb +16 -0
  103. data/test/eyetests/tests/path_star_01.rb +16 -0
  104. data/test/eyetests/tests/path_t_command_01.rb +16 -0
  105. data/test/eyetests/tests/path_t_command_02.rb +16 -0
  106. data/test/eyetests/tests/path_v_command_01.rb +16 -0
  107. data/test/eyetests/tests/path_v_command_02.rb +16 -0
  108. data/test/eyetests/tests/store_pixel_smiley.rb +123 -0
  109. data/test/eyetests/tests/texture_fill.rb +11 -0
  110. data/test/gruff_tests/test/gruff_test_case.rb +120 -0
  111. data/test/gruff_tests/test/monkey_gruff.rb +7 -0
  112. data/test/gruff_tests/test/test_accumulator_bar.rb +50 -0
  113. data/test/gruff_tests/test/test_area.rb +134 -0
  114. data/test/gruff_tests/test/test_bar.rb +283 -0
  115. data/test/gruff_tests/test/test_base.rb +8 -0
  116. data/test/gruff_tests/test/test_bullet.rb +26 -0
  117. data/test/gruff_tests/test/test_legend.rb +71 -0
  118. data/test/gruff_tests/test/test_line.rb +493 -0
  119. data/test/gruff_tests/test/test_mini_bar.rb +32 -0
  120. data/test/gruff_tests/test/test_mini_pie.rb +20 -0
  121. data/test/gruff_tests/test/test_mini_side_bar.rb +37 -0
  122. data/test/gruff_tests/test/test_net.rb +230 -0
  123. data/test/gruff_tests/test/test_photo.rb +41 -0
  124. data/test/gruff_tests/test/test_pie.rb +154 -0
  125. data/test/gruff_tests/test/test_scene.rb +100 -0
  126. data/test/gruff_tests/test/test_side_bar.rb +12 -0
  127. data/test/gruff_tests/test/test_sidestacked_bar.rb +89 -0
  128. data/test/gruff_tests/test/test_spider.rb +216 -0
  129. data/test/gruff_tests/test/test_stacked_bar.rb +52 -0
  130. data/test/images/clown.jpg +0 -0
  131. data/test/images/texture.jpg +0 -0
  132. data/test/implemented_methods.rb +18 -0
  133. data/test/spec/draw_spec.rb +24 -0
  134. data/test/spec/image_constants.rb +76 -0
  135. data/test/spec/image_spec.rb +23 -0
  136. data/test/spec/pixel_spec.rb +84 -0
  137. data/test/spec/stories/geometry_runner.rb +13 -0
  138. data/test/spec/stories/geometry_steps.rb +24 -0
  139. data/test/spec/stories/geometry_story.rb +116 -0
  140. data/test/spec/stories/image_filling_runner.rb +13 -0
  141. data/test/spec/stories/image_filling_steps.rb +64 -0
  142. data/test/spec/stories/image_filling_story.rb +41 -0
  143. metadata +215 -0
@@ -0,0 +1,168 @@
1
+ #--
2
+ # $Id: stretchable.rb,v 1.6 2008/02/24 21:52:32 rmagick Exp $
3
+ # Copyright (C) 2008 Timothy P. Hunter
4
+ #++
5
+
6
+ module Magick
7
+ class RVG
8
+
9
+ module PreserveAspectRatio
10
+ #--
11
+ # Included in Stretchable module and Image class
12
+ #++
13
+ # Specifies how the image within a viewport should be scaled.
14
+ # [+align+] a combination of 'xMin', 'xMid', or 'xMax', followed by
15
+ # 'YMin', 'YMid', or 'YMax'
16
+ # [+meet_or_slice+] one of 'meet' or 'slice'
17
+ def preserve_aspect_ratio(align, meet_or_slice='meet')
18
+ @align = align.to_s
19
+ if @align != 'none'
20
+ m = /\A(xMin|xMid|xMax)(YMin|YMid|YMax)\z/.match(@align)
21
+ raise(ArgumentError, "unknown alignment specifier: #{@align}") unless m
22
+ end
23
+
24
+ if meet_or_slice
25
+ meet_or_slice = meet_or_slice.to_s.downcase
26
+ if meet_or_slice == 'meet' || meet_or_slice == 'slice'
27
+ @meet_or_slice = meet_or_slice
28
+ else
29
+ raise(ArgumentError, "specifier must be `meet' or `slice' (got #{meet_or_slice})")
30
+ end
31
+ end
32
+ yield(self) if block_given?
33
+ self
34
+ end
35
+ end # module PreserveAspectRatio
36
+
37
+
38
+ # The methods in this module describe the user-coordinate space.
39
+ # RVG and Pattern objects are stretchable.
40
+ module Stretchable
41
+
42
+ private
43
+ # Scale to fit
44
+ def set_viewbox_none(width, height)
45
+ sx, sy = 1.0, 1.0
46
+
47
+ if @vbx_width
48
+ sx = width / @vbx_width
49
+ end
50
+ if @vbx_height
51
+ sy = height / @vbx_height
52
+ end
53
+
54
+ return [sx, sy]
55
+ end
56
+
57
+ # Use align attribute to compute x- and y-offset from viewport's upper-left corner.
58
+ def align_to_viewport(width, height, sx, sy)
59
+ tx = case @align
60
+ when /\AxMin/
61
+ 0
62
+ when NilClass, /\AxMid/
63
+ (width - @vbx_width*sx) / 2.0
64
+ when /\AxMax/
65
+ width - @vbx_width*sx
66
+ end
67
+
68
+ ty = case @align
69
+ when /YMin\z/
70
+ 0
71
+ when NilClass, /YMid\z/
72
+ (height - @vbx_height*sy) / 2.0
73
+ when /YMax\z/
74
+ height - @vbx_height*sy
75
+ end
76
+ return [tx, ty]
77
+ end
78
+
79
+ # Scale to smaller viewbox dimension
80
+ def set_viewbox_meet(width, height)
81
+ sx = sy = [width / @vbx_width, height / @vbx_height].min
82
+ return [sx, sy]
83
+ end
84
+
85
+ # Scale to larger viewbox dimension
86
+ def set_viewbox_slice(width, height)
87
+ sx = sy = [width / @vbx_width, height / @vbx_height].max
88
+ return [sx, sy]
89
+ end
90
+
91
+ # Establish the viewbox as necessary
92
+ def add_viewbox_primitives(width, height, gc)
93
+ @vbx_width ||= width
94
+ @vbx_height ||= height
95
+ @vbx_x ||= 0.0
96
+ @vbx_y ||= 0.0
97
+
98
+ if @align == 'none'
99
+ sx, sy = set_viewbox_none(width, height)
100
+ tx, ty = 0, 0
101
+ elsif @meet_or_slice == 'meet'
102
+ sx, sy = set_viewbox_meet(width, height)
103
+ tx, ty = align_to_viewport(width, height, sx, sy)
104
+ else
105
+ sx, sy = set_viewbox_slice(width, height)
106
+ tx, ty = align_to_viewport(width, height, sx, sy)
107
+ end
108
+
109
+ # Establish clipping path around the current viewport
110
+ name = __id__.to_s
111
+ gc.define_clip_path(name) do
112
+ gc.path("M0,0 l#{width},0 l0,#{height} l-#{width},0 l0,-#{height}z")
113
+ end
114
+
115
+ gc.clip_path(name)
116
+ # Add a non-scaled translation if meet or slice
117
+ gc.translate(tx, ty) if (tx.abs > 1.0e-10 || ty.abs > 1.0e-10)
118
+ # Scale viewbox as necessary
119
+ gc.scale(sx, sy) if (sx != 1.0 || sy != 1.0)
120
+ # Add a scaled translation if non-0 origin
121
+ gc.translate(-@vbx_x, -@vbx_y) if (@vbx_x.abs != 0.0 || @vbx_y.abs != 0)
122
+ end
123
+
124
+ def initialize(*args, &block)
125
+ super()
126
+ @vbx_x, @vbx_y, @vbx_width, @vbx_height = nil
127
+ @meet_or_slice = 'meet'
128
+ @align = nil
129
+ end
130
+
131
+ public
132
+ include PreserveAspectRatio
133
+
134
+ # Describe a user coordinate system to be imposed on the viewbox.
135
+ # The arguments must be numbers and the +width+ and +height+
136
+ # arguments must be positive.
137
+ def viewbox(x, y, width, height)
138
+ begin
139
+ @vbx_x = Float(x)
140
+ @vbx_y = Float(y)
141
+ @vbx_width = Float(width)
142
+ @vbx_height = Float(height)
143
+ rescue ArgumentError
144
+ raise ArgumentError, "arguments must be convertable to float (got #{x.class}, #{y.class}, #{width.class}, #{height.class})"
145
+ end
146
+ raise(ArgumentError, "viewbox width must be > 0 (#{width} given)") unless width >= 0
147
+ raise(ArgumentError, "viewbox height must be > 0 (#{height} given)") unless height >= 0
148
+
149
+ # return the user-coordinate space attributes if defined
150
+ class << self
151
+ if not defined? @redefined then
152
+ @redefined = true
153
+ define_method(:x) { @vbx_x }
154
+ define_method(:y) { @vbx_y }
155
+ define_method(:width) { @vbx_width}
156
+ define_method(:height) { @vbx_height }
157
+ end
158
+ end
159
+
160
+ yield(self) if block_given?
161
+ self
162
+ end
163
+
164
+ end # module Stretchable
165
+
166
+ end # class RVG
167
+ end # module Magick
168
+
@@ -0,0 +1,118 @@
1
+ #--
2
+ # $Id: stylable.rb,v 1.5 2008/02/24 18:26:37 rmagick Exp $
3
+ # Copyright (C) 2008 Timothy P. Hunter
4
+ #++
5
+
6
+ module Magick
7
+ class RVG
8
+
9
+ #:stopdoc:
10
+ STYLES = [:clip_path, :clip_rule, :fill, :fill_opacity, :fill_rule, :font,
11
+ :font_family, :font_size, :font_stretch, :font_style, :font_weight,
12
+ :opacity, :stroke, :stroke_dasharray, :stroke_dashoffset, :stroke_linecap,
13
+ :stroke_linejoin, :stroke_miterlimit, :stroke_opacity, :stroke_width,
14
+ :text_anchor, :text_decoration,
15
+ :glyph_orientation_vertical, :glyph_orientation_horizontal,
16
+ :letter_spacing, :word_spacing, :baseline_shift, :writing_mode]
17
+
18
+ Styles = Struct.new(*STYLES)
19
+
20
+ # Styles is a Struct class with a couple of extra methods
21
+ class Styles
22
+
23
+ def set(styles)
24
+ begin
25
+ styles.each_pair do |style, value|
26
+ begin
27
+ self[style] = value
28
+ rescue NoMethodError
29
+ raise ArgumentError, "unknown style `#{style}'"
30
+ end
31
+ end
32
+ rescue NoMethodError
33
+ raise ArgumentError, "style arguments must be in the form `style => value'"
34
+ end
35
+ self
36
+ end
37
+
38
+ # Iterate over the style names. Yield for each style that has a value.
39
+ def each_value
40
+ each_pair do |style, value|
41
+ yield(style, value) if value
42
+ end
43
+ end
44
+
45
+ # The "usual" deep_copy method doesn't copy a Struct correctly.
46
+ def deep_copy(h=nil)
47
+ copy = Styles.new
48
+ each_pair { |style, value| copy[style] = value }
49
+ return copy
50
+ end
51
+
52
+ end # class Styles
53
+
54
+ #:startdoc:
55
+
56
+ # This module is mixed into classes that can have styles.
57
+ module Stylable
58
+
59
+ private
60
+
61
+ # For each style that has a value, add a style primitive to the gc.
62
+ # Use splat to splat out Array arguments such as stroke_dasharray.
63
+ def add_style_primitives(gc)
64
+ @styles.each_value do |style, value|
65
+ if value.respond_to? :add_primitives
66
+ value.add_primitives(gc, style)
67
+ else
68
+ gc.__send__(style, *value)
69
+ end
70
+ end
71
+ end
72
+
73
+ def initialize
74
+ super
75
+ @styles = Styles.new
76
+ end
77
+
78
+ public
79
+
80
+ # This method can be used with any RVG, Group, Use, Text, or
81
+ # shape object. The argument is a hash. The style names are
82
+ # the hash keys. The style names and values are:
83
+ # [:clip_path] clipping path defined by clip_path
84
+ # [:clip_rule] 'evenodd' or 'nozero'
85
+ # [:fill] color name
86
+ # [:fill_opacity] the fill opacity, 0.0<=N<=1.0
87
+ # [:fill_rule] 'evenodd' or 'nozero'
88
+ # [:font] font name or font file name
89
+ # [:font_family] font family name, ex. 'serif'
90
+ # [:font_size] font size in points
91
+ # [:font_stretch] 'normal','ultra_condensed','extra_condensed',
92
+ # 'condensed','semi_condensed','semi_expanded',
93
+ # 'expanded','extra_expanded','ultra_expanded'
94
+ # [:font_style] 'normal','italic','oblique'
95
+ # [:font_weight] 'normal','bold','bolder','lighter', or
96
+ # a multiple of 100 between 100 and 900.
97
+ # [:opacity] both fill and stroke opacity, 0.0<=N<=1.0
98
+ # [:stroke] color name
99
+ # [:stroke_dasharray] dash pattern (Array)
100
+ # [:stroke_dashoffset] initial distance into dash pattern
101
+ # [:stroke_linecap] 'butt', 'round', 'square'
102
+ # [:stroke_linejoin] 'miter', 'round', 'bevel'
103
+ # [:stroke_miterlimit] miter length constraint
104
+ # [:stroke_opacity] the stroke opacity, 0.0<=N<=1.0
105
+ # [:stroke_width] stroke width
106
+ # [:text_anchor] 'start','middle','end'
107
+ # [:text_decoration] 'none','underline','overline','line_through'
108
+ def styles(styles)
109
+ @styles.set(styles)
110
+ yield(self) if block_given?
111
+ self
112
+ end
113
+
114
+ end # module Stylable
115
+
116
+ end # class RVG
117
+ end # module Magick
118
+
data/lib/rvg/text.rb ADDED
@@ -0,0 +1,187 @@
1
+ #--
2
+ # $Id: text.rb,v 1.6 2008/02/24 18:26:37 rmagick Exp $
3
+ # Copyright (C) 2008 Timothy P. Hunter
4
+ #++
5
+ # Text-related classes
6
+
7
+ module Magick
8
+ class RVG
9
+
10
+ # Base class for Tspan, Tref and Text.
11
+ class TextBase
12
+ include Stylable
13
+ include Duplicatable
14
+
15
+ private
16
+
17
+ def initialize(text, &block) #:nodoc:
18
+ super()
19
+ @text = text.to_s if text
20
+ @dx = @dy = 0
21
+ @rotation = 0
22
+ @tspans = Content.new
23
+ yield(self) if block_given?
24
+ end
25
+
26
+ public
27
+
28
+ # Create a new text chunk. Each chunk can have its own initial position and styles.
29
+ # If <tt>x</tt> and <tt>y</tt> are omitted the text starts at the current text
30
+ # position.
31
+ def tspan(text, x=nil, y=nil)
32
+ tspan = Tspan.new(text, x, y)
33
+ tspan.parent = self
34
+ @tspans << tspan
35
+ return tspan
36
+ end
37
+
38
+ # Add <tt>x</tt> and <tt>y</tt> to the current text position.
39
+ def d(x, y=0)
40
+ @dx, @dy = Magick::RVG.convert_to_float(x, y)
41
+ yield(self) if block_given?
42
+ self
43
+ end
44
+
45
+ # Rotate the text about the current text position.
46
+ def rotate(degrees)
47
+ @rotation = Magick::RVG.convert_to_float(degrees)[0]
48
+ yield(self) if block_given?
49
+ self
50
+ end
51
+
52
+ # We do our own transformations.
53
+ def add_primitives(gc) #:nodoc:
54
+ if @text || @tspans.length > 0
55
+ gc.push
56
+ x = self.cx + @dx
57
+ y = self.cy + @dy
58
+ if @rotation != 0
59
+ gc.translate(x, y)
60
+ gc.rotate(@rotation)
61
+ gc.translate(-x, -y)
62
+ end
63
+ add_style_primitives(gc)
64
+ if @text
65
+ x2, y2 = gc.text(x, y, @text)
66
+ self.cx = x + x2
67
+ self.cy = y + y2
68
+ end
69
+ @tspans.each do |tspan|
70
+ tspan.add_primitives(gc)
71
+ end
72
+ gc.pop
73
+ end
74
+ end
75
+
76
+ end # class TextBase
77
+
78
+ # Tspan and Tref shared methods - read/update @cx, @cy in parent Text object.
79
+ module TextLink #:nodoc:
80
+
81
+ def add_primitives(gc)
82
+ @parent.cx = @x if @x
83
+ @parent.cy = @y if @y
84
+ super
85
+ end
86
+
87
+ def cx()
88
+ @parent.cx
89
+ end
90
+
91
+ def cy()
92
+ @parent.cy
93
+ end
94
+
95
+ def cx=(x)
96
+ @parent.cx = x
97
+ end
98
+
99
+ def cy=(y)
100
+ @parent.cy = y
101
+ end
102
+
103
+ end # module TextLink
104
+
105
+
106
+ class Tref < TextBase #:nodoc:
107
+ include TextLink
108
+
109
+ def initialize(obj, x, y, parent)
110
+ @x, @y = Magick::RVG.convert_to_float(x, y, :allow_nil)
111
+ super(nil)
112
+ @tspans << obj
113
+ @parent = parent
114
+ end
115
+
116
+ end # class Tref
117
+
118
+ class Tspan < TextBase #:nodoc:
119
+ include TextLink
120
+
121
+ attr_accessor :parent
122
+
123
+ # Define a text segment starting at (<tt>x</tt>, <tt>y</tt>).
124
+ # If <tt>x</tt> and <tt>y</tt> are omitted the segment starts
125
+ # at the current text position.
126
+ #
127
+ # Tspan objects can contain Tspan objects.
128
+ def initialize(text=nil, x=nil, y=nil, &block)
129
+ @x, @y = Magick::RVG.convert_to_float(x, y, :allow_nil)
130
+ super(text, &block)
131
+ end
132
+
133
+ end # class Tspan
134
+
135
+ class Text < TextBase
136
+
137
+ attr_accessor :cx, :cy #:nodoc:
138
+
139
+ # Define a text string starting at [<tt>x</tt>, <tt>y</tt>].
140
+ # Use the RVG::TextConstructors#text method to create Text objects in a container.
141
+ #
142
+ # container.text(100, 100, "Simple text").styles(:font=>'Arial')
143
+ #
144
+ # Text objects can contain Tspan objects.
145
+ #
146
+ # container.text(100, 100).styles(:font=>'Arial') do |t|
147
+ # t.tspan("Red text").styles(:fill=>'red')
148
+ # t.tspan("Blue text").styles(:fill=>'blue')
149
+ # end
150
+ def initialize(x=0, y=0, text=nil, &block)
151
+ @cx, @cy = Magick::RVG.convert_to_float(x, y)
152
+ super(text, &block)
153
+ end
154
+
155
+ # Reference a Tspan object. <tt>x</tt> and <tt>y</tt> are just
156
+ # like <tt>x</tt> and <tt>y</tt> in RVG::TextBase#tspan
157
+ def tref(obj, x=nil, y=nil)
158
+ if ! obj.kind_of?(Tspan)
159
+ raise ArgumentError, "wrong argument type #{obj.class} (expected Tspan)"
160
+ end
161
+ obj = obj.deep_copy
162
+ obj.parent = self
163
+ tref = Tref.new(obj, x, y, self)
164
+ @tspans << tref
165
+ return tref
166
+ end
167
+
168
+ end # class Text
169
+
170
+
171
+
172
+ # Methods that construct text objects within a container
173
+ module TextConstructors
174
+
175
+ # Draw a text string at (<tt>x</tt>,<tt>y</tt>). The string can
176
+ # be omitted. Optionally, define text chunks within the associated
177
+ # block.
178
+ def text(x=0, y=0, text=nil, &block)
179
+ t = Text.new(x, y, text, &block)
180
+ @content << t
181
+ return t
182
+ end
183
+
184
+ end # module TextConstructors
185
+
186
+ end # class RVG
187
+ end # module Magick