rmagick 1.14.1 → 1.15.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rmagick might be problematic. Click here for more details.
- data/ChangeLog +22 -0
- data/README.html +11 -63
- data/README.txt +8 -56
- data/configure +214 -787
- data/configure.ac +22 -24
- data/doc/comtasks.html +2 -2
- data/doc/constants.html +5 -6
- data/doc/draw.html +33 -14
- data/doc/ex/clip_path.rb +3 -0
- data/doc/ex/path.rb +1 -1
- data/doc/ex/polaroid.rb +23 -0
- data/doc/ex/tspan01.rb +2 -2
- data/doc/ex/tspan02.rb +2 -2
- data/doc/ex/tspan03.rb +3 -3
- data/doc/ex/wet_floor.rb +54 -0
- data/doc/ilist.html +83 -4
- data/doc/image1.html +4 -5
- data/doc/image2.html +395 -266
- data/doc/image3.html +104 -8
- data/doc/imageattrs.html +2 -2
- data/doc/imusage.html +2 -2
- data/doc/index.html +22 -18
- data/doc/info.html +28 -6
- data/doc/magick.html +125 -4
- data/doc/optequiv.html +196 -21
- data/doc/rvg.html +2 -2
- data/doc/rvgclip.html +2 -2
- data/doc/rvggroup.html +2 -2
- data/doc/rvgimage.html +2 -2
- data/doc/rvgpattern.html +2 -2
- data/doc/rvgshape.html +2 -2
- data/doc/rvgstyle.html +2 -2
- data/doc/rvgtext.html +2 -2
- data/doc/rvgtspan.html +2 -2
- data/doc/rvgtut.html +3 -3
- data/doc/rvguse.html +2 -2
- data/doc/rvgxform.html +2 -2
- data/doc/struct.html +2 -2
- data/doc/usage.html +26 -5
- data/ext/RMagick/MANIFEST +3 -1
- data/ext/RMagick/rmagick.h +46 -12
- data/ext/RMagick/rmagick_config.h.in +12 -2
- data/ext/RMagick/rmdraw.c +202 -62
- data/ext/RMagick/rmfill.c +36 -36
- data/ext/RMagick/rmilist.c +75 -31
- data/ext/RMagick/rmimage.c +640 -323
- data/ext/RMagick/rminfo.c +76 -15
- data/ext/RMagick/rmmain.c +107 -30
- data/ext/RMagick/rmutil.c +97 -68
- data/lib/RMagick.rb +11 -11
- data/lib/rvg/clippath.rb +38 -36
- data/lib/rvg/container.rb +120 -118
- data/lib/rvg/deep_equal.rb +44 -42
- data/lib/rvg/describable.rb +49 -47
- data/lib/rvg/embellishable.rb +399 -397
- data/lib/rvg/misc.rb +613 -603
- data/lib/rvg/paint.rb +38 -36
- data/lib/rvg/pathdata.rb +124 -122
- data/lib/rvg/rvg.rb +202 -198
- data/lib/rvg/stretchable.rb +132 -130
- data/lib/rvg/stylable.rb +101 -99
- data/lib/rvg/text.rb +173 -171
- data/lib/rvg/transformable.rb +120 -118
- data/lib/rvg/units.rb +60 -58
- data/rmagick.gemspec +1 -1
- metadata +5 -3
data/lib/rvg/misc.rb
CHANGED
@@ -1,729 +1,739 @@
|
|
1
|
-
# $Id: misc.rb,v 1.
|
2
|
-
# Copyright (C)
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
ivalue.deep_copy
|
24
|
-
|
25
|
-
ivalue.dup
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
1
|
+
# $Id: misc.rb,v 1.10 2007/01/20 17:39:49 rmagick Exp $
|
2
|
+
# Copyright (C) 2007 Timothy P. Hunter
|
3
|
+
module Magick
|
4
|
+
class RVG
|
5
|
+
|
6
|
+
# This is a standard deep_copy method that is used in most classes.
|
7
|
+
# Thanks to Robert Klemme.
|
8
|
+
module Duplicatable
|
9
|
+
|
10
|
+
def deep_copy(h = {})
|
11
|
+
# Prevent recursion. If we reach the
|
12
|
+
# object we started with, stop copying.
|
13
|
+
copy = h[__id__]
|
14
|
+
unless copy
|
15
|
+
h[__id__] = copy = self.class.allocate
|
16
|
+
ivars = instance_variables
|
17
|
+
ivars.each do |ivar|
|
18
|
+
ivalue = instance_variable_get(ivar)
|
19
|
+
cvalue = case
|
20
|
+
when NilClass === ivalue, Symbol === ivalue, Float === ivalue,
|
21
|
+
Fixnum === ivalue, FalseClass === ivalue, TrueClass === ivalue
|
22
|
+
ivalue
|
23
|
+
when ivalue.respond_to?(:deep_copy)
|
24
|
+
ivalue.deep_copy(h)
|
25
|
+
when ivalue.respond_to?(:dup)
|
26
|
+
ivalue.dup
|
27
|
+
else
|
28
|
+
ivalue
|
29
|
+
end
|
30
|
+
copy.instance_variable_set(ivar, cvalue)
|
31
|
+
end
|
32
|
+
copy.freeze if frozen?
|
30
33
|
end
|
31
|
-
copy
|
34
|
+
return copy
|
32
35
|
end
|
33
|
-
return copy
|
34
|
-
end
|
35
|
-
|
36
|
-
end # module Magick::RVG::Duplicatable
|
37
36
|
|
37
|
+
end # module Duplicatable
|
38
38
|
|
39
|
-
# Convert an array of method arguments to Float objects. If any
|
40
|
-
# cannot be converted, raise ArgumentError and issue a message.
|
41
|
-
def self.fmsg(*args)
|
42
|
-
"at least one argument cannot be converted to Float (got #{args.collect {|a| a.class}.join(', ')})"
|
43
|
-
end
|
44
39
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
args.pop
|
50
|
-
end
|
51
|
-
begin
|
52
|
-
fargs = args.collect { |a| (allow_nil && a.nil?) ? a : Float(a) }
|
53
|
-
rescue ArgumentError, TypeError
|
54
|
-
raise ArgumentError, self.fmsg(*args)
|
40
|
+
# Convert an array of method arguments to Float objects. If any
|
41
|
+
# cannot be converted, raise ArgumentError and issue a message.
|
42
|
+
def self.fmsg(*args)
|
43
|
+
"at least one argument cannot be converted to Float (got #{args.collect {|a| a.class}.join(', ')})"
|
55
44
|
end
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
45
|
+
|
46
|
+
def self.convert_to_float(*args)
|
47
|
+
allow_nil = false
|
48
|
+
if args.last == :allow_nil
|
49
|
+
allow_nil = true
|
50
|
+
args.pop
|
51
|
+
end
|
52
|
+
begin
|
53
|
+
fargs = args.collect { |a| (allow_nil && a.nil?) ? a : Float(a) }
|
54
|
+
rescue ArgumentError, TypeError
|
55
|
+
raise ArgumentError, self.fmsg(*args)
|
56
|
+
end
|
57
|
+
return fargs
|
64
58
|
end
|
65
|
-
return farg
|
66
|
-
end
|
67
59
|
|
68
|
-
|
60
|
+
def self.convert_one_to_float(arg)
|
61
|
+
begin
|
62
|
+
farg = Float(arg)
|
63
|
+
rescue ArgumentError, TypeError
|
64
|
+
raise ArgumentError, "argument cannot be converted to Float (got #{arg.class})"
|
65
|
+
end
|
66
|
+
return farg
|
67
|
+
end
|
69
68
|
|
69
|
+
end # class RVG
|
70
|
+
end # module Magick
|
70
71
|
|
71
72
|
|
72
73
|
|
73
74
|
|
74
|
-
module Magick::RVG::Utility
|
75
75
|
|
76
|
-
|
76
|
+
module Magick
|
77
|
+
class RVG
|
78
|
+
class Utility
|
77
79
|
|
78
|
-
|
79
|
-
@ctx = context
|
80
|
-
@ctx.shadow.affine = @ctx.text_attrs.affine
|
81
|
-
end
|
80
|
+
class TextStrategy
|
82
81
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
text = '\''+text+'\''
|
88
|
-
return text
|
89
|
-
elsif !text['"']
|
90
|
-
text = '"'+text+'"'
|
91
|
-
return text
|
92
|
-
elsif !(text['{'] || text['}'])
|
93
|
-
text = '{'+text+'}'
|
94
|
-
return text
|
95
|
-
end
|
82
|
+
def initialize(context)
|
83
|
+
@ctx = context
|
84
|
+
@ctx.shadow.affine = @ctx.text_attrs.affine
|
85
|
+
end
|
96
86
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
87
|
+
def enquote(text)
|
88
|
+
if text.length > 2 && /\A(?:\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})\z/.match(text)
|
89
|
+
return text
|
90
|
+
elsif !text['\'']
|
91
|
+
text = '\''+text+'\''
|
92
|
+
return text
|
93
|
+
elsif !text['"']
|
94
|
+
text = '"'+text+'"'
|
95
|
+
return text
|
96
|
+
elsif !(text['{'] || text['}'])
|
97
|
+
text = '{'+text+'}'
|
98
|
+
return text
|
99
|
+
end
|
101
100
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
if glyph_orientation == 0 || glyph_orientation == 180
|
107
|
-
[w, h]
|
108
|
-
else
|
109
|
-
[h, w]
|
110
|
-
end
|
111
|
-
end
|
101
|
+
# escape existing braces, surround with braces
|
102
|
+
text.gsub!(/[}]/) { |b| '\\' + b }
|
103
|
+
return '{' + text + '}'
|
104
|
+
end
|
112
105
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
y_rel_coords << wy
|
123
|
-
end
|
124
|
-
first_word = false
|
125
|
-
word.split('').each do |glyph|
|
126
|
-
wx, wy = get_letter_spacing(glyph)
|
127
|
-
x_rel_coords << wx
|
128
|
-
y_rel_coords << wy
|
106
|
+
def glyph_metrics(glyph_orientation, glyph)
|
107
|
+
glyph_metrics = @ctx.shadow.get_type_metrics(glyph)
|
108
|
+
h = glyph_metrics.ascent - glyph_metrics.descent
|
109
|
+
w = glyph_metrics.width
|
110
|
+
if glyph_orientation == 0 || glyph_orientation == 180
|
111
|
+
[w, h]
|
112
|
+
else
|
113
|
+
[h, w]
|
114
|
+
end
|
129
115
|
end
|
130
|
-
end
|
131
|
-
[x_rel_coords, y_rel_coords]
|
132
|
-
end
|
133
116
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
return x
|
155
|
-
end
|
117
|
+
def text_rel_coords(text)
|
118
|
+
y_rel_coords = []
|
119
|
+
x_rel_coords = []
|
120
|
+
first_word = true
|
121
|
+
words = text.split(::Magick::RVG::WORD_SEP)
|
122
|
+
words.each do |word|
|
123
|
+
unless first_word
|
124
|
+
wx, wy = get_word_spacing()
|
125
|
+
x_rel_coords << wx
|
126
|
+
y_rel_coords << wy
|
127
|
+
end
|
128
|
+
first_word = false
|
129
|
+
word.split('').each do |glyph|
|
130
|
+
wx, wy = get_letter_spacing(glyph)
|
131
|
+
x_rel_coords << wx
|
132
|
+
y_rel_coords << wy
|
133
|
+
end
|
134
|
+
end
|
135
|
+
[x_rel_coords, y_rel_coords]
|
136
|
+
end
|
156
137
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
138
|
+
def shift_baseline(glyph_orientation, glyph)
|
139
|
+
glyph_dimensions = @ctx.shadow.get_type_metrics(glyph)
|
140
|
+
if glyph_orientation == 0 || glyph_orientation == 180
|
141
|
+
x = glyph_dimensions.width
|
142
|
+
else
|
143
|
+
x = glyph_dimensions.ascent - glyph_dimensions.descent
|
144
|
+
end
|
145
|
+
case @ctx.text_attrs.baseline_shift
|
146
|
+
when :baseline
|
147
|
+
x = 0
|
148
|
+
when :sub
|
149
|
+
;
|
150
|
+
when :super
|
151
|
+
x = -x
|
152
|
+
when /[-+]?(\d+)%/
|
153
|
+
m = $1 == '-' ? -1.0 : 1.0
|
154
|
+
x = (m * x * $1.to_f / 100.0)
|
155
|
+
else
|
156
|
+
x = -@ctx.text_attrs.baseline_shift
|
157
|
+
end
|
158
|
+
return x
|
159
|
+
end
|
169
160
|
|
170
|
-
|
161
|
+
def render_glyph(glyph_orientation, x, y, glyph)
|
162
|
+
if glyph_orientation == 0
|
163
|
+
@ctx.gc.text(x, y, enquote(glyph))
|
164
|
+
else
|
165
|
+
@ctx.gc.push
|
166
|
+
@ctx.gc.translate(x, y)
|
167
|
+
@ctx.gc.rotate(glyph_orientation)
|
168
|
+
@ctx.gc.translate(-x, -y)
|
169
|
+
@ctx.gc.text(x, y, enquote(glyph))
|
170
|
+
@ctx.gc.pop
|
171
|
+
end
|
172
|
+
end
|
171
173
|
|
172
|
-
|
174
|
+
end # class TextStrategy
|
173
175
|
|
174
|
-
|
175
|
-
@word_space ||= glyph_metrics(@ctx.text_attrs.glyph_orientation_horizontal, ' ')[0]
|
176
|
-
[@word_space + @ctx.text_attrs.word_spacing, 0]
|
177
|
-
end
|
176
|
+
class LRTextStrategy < TextStrategy
|
178
177
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
178
|
+
def get_word_spacing()
|
179
|
+
@word_space ||= glyph_metrics(@ctx.text_attrs.glyph_orientation_horizontal, ' ')[0]
|
180
|
+
[@word_space + @ctx.text_attrs.word_spacing, 0]
|
181
|
+
end
|
183
182
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
# We're handling the anchoring.
|
190
|
-
@ctx.gc.push()
|
191
|
-
@ctx.gc.text_anchor(Magick::StartAnchor)
|
192
|
-
if @ctx.text_attrs.text_anchor == :end
|
193
|
-
x -= dx
|
194
|
-
elsif @ctx.text_attrs.text_anchor == :middle
|
195
|
-
x -= dx / 2
|
196
|
-
end
|
183
|
+
def get_letter_spacing(glyph)
|
184
|
+
gx, gy = glyph_metrics(@ctx.text_attrs.glyph_orientation_horizontal, glyph)
|
185
|
+
[gx+@ctx.text_attrs.letter_spacing, gy]
|
186
|
+
end
|
197
187
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
188
|
+
def render(x, y, text)
|
189
|
+
x_rel_coords, y_rel_coords = text_rel_coords(text)
|
190
|
+
dx = x_rel_coords.inject(0) {|sum, a| sum + a}
|
191
|
+
dy = y_rel_coords.max
|
192
|
+
|
193
|
+
# We're handling the anchoring.
|
194
|
+
@ctx.gc.push()
|
195
|
+
@ctx.gc.text_anchor(Magick::StartAnchor)
|
196
|
+
if @ctx.text_attrs.text_anchor == :end
|
197
|
+
x -= dx
|
198
|
+
elsif @ctx.text_attrs.text_anchor == :middle
|
199
|
+
x -= dx / 2
|
200
|
+
end
|
211
201
|
|
212
|
-
|
202
|
+
# Align the first glyph
|
203
|
+
case @ctx.text_attrs.glyph_orientation_horizontal
|
204
|
+
when 0
|
205
|
+
;
|
206
|
+
when 90
|
207
|
+
y -= dy
|
208
|
+
when 180
|
209
|
+
x += x_rel_coords.shift
|
210
|
+
x_rel_coords << 0
|
211
|
+
y -= dy
|
212
|
+
when 270
|
213
|
+
x += x_rel_coords[0]
|
214
|
+
end
|
213
215
|
|
214
|
-
|
215
|
-
text.split(::Magick::RVG::WORD_SEP).each do |word|
|
216
|
-
unless first_word
|
217
|
-
x += x_rel_coords.shift
|
218
|
-
end
|
219
|
-
first_word = false
|
220
|
-
word.split('').each do |glyph|
|
221
|
-
render_glyph(@ctx.text_attrs.glyph_orientation_horizontal, x, y, glyph)
|
222
|
-
x += x_rel_coords.shift
|
223
|
-
end
|
224
|
-
end
|
216
|
+
y += shift_baseline(@ctx.text_attrs.glyph_orientation_horizontal, text[0,1])
|
225
217
|
|
226
|
-
|
227
|
-
|
228
|
-
|
218
|
+
first_word = true
|
219
|
+
text.split(::Magick::RVG::WORD_SEP).each do |word|
|
220
|
+
unless first_word
|
221
|
+
x += x_rel_coords.shift
|
222
|
+
end
|
223
|
+
first_word = false
|
224
|
+
word.split('').each do |glyph|
|
225
|
+
render_glyph(@ctx.text_attrs.glyph_orientation_horizontal, x, y, glyph)
|
226
|
+
x += x_rel_coords.shift
|
227
|
+
end
|
228
|
+
end
|
229
229
|
|
230
|
-
|
230
|
+
@ctx.gc.pop()
|
231
|
+
[dx, 0]
|
232
|
+
end
|
231
233
|
|
232
|
-
|
234
|
+
end # class LRTextStrategy
|
233
235
|
|
234
|
-
|
235
|
-
raise NotImplementedError
|
236
|
-
end
|
236
|
+
class RLTextStrategy < TextStrategy
|
237
237
|
|
238
|
-
|
238
|
+
def render(x, y, text)
|
239
|
+
raise NotImplementedError
|
240
|
+
end
|
239
241
|
|
242
|
+
end # class RLTextStrategy
|
240
243
|
|
241
|
-
class TBTextStrategy < TextStrategy
|
242
244
|
|
243
|
-
|
244
|
-
@word_space ||= glyph_metrics(@ctx.text_attrs.glyph_orientation_vertical, ' ')[1]
|
245
|
-
[0, @word_space + @ctx.text_attrs.word_spacing]
|
246
|
-
end
|
245
|
+
class TBTextStrategy < TextStrategy
|
247
246
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
247
|
+
def get_word_spacing()
|
248
|
+
@word_space ||= glyph_metrics(@ctx.text_attrs.glyph_orientation_vertical, ' ')[1]
|
249
|
+
[0, @word_space + @ctx.text_attrs.word_spacing]
|
250
|
+
end
|
252
251
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
# We're handling the anchoring.
|
259
|
-
@ctx.gc.push()
|
260
|
-
@ctx.gc.text_anchor(Magick::StartAnchor)
|
261
|
-
if @ctx.text_attrs.text_anchor == :end
|
262
|
-
y -= dy
|
263
|
-
elsif @ctx.text_attrs.text_anchor == :middle
|
264
|
-
y -= dy / 2
|
265
|
-
end
|
252
|
+
def get_letter_spacing(glyph)
|
253
|
+
gx, gy = glyph_metrics(@ctx.text_attrs.glyph_orientation_vertical, glyph)
|
254
|
+
[gx, gy+@ctx.text_attrs.letter_spacing]
|
255
|
+
end
|
266
256
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
y += y_rel_coords.shift
|
281
|
-
y_rel_coords << 0 # since we used an element we need to add a dummy
|
282
|
-
end
|
257
|
+
def render(x, y, text)
|
258
|
+
x_rel_coords, y_rel_coords = text_rel_coords(text)
|
259
|
+
dx = x_rel_coords.max
|
260
|
+
dy = y_rel_coords.inject(0) {|sum, a| sum + a}
|
261
|
+
|
262
|
+
# We're handling the anchoring.
|
263
|
+
@ctx.gc.push()
|
264
|
+
@ctx.gc.text_anchor(Magick::StartAnchor)
|
265
|
+
if @ctx.text_attrs.text_anchor == :end
|
266
|
+
y -= dy
|
267
|
+
elsif @ctx.text_attrs.text_anchor == :middle
|
268
|
+
y -= dy / 2
|
269
|
+
end
|
283
270
|
|
284
|
-
|
271
|
+
# Align the first glyph such that its center
|
272
|
+
# is aligned on x and its top is aligned on y.
|
285
273
|
|
286
|
-
first_word = true
|
287
|
-
text.split(::Magick::RVG::WORD_SEP).each do |word|
|
288
|
-
unless first_word
|
289
|
-
y += y_rel_coords.shift
|
290
|
-
x_rel_coords.shift
|
291
|
-
end
|
292
|
-
first_word = false
|
293
|
-
word.split('').each do |glyph|
|
294
274
|
case @ctx.text_attrs.glyph_orientation_vertical
|
295
|
-
when 0
|
296
|
-
|
275
|
+
when 0
|
276
|
+
x -= x_rel_coords.max / 2
|
277
|
+
y += y_rel_coords[0]
|
278
|
+
when 90
|
279
|
+
x -= x_rel_coords.max / 2
|
297
280
|
when 180
|
298
|
-
|
281
|
+
x += x_rel_coords.max / 2
|
282
|
+
when 270
|
283
|
+
x += x_rel_coords.max / 2
|
284
|
+
y += y_rel_coords.shift
|
285
|
+
y_rel_coords << 0 # since we used an element we need to add a dummy
|
299
286
|
end
|
300
287
|
|
301
|
-
|
302
|
-
y += y_rel_coords.shift
|
303
|
-
end
|
304
|
-
end
|
288
|
+
x -= shift_baseline(@ctx.text_attrs.glyph_orientation_vertical, text[0,1])
|
305
289
|
|
306
|
-
|
307
|
-
|
308
|
-
|
290
|
+
first_word = true
|
291
|
+
text.split(::Magick::RVG::WORD_SEP).each do |word|
|
292
|
+
unless first_word
|
293
|
+
y += y_rel_coords.shift
|
294
|
+
x_rel_coords.shift
|
295
|
+
end
|
296
|
+
first_word = false
|
297
|
+
word.split('').each do |glyph|
|
298
|
+
case @ctx.text_attrs.glyph_orientation_vertical
|
299
|
+
when 0, 90, 270
|
300
|
+
x_shift = (dx - x_rel_coords.shift) / 2
|
301
|
+
when 180
|
302
|
+
x_shift = -(dx - x_rel_coords.shift) / 2
|
303
|
+
end
|
304
|
+
|
305
|
+
render_glyph(@ctx.text_attrs.glyph_orientation_vertical, x+x_shift, y, glyph)
|
306
|
+
y += y_rel_coords.shift
|
307
|
+
end
|
308
|
+
end
|
309
309
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
class DefaultTextStrategy < TextStrategy
|
314
|
-
|
315
|
-
def render(x, y, text)
|
316
|
-
@ctx.gc.text(x, y, enquote(text))
|
317
|
-
tm = @ctx.shadow.get_type_metrics(text)
|
318
|
-
dx = case @ctx.text_attrs.text_anchor
|
319
|
-
when :start
|
320
|
-
tm.width
|
321
|
-
when :middle
|
322
|
-
tm.width / 2
|
323
|
-
when :end
|
324
|
-
0
|
325
|
-
end
|
326
|
-
[dx, 0]
|
327
|
-
end
|
310
|
+
@ctx.gc.pop()
|
311
|
+
[0, dy]
|
312
|
+
end
|
328
313
|
|
329
|
-
|
314
|
+
end # class TBTextStrategy
|
315
|
+
|
316
|
+
# Handle "easy" text
|
317
|
+
class DefaultTextStrategy < TextStrategy
|
318
|
+
|
319
|
+
def render(x, y, text)
|
320
|
+
@ctx.gc.text(x, y, enquote(text))
|
321
|
+
tm = @ctx.shadow.get_type_metrics(text)
|
322
|
+
dx = case @ctx.text_attrs.text_anchor
|
323
|
+
when :start
|
324
|
+
tm.width
|
325
|
+
when :middle
|
326
|
+
tm.width / 2
|
327
|
+
when :end
|
328
|
+
0
|
329
|
+
end
|
330
|
+
[dx, 0]
|
331
|
+
end
|
330
332
|
|
331
|
-
end #
|
333
|
+
end # class NormalTextStrategy
|
332
334
|
|
335
|
+
end # class Utility
|
336
|
+
end # class RVG
|
337
|
+
end # module Magick
|
333
338
|
|
334
339
|
|
335
340
|
|
336
|
-
module Magick::RVG::Utility
|
337
341
|
|
338
|
-
|
342
|
+
module Magick
|
343
|
+
class RVG
|
344
|
+
class Utility
|
339
345
|
|
340
|
-
|
346
|
+
class TextAttributes
|
341
347
|
|
342
|
-
|
348
|
+
public
|
343
349
|
|
344
|
-
|
345
|
-
@affine = Array.new
|
346
|
-
@affine << Magick::AffineMatrix.new(1, 0, 0, 1, 0, 0)
|
347
|
-
@baseline_shift = Array.new
|
348
|
-
@baseline_shift << :baseline
|
349
|
-
@glyph_orientation_horizontal = Array.new
|
350
|
-
@glyph_orientation_horizontal << 0
|
351
|
-
@glyph_orientation_vertical = Array.new
|
352
|
-
@glyph_orientation_vertical << 90
|
353
|
-
@letter_spacing = Array.new
|
354
|
-
@letter_spacing << 0
|
355
|
-
@text_anchor = Array.new
|
356
|
-
@text_anchor << :start
|
357
|
-
@word_spacing = Array.new
|
358
|
-
@word_spacing << 0
|
359
|
-
@writing_mode = Array.new
|
360
|
-
@writing_mode << 'lr-tb'
|
361
|
-
end
|
350
|
+
WRITING_MODE = %w{lr-tb lr rl-tb rl tb-rl tb}
|
362
351
|
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
352
|
+
def initialize()
|
353
|
+
@affine = Array.new
|
354
|
+
@affine << Magick::AffineMatrix.new(1, 0, 0, 1, 0, 0)
|
355
|
+
@baseline_shift = Array.new
|
356
|
+
@baseline_shift << :baseline
|
357
|
+
@glyph_orientation_horizontal = Array.new
|
358
|
+
@glyph_orientation_horizontal << 0
|
359
|
+
@glyph_orientation_vertical = Array.new
|
360
|
+
@glyph_orientation_vertical << 90
|
361
|
+
@letter_spacing = Array.new
|
362
|
+
@letter_spacing << 0
|
363
|
+
@text_anchor = Array.new
|
364
|
+
@text_anchor << :start
|
365
|
+
@word_spacing = Array.new
|
366
|
+
@word_spacing << 0
|
367
|
+
@writing_mode = Array.new
|
368
|
+
@writing_mode << 'lr-tb'
|
369
|
+
end
|
373
370
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
371
|
+
def push()
|
372
|
+
@affine.push(@affine.last.dup)
|
373
|
+
@baseline_shift.push(@baseline_shift.last)
|
374
|
+
@text_anchor.push(@text_anchor.last)
|
375
|
+
@writing_mode.push(@writing_mode.last.dup)
|
376
|
+
@glyph_orientation_vertical.push(@glyph_orientation_vertical.last)
|
377
|
+
@glyph_orientation_horizontal.push(@glyph_orientation_horizontal.last)
|
378
|
+
@letter_spacing.push(@letter_spacing.last)
|
379
|
+
@word_spacing.push(@word_spacing.last)
|
380
|
+
end
|
384
381
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
382
|
+
def pop()
|
383
|
+
@affine.pop
|
384
|
+
@baseline_shift.pop
|
385
|
+
@text_anchor.pop
|
386
|
+
@writing_mode.pop
|
387
|
+
@glyph_orientation_vertical.pop
|
388
|
+
@glyph_orientation_horizontal.pop
|
389
|
+
@letter_spacing.pop
|
390
|
+
@word_spacing.pop
|
391
|
+
end
|
393
392
|
|
394
|
-
|
395
|
-
|
396
|
-
|
393
|
+
def set_affine(sx, rx, ry, sy, tx, ty)
|
394
|
+
@affine[-1].sx = sx
|
395
|
+
@affine[-1].rx = rx
|
396
|
+
@affine[-1].ry = ry
|
397
|
+
@affine[-1].sy = sy
|
398
|
+
@affine[-1].tx = tx
|
399
|
+
@affine[-1].ty = ty
|
400
|
+
end
|
397
401
|
|
398
|
-
|
399
|
-
|
400
|
-
|
402
|
+
def affine()
|
403
|
+
@affine[-1]
|
404
|
+
end
|
401
405
|
|
402
|
-
|
403
|
-
|
404
|
-
|
406
|
+
def baseline_shift()
|
407
|
+
@baseline_shift[-1]
|
408
|
+
end
|
405
409
|
|
406
|
-
|
407
|
-
|
408
|
-
|
410
|
+
def baseline_shift=(value)
|
411
|
+
@baseline_shift[-1] = value
|
412
|
+
end
|
409
413
|
|
410
|
-
|
411
|
-
|
412
|
-
|
414
|
+
def text_anchor()
|
415
|
+
@text_anchor[-1]
|
416
|
+
end
|
413
417
|
|
414
|
-
|
415
|
-
|
416
|
-
|
418
|
+
def text_anchor=(anchor)
|
419
|
+
@text_anchor[-1] = anchor
|
420
|
+
end
|
417
421
|
|
418
|
-
|
419
|
-
|
420
|
-
|
422
|
+
def glyph_orientation_vertical()
|
423
|
+
@glyph_orientation_vertical[-1]
|
424
|
+
end
|
421
425
|
|
422
|
-
|
423
|
-
|
424
|
-
|
426
|
+
def glyph_orientation_vertical=(angle)
|
427
|
+
@glyph_orientation_vertical[-1] = angle
|
428
|
+
end
|
425
429
|
|
426
|
-
|
427
|
-
|
428
|
-
|
430
|
+
def glyph_orientation_horizontal()
|
431
|
+
@glyph_orientation_horizontal[-1]
|
432
|
+
end
|
429
433
|
|
430
|
-
|
431
|
-
|
432
|
-
|
434
|
+
def glyph_orientation_horizontal=(angle)
|
435
|
+
@glyph_orientation_horizontal[-1] = angle
|
436
|
+
end
|
433
437
|
|
434
|
-
|
435
|
-
|
436
|
-
|
438
|
+
def letter_spacing()
|
439
|
+
@letter_spacing[-1]
|
440
|
+
end
|
437
441
|
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
@glyph_orientation_horizontal[-1] != 0
|
442
|
-
end
|
442
|
+
def letter_spacing=(value)
|
443
|
+
@letter_spacing[-1] = value
|
444
|
+
end
|
443
445
|
|
444
|
-
|
445
|
-
|
446
|
-
|
446
|
+
def non_default?
|
447
|
+
@baseline_shift[-1] != :baseline || @letter_spacing[-1] != 0 ||
|
448
|
+
@word_spacing[-1] != 0 || @writing_mode[-1][/\Alr/].nil? ||
|
449
|
+
@glyph_orientation_horizontal[-1] != 0
|
450
|
+
end
|
447
451
|
|
448
|
-
|
449
|
-
|
450
|
-
|
452
|
+
def word_spacing()
|
453
|
+
@word_spacing[-1]
|
454
|
+
end
|
451
455
|
|
452
|
-
|
453
|
-
|
454
|
-
|
456
|
+
def word_spacing=(value)
|
457
|
+
@word_spacing[-1] = value
|
458
|
+
end
|
455
459
|
|
456
|
-
|
457
|
-
|
458
|
-
|
460
|
+
def writing_mode()
|
461
|
+
@writing_mode[-1]
|
462
|
+
end
|
459
463
|
|
460
|
-
|
464
|
+
def writing_mode=(mode)
|
465
|
+
@writing_mode[-1] = WRITING_MODE.include?(mode) ? mode : 'lr-tb'
|
466
|
+
end
|
461
467
|
|
462
|
-
|
468
|
+
end # class TextAttributes
|
463
469
|
|
464
|
-
|
465
|
-
:ultra_condensed => Magick::UltraCondensedStretch,
|
466
|
-
:extra_condensed => Magick::ExtraCondensedStretch,
|
467
|
-
:condensed => Magick::CondensedStretch,
|
468
|
-
:semi_condensed => Magick::SemiCondensedStretch,
|
469
|
-
:semi_expanded => Magick::SemiExpandedStretch,
|
470
|
-
:expanded => Magick::ExpandedStretch,
|
471
|
-
:extra_expanded => Magick::ExtraExpandedStretch,
|
472
|
-
:ultra_expanded => Magick::UltraExpandedStretch}
|
470
|
+
class GraphicContext
|
473
471
|
|
474
|
-
|
475
|
-
|
476
|
-
|
472
|
+
FONT_STRETCH = {:normal => Magick::NormalStretch,
|
473
|
+
:ultra_condensed => Magick::UltraCondensedStretch,
|
474
|
+
:extra_condensed => Magick::ExtraCondensedStretch,
|
475
|
+
:condensed => Magick::CondensedStretch,
|
476
|
+
:semi_condensed => Magick::SemiCondensedStretch,
|
477
|
+
:semi_expanded => Magick::SemiExpandedStretch,
|
478
|
+
:expanded => Magick::ExpandedStretch,
|
479
|
+
:extra_expanded => Magick::ExtraExpandedStretch,
|
480
|
+
:ultra_expanded => Magick::UltraExpandedStretch}
|
477
481
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
'lighter' => Magick::LighterWeight}
|
482
|
+
FONT_STYLE = {:normal => Magick::NormalStyle,
|
483
|
+
:italic => Magick::ItalicStyle,
|
484
|
+
:oblique => Magick::ObliqueStyle}
|
482
485
|
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
+
FONT_WEIGHT = {'normal' => Magick::NormalWeight,
|
487
|
+
'bold' => Magick::BoldWeight,
|
488
|
+
'bolder' => Magick::BolderWeight,
|
489
|
+
'lighter' => Magick::LighterWeight}
|
486
490
|
|
487
|
-
|
488
|
-
|
489
|
-
|
491
|
+
TEXT_ANCHOR = {:start => Magick::StartAnchor,
|
492
|
+
:middle => Magick::MiddleAnchor,
|
493
|
+
:end => Magick::EndAnchor}
|
490
494
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
:line_through => Magick::LineThroughDecoration}
|
495
|
+
ANCHOR_TO_ALIGN = {:start => Magick::LeftAlign,
|
496
|
+
:middle => Magick::CenterAlign,
|
497
|
+
:end => Magick::RightAlign}
|
495
498
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
+
TEXT_DECORATION = {:none => Magick::NoDecoration,
|
500
|
+
:underline => Magick::UnderlineDecoration,
|
501
|
+
:overline => Magick::OverlineDecoration,
|
502
|
+
:line_through => Magick::LineThroughDecoration}
|
499
503
|
|
500
|
-
|
501
|
-
|
502
|
-
|
504
|
+
TEXT_STRATEGIES = {'lr-tb'=>LRTextStrategy, 'lr'=>LRTextStrategy,
|
505
|
+
'rt-tb'=>RLTextStrategy, 'rl'=>RLTextStrategy,
|
506
|
+
'tb-rl'=>TBTextStrategy, 'tb'=>TBTextStrategy}
|
503
507
|
|
504
|
-
|
508
|
+
def GraphicContext.degrees_to_radians(deg)
|
509
|
+
Math::PI * (deg % 360.0) / 180.0
|
510
|
+
end
|
505
511
|
|
506
|
-
|
507
|
-
@rx = @ry = 0
|
508
|
-
@sx = @sy = 1
|
509
|
-
@tx = @ty = 0
|
510
|
-
end
|
512
|
+
private
|
511
513
|
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
sy = curr.rx * @ry + curr.sy * @sy
|
518
|
-
tx = curr.sx * @tx + curr.ry * @ty + curr.tx
|
519
|
-
ty = curr.rx * @tx + curr.sy * @ty + curr.ty
|
520
|
-
@text_attrs.set_affine(sx, rx, ry, sy, tx, ty)
|
521
|
-
init_matrix()
|
522
|
-
end
|
514
|
+
def init_matrix()
|
515
|
+
@rx = @ry = 0
|
516
|
+
@sx = @sy = 1
|
517
|
+
@tx = @ty = 0
|
518
|
+
end
|
523
519
|
|
524
|
-
|
520
|
+
def concat_matrix()
|
521
|
+
curr = @text_attrs.affine
|
522
|
+
sx = curr.sx * @sx + curr.ry * @rx
|
523
|
+
rx = curr.rx * @sx + curr.sy * @rx
|
524
|
+
ry = curr.sx * @ry + curr.ry * @sy
|
525
|
+
sy = curr.rx * @ry + curr.sy * @sy
|
526
|
+
tx = curr.sx * @tx + curr.ry * @ty + curr.tx
|
527
|
+
ty = curr.rx * @tx + curr.sy * @ty + curr.ty
|
528
|
+
@text_attrs.set_affine(sx, rx, ry, sy, tx, ty)
|
529
|
+
init_matrix()
|
530
|
+
end
|
525
531
|
|
526
|
-
|
532
|
+
public
|
527
533
|
|
528
|
-
|
529
|
-
@gc = Magick::Draw.new
|
530
|
-
@shadow = Array.new
|
531
|
-
@shadow << Magick::Draw.new
|
532
|
-
@text_attrs = TextAttributes.new
|
533
|
-
init_matrix()
|
534
|
-
end
|
534
|
+
attr_reader :gc, :text_attrs
|
535
535
|
|
536
|
-
|
537
|
-
|
538
|
-
|
536
|
+
def initialize()
|
537
|
+
@gc = Magick::Draw.new
|
538
|
+
@shadow = Array.new
|
539
|
+
@shadow << Magick::Draw.new
|
540
|
+
@text_attrs = TextAttributes.new
|
541
|
+
init_matrix()
|
542
|
+
end
|
539
543
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
@text_attrs.set_affine(sx, rx, ry, sy, tx, ty)
|
544
|
-
nil
|
545
|
-
end
|
544
|
+
def method_missing(methID, *args, &block)
|
545
|
+
@gc.__send__(methID, *args, &block)
|
546
|
+
end
|
546
547
|
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
value
|
553
|
-
else
|
554
|
-
:baseline
|
548
|
+
def affine(sx, rx, ry, sy, tx, ty)
|
549
|
+
sx, rx, ry, sy, tx, ty = Magick::RVG.convert_to_float(sx, rx, ry, sy, tx, ty)
|
550
|
+
@gc.affine(sx, rx, ry, sy, tx, ty)
|
551
|
+
@text_attrs.set_affine(sx, rx, ry, sy, tx, ty)
|
552
|
+
nil
|
555
553
|
end
|
556
|
-
nil
|
557
|
-
end
|
558
554
|
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
555
|
+
def baseline_shift(value)
|
556
|
+
@text_attrs.baseline_shift = case value
|
557
|
+
when 'baseline', 'sub', 'super'
|
558
|
+
value.intern
|
559
|
+
when /[-+]?\d+%/, Numeric
|
560
|
+
value
|
561
|
+
else
|
562
|
+
:baseline
|
563
|
+
end
|
564
|
+
nil
|
565
|
+
end
|
564
566
|
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
567
|
+
def font(name)
|
568
|
+
@gc.font(name)
|
569
|
+
@shadow[-1].font = name
|
570
|
+
nil
|
571
|
+
end
|
570
572
|
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
573
|
+
def font_family(name)
|
574
|
+
@gc.font_family(name)
|
575
|
+
@shadow[-1].font_family = name
|
576
|
+
nil
|
577
|
+
end
|
576
578
|
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
end
|
579
|
+
def font_size(points)
|
580
|
+
@gc.font_size(points)
|
581
|
+
@shadow[-1].pointsize = points
|
582
|
+
nil
|
583
|
+
end
|
583
584
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
585
|
+
def font_stretch(stretch)
|
586
|
+
stretch = FONT_STRETCH.fetch(stretch.intern, Magick::NormalStretch)
|
587
|
+
@gc.font_stretch(stretch)
|
588
|
+
@shadow[-1].font_stretch = stretch
|
589
|
+
nil
|
590
|
+
end
|
590
591
|
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
end
|
592
|
+
def font_style(style)
|
593
|
+
style = FONT_STYLE.fetch(style.intern, Magick::NormalStyle)
|
594
|
+
@gc.font_style(style)
|
595
|
+
@shadow[-1].font_style = style
|
596
|
+
nil
|
597
|
+
end
|
598
598
|
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
599
|
+
def font_weight(weight)
|
600
|
+
# If the arg is not in the hash use it directly. Handles numeric values.
|
601
|
+
weight = FONT_WEIGHT.fetch(weight) {|key| key}
|
602
|
+
@gc.font_weight(weight)
|
603
|
+
@shadow[-1].font_weight = weight
|
604
|
+
nil
|
605
|
+
end
|
604
606
|
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
607
|
+
def glyph_orientation_horizontal(deg)
|
608
|
+
deg = Magick::RVG.convert_one_to_float(deg)
|
609
|
+
@text_attrs.glyph_orientation_horizontal = (deg % 360) / 90 * 90
|
610
|
+
nil
|
611
|
+
end
|
610
612
|
|
611
|
-
|
612
|
-
|
613
|
-
|
613
|
+
def glyph_orientation_vertical(deg)
|
614
|
+
deg = Magick::RVG.convert_one_to_float(deg)
|
615
|
+
@text_attrs.glyph_orientation_vertical = (deg % 360) / 90 * 90
|
616
|
+
nil
|
617
|
+
end
|
614
618
|
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
end
|
619
|
+
def inspect()
|
620
|
+
@gc.inspect
|
621
|
+
end
|
619
622
|
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
nil
|
625
|
-
end
|
623
|
+
def letter_spacing(value)
|
624
|
+
@text_attrs.letter_spacing = Magick::RVG.convert_one_to_float(value)
|
625
|
+
nil
|
626
|
+
end
|
626
627
|
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
628
|
+
def push()
|
629
|
+
@gc.push
|
630
|
+
@shadow.push(@shadow.last.dup)
|
631
|
+
@text_attrs.push
|
632
|
+
nil
|
633
|
+
end
|
633
634
|
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
@sy = Math.cos(GraphicContext.degrees_to_radians(degrees))
|
641
|
-
concat_matrix()
|
642
|
-
nil
|
643
|
-
end
|
635
|
+
def pop()
|
636
|
+
@gc.pop
|
637
|
+
@shadow.pop
|
638
|
+
@text_attrs.pop
|
639
|
+
nil
|
640
|
+
end
|
644
641
|
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
642
|
+
def rotate(degrees)
|
643
|
+
degrees = Magick::RVG.convert_one_to_float(degrees)
|
644
|
+
@gc.rotate(degrees)
|
645
|
+
@sx = Math.cos(GraphicContext.degrees_to_radians(degrees))
|
646
|
+
@rx = Math.sin(GraphicContext.degrees_to_radians(degrees))
|
647
|
+
@ry = -Math.sin(GraphicContext.degrees_to_radians(degrees))
|
648
|
+
@sy = Math.cos(GraphicContext.degrees_to_radians(degrees))
|
649
|
+
concat_matrix()
|
650
|
+
nil
|
651
|
+
end
|
652
652
|
|
653
|
-
|
654
|
-
|
655
|
-
|
653
|
+
def scale(sx, sy)
|
654
|
+
sx, sy = Magick::RVG.convert_to_float(sx, sy)
|
655
|
+
@gc.scale(sx, sy)
|
656
|
+
@sx, @sy = sx, sy
|
657
|
+
concat_matrix()
|
658
|
+
nil
|
659
|
+
end
|
656
660
|
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
@ry = Math.tan(GraphicContext.degrees_to_radians(degrees))
|
661
|
-
concat_matrix()
|
662
|
-
nil
|
663
|
-
end
|
661
|
+
def shadow()
|
662
|
+
@shadow.last
|
663
|
+
end
|
664
664
|
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
665
|
+
def skewX(degrees)
|
666
|
+
degrees = Magick::RVG.convert_one_to_float(degrees)
|
667
|
+
@gc.skewX(degrees)
|
668
|
+
@ry = Math.tan(GraphicContext.degrees_to_radians(degrees))
|
669
|
+
concat_matrix()
|
670
|
+
nil
|
671
|
+
end
|
672
672
|
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
673
|
+
def skewY(degrees)
|
674
|
+
degrees = Magick::RVG.convert_one_to_float(degrees)
|
675
|
+
@gc.skewY(degrees)
|
676
|
+
@rx = Math.tan(GraphicContext.degrees_to_radians(degrees))
|
677
|
+
concat_matrix()
|
678
|
+
nil
|
679
|
+
end
|
679
680
|
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
end
|
681
|
+
def stroke_width(width)
|
682
|
+
width = Magick::RVG.convert_one_to_float(width)
|
683
|
+
@gc.stroke_width(width)
|
684
|
+
@shadow[-1].stroke_width = width
|
685
|
+
nil
|
686
|
+
end
|
687
687
|
|
688
|
-
|
689
|
-
|
688
|
+
def text(x, y, text)
|
689
|
+
return if text.length == 0
|
690
|
+
if @text_attrs.non_default?
|
691
|
+
text_renderer = TEXT_STRATEGIES[@text_attrs.writing_mode].new(self)
|
692
|
+
else
|
693
|
+
text_renderer = DefaultTextStrategy.new(self)
|
694
|
+
end
|
690
695
|
|
691
|
-
|
692
|
-
|
693
|
-
anchor_enum = TEXT_ANCHOR.fetch(anchor, Magick::StartAnchor)
|
694
|
-
@gc.text_anchor(anchor_enum)
|
695
|
-
align = ANCHOR_TO_ALIGN.fetch(anchor, Magick::LeftAlign)
|
696
|
-
@shadow[-1].align = align
|
697
|
-
@text_attrs.text_anchor = anchor
|
698
|
-
nil
|
699
|
-
end
|
696
|
+
return text_renderer.render(x, y, text)
|
697
|
+
end
|
700
698
|
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
699
|
+
def text_anchor(anchor)
|
700
|
+
anchor = anchor.intern
|
701
|
+
anchor_enum = TEXT_ANCHOR.fetch(anchor, Magick::StartAnchor)
|
702
|
+
@gc.text_anchor(anchor_enum)
|
703
|
+
align = ANCHOR_TO_ALIGN.fetch(anchor, Magick::LeftAlign)
|
704
|
+
@shadow[-1].align = align
|
705
|
+
@text_attrs.text_anchor = anchor
|
706
|
+
nil
|
707
|
+
end
|
707
708
|
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
end
|
709
|
+
def text_decoration(decoration)
|
710
|
+
decoration = TEXT_DECORATION.fetch(decoration.intern, Magick::NoDecoration)
|
711
|
+
@gc.decorate(decoration)
|
712
|
+
@shadow[-1].decorate = decoration
|
713
|
+
nil
|
714
|
+
end
|
715
715
|
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
716
|
+
def translate(tx, ty)
|
717
|
+
tx, ty = Magick::RVG.convert_to_float(tx, ty)
|
718
|
+
@gc.translate(tx, ty)
|
719
|
+
@tx, @ty = tx, ty
|
720
|
+
concat_matrix()
|
721
|
+
nil
|
722
|
+
end
|
720
723
|
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
724
|
+
def word_spacing(value)
|
725
|
+
@text_attrs.word_spacing = Magick::RVG.convert_one_to_float(value)
|
726
|
+
nil
|
727
|
+
end
|
728
|
+
|
729
|
+
def writing_mode(mode)
|
730
|
+
@text_attrs.writing_mode = mode
|
731
|
+
nil
|
732
|
+
end
|
725
733
|
|
726
|
-
|
734
|
+
end # class GraphicContext
|
727
735
|
|
728
|
-
end
|
736
|
+
end # class Utility
|
737
|
+
end # class RVG
|
738
|
+
end # module Magick
|
729
739
|
|