rmagick4j 0.3.1-java → 0.3.2-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,156 @@
1
+ #--
2
+ # $Id: stretchable.rb,v 1.4 2007/01/20 17:39:50 rmagick Exp $
3
+ # Copyright (C) 2007 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
+ # Only RVG 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
+ yield(self) if block_given?
149
+ self
150
+ end
151
+
152
+ end # module Stretchable
153
+
154
+ end # class RVG
155
+ end # module Magick
156
+
@@ -0,0 +1,118 @@
1
+ #--
2
+ # $Id: stylable.rb,v 1.4 2007/01/20 17:49:57 rmagick Exp $
3
+ # Copyright (C) 2007 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.5 2007/01/20 17:39:50 rmagick Exp $
3
+ # Copyright (C) 2007 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