rmagick4j 0.3.1-java → 0.3.2-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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