prawn-svg 0.9.1.6 → 0.9.1.7

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,184 @@
1
+ module Prawn
2
+ module Svg
3
+ class Parser::Path
4
+ # Raised if the SVG path cannot be parsed.
5
+ InvalidError = Class.new(StandardError)
6
+
7
+ #
8
+ # Parses an SVG path and returns a Prawn-compatible call tree.
9
+ #
10
+ def parse(data)
11
+ cmd = values = nil
12
+ value = ""
13
+ @subpath_initial_point = @last_point = nil
14
+ @previous_control_point = @previous_quadratic_control_point = nil
15
+ @calls = []
16
+
17
+ data.each_char do |c|
18
+ if c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'
19
+ values << value.to_f if value != ""
20
+ run_path_command(cmd, values) if cmd
21
+ cmd = c
22
+ values = []
23
+ value = ""
24
+ elsif c >= '0' && c <= '9' || c == '.' || c == "-"
25
+ unless cmd
26
+ raise InvalidError, "Numerical value specified before character command in SVG path data"
27
+ end
28
+ value << c
29
+ elsif c == ' ' || c == "\t" || c == "\r" || c == "\n" || c == ","
30
+ if value != ""
31
+ values << value.to_f
32
+ value = ""
33
+ end
34
+ else
35
+ raise InvalidError, "Invalid character '#{c}' in SVG path data"
36
+ end
37
+ end
38
+
39
+ values << value.to_f if value != ""
40
+ run_path_command(cmd, values) if cmd
41
+
42
+ @calls
43
+ end
44
+
45
+
46
+ private
47
+ def run_path_command(command, values)
48
+ upcase_command = command.upcase
49
+ relative = command != upcase_command
50
+
51
+ case upcase_command
52
+ when 'M' # moveto
53
+ x = values.shift
54
+ y = values.shift
55
+
56
+ if relative && @last_point
57
+ x += @last_point.first
58
+ y += @last_point.last
59
+ end
60
+
61
+ @last_point = @subpath_initial_point = [x, y]
62
+ @calls << ["move_to", @last_point]
63
+
64
+ return run_path_command('L', values) if values.any?
65
+
66
+ when 'Z' # closepath
67
+ if @subpath_initial_point
68
+ @calls << ["line_to", @subpath_initial_point]
69
+ @last_point = @subpath_initial_point
70
+ end
71
+
72
+ when 'L' # lineto
73
+ while values.any?
74
+ x = values.shift
75
+ y = values.shift
76
+ if relative && @last_point
77
+ x += @last_point.first
78
+ y += @last_point.last
79
+ end
80
+ @last_point = [x, y]
81
+ @calls << ["line_to", @last_point]
82
+ end
83
+
84
+ when 'H' # horizontal lineto
85
+ while values.any?
86
+ x = values.shift
87
+ x += @last_point.first if relative && @last_point
88
+ @last_point = [x, @last_point.last]
89
+ @calls << ["line_to", @last_point]
90
+ end
91
+
92
+ when 'V' # vertical lineto
93
+ while values.any?
94
+ y = values.shift
95
+ y += @last_point.last if relative && @last_point
96
+ @last_point = [@last_point.first, y]
97
+ @calls << ["line_to", @last_point]
98
+ end
99
+
100
+ when 'C' # curveto
101
+ while values.any?
102
+ x1, y1, x2, y2, x, y = (1..6).collect {values.shift}
103
+ if relative && @last_point
104
+ x += @last_point.first
105
+ x1 += @last_point.first
106
+ x2 += @last_point.first
107
+ y += @last_point.last
108
+ y1 += @last_point.last
109
+ y2 += @last_point.last
110
+ end
111
+
112
+ @last_point = [x, y]
113
+ @previous_control_point = [x2, y2]
114
+ @calls << ["curve_to", [x, y, x1, y1, x2, y2]]
115
+ end
116
+
117
+ when 'S' # shorthand/smooth curveto
118
+ while values.any?
119
+ x2, y2, x, y = (1..4).collect {values.shift}
120
+ if relative && @last_point
121
+ x += @last_point.first
122
+ x2 += @last_point.first
123
+ y += @last_point.last
124
+ y2 += @last_point.last
125
+ end
126
+
127
+ if @previous_control_point
128
+ x1 = 2 * @last_point.first - @previous_control_point.first
129
+ y1 = 2 * @last_point.last - @previous_control_point.last
130
+ else
131
+ x1, y1 = @last_point
132
+ end
133
+
134
+ @last_point = [x, y]
135
+ @previous_control_point = [x2, y2]
136
+ @calls << ["curve_to", [x, y, x1, y1, x2, y2]]
137
+ end
138
+
139
+ when 'Q', 'T' # quadratic curveto
140
+ while values.any?
141
+ if shorthand = upcase_command == 'T'
142
+ x, y = (1..2).collect {values.shift}
143
+ else
144
+ x1, y1, x, y = (1..4).collect {values.shift}
145
+ end
146
+
147
+ if relative && @last_point
148
+ x += @last_point.first
149
+ x1 += @last_point.first if x1
150
+ y += @last_point.last
151
+ y1 += @last_point.last if y1
152
+ end
153
+
154
+ if shorthand
155
+ if @previous_quadratic_control_point
156
+ x1 = 2 * @last_point.first - @previous_quadratic_control_point.first
157
+ y1 = 2 * @last_point.last - @previous_quadratic_control_point.last
158
+ else
159
+ x1, y1 = @last_point
160
+ end
161
+ end
162
+
163
+ # convert from quadratic to cubic
164
+ cx1 = @last_point.first + (x1 - @last_point.first) * 2 / 3.0
165
+ cy1 = @last_point.last + (y1 - @last_point.last) * 2 / 3.0
166
+ cx2 = cx1 + (x - @last_point.first) / 3.0
167
+ cy2 = cy1 + (y - @last_point.last) / 3.0
168
+
169
+ @last_point = [x, y]
170
+ @previous_quadratic_control_point = [x1, y1]
171
+
172
+ @calls << ["curve_to", [x, y, cx1, cy1, cx2, cy2]]
173
+ end
174
+
175
+ when 'A'
176
+ # unsupported
177
+ end
178
+
179
+ @previous_control_point = nil unless %w(C S).include?(upcase_command)
180
+ @previous_quadratic_control_point = nil unless %w(Q T).include?(upcase_command)
181
+ end
182
+ end
183
+ end
184
+ end
metadata CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
6
6
  - 0
7
7
  - 9
8
8
  - 1
9
- - 6
10
- version: 0.9.1.6
9
+ - 7
10
+ version: 0.9.1.7
11
11
  platform: ruby
12
12
  authors:
13
13
  - Roger Nesbitt
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-03-31 00:00:00 +13:00
18
+ date: 2010-05-08 00:00:00 +12:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -57,10 +57,10 @@ extra_rdoc_files: []
57
57
  files:
58
58
  - README
59
59
  - LICENSE
60
+ - lib/prawn/svg/extension.rb
61
+ - lib/prawn/svg/interface.rb
62
+ - lib/prawn/svg/parser/path.rb
60
63
  - lib/prawn/svg/parser.rb
61
- - lib/prawn/svg/path.rb
62
- - lib/prawn/svg/svg.rb
63
- - lib/prawn/svg_document.rb
64
64
  - lib/prawn-svg.rb
65
65
  has_rdoc: true
66
66
  homepage: http://github.com/mogest/prawn-svg
@@ -1,180 +0,0 @@
1
- class Prawn::Svg::Parser::Path
2
- # Raised if the SVG path cannot be parsed.
3
- InvalidError = Class.new(StandardError)
4
-
5
- #
6
- # Parses an SVG path and returns a Prawn-compatible call tree.
7
- #
8
- def parse(data)
9
- cmd = values = nil
10
- value = ""
11
- @subpath_initial_point = @last_point = nil
12
- @previous_control_point = @previous_quadratic_control_point = nil
13
- @calls = []
14
-
15
- data.each_char do |c|
16
- if c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'
17
- values << value.to_f if value != ""
18
- run_path_command(cmd, values) if cmd
19
- cmd = c
20
- values = []
21
- value = ""
22
- elsif c >= '0' && c <= '9' || c == '.' || c == "-"
23
- unless cmd
24
- raise InvalidError, "Numerical value specified before character command in SVG path data"
25
- end
26
- value << c
27
- elsif c == ' ' || c == "\t" || c == "\r" || c == "\n" || c == ","
28
- if value != ""
29
- values << value.to_f
30
- value = ""
31
- end
32
- else
33
- raise InvalidError, "Invalid character '#{c}' in SVG path data"
34
- end
35
- end
36
-
37
- values << value.to_f if value != ""
38
- run_path_command(cmd, values) if cmd
39
-
40
- @calls
41
- end
42
-
43
-
44
- private
45
- def run_path_command(command, values)
46
- upcase_command = command.upcase
47
- relative = command != upcase_command
48
-
49
- case upcase_command
50
- when 'M' # moveto
51
- x = values.shift
52
- y = values.shift
53
-
54
- if relative && @last_point
55
- x += @last_point.first
56
- y += @last_point.last
57
- end
58
-
59
- @last_point = @subpath_initial_point = [x, y]
60
- @calls << ["move_to", @last_point]
61
-
62
- return run_path_command('L', values) if values.any?
63
-
64
- when 'Z' # closepath
65
- if @subpath_initial_point
66
- @calls << ["line_to", @subpath_initial_point]
67
- @last_point = @subpath_initial_point
68
- end
69
-
70
- when 'L' # lineto
71
- while values.any?
72
- x = values.shift
73
- y = values.shift
74
- if relative && @last_point
75
- x += @last_point.first
76
- y += @last_point.last
77
- end
78
- @last_point = [x, y]
79
- @calls << ["line_to", @last_point]
80
- end
81
-
82
- when 'H' # horizontal lineto
83
- while values.any?
84
- x = values.shift
85
- x += @last_point.first if relative && @last_point
86
- @last_point = [x, @last_point.last]
87
- @calls << ["line_to", @last_point]
88
- end
89
-
90
- when 'V' # vertical lineto
91
- while values.any?
92
- y = values.shift
93
- y += @last_point.last if relative && @last_point
94
- @last_point = [@last_point.first, y]
95
- @calls << ["line_to", @last_point]
96
- end
97
-
98
- when 'C' # curveto
99
- while values.any?
100
- x1, y1, x2, y2, x, y = (1..6).collect {values.shift}
101
- if relative && @last_point
102
- x += @last_point.first
103
- x1 += @last_point.first
104
- x2 += @last_point.first
105
- y += @last_point.last
106
- y1 += @last_point.last
107
- y2 += @last_point.last
108
- end
109
-
110
- @last_point = [x, y]
111
- @previous_control_point = [x2, y2]
112
- @calls << ["curve_to", [x, y, x1, y1, x2, y2]]
113
- end
114
-
115
- when 'S' # shorthand/smooth curveto
116
- while values.any?
117
- x2, y2, x, y = (1..4).collect {values.shift}
118
- if relative && @last_point
119
- x += @last_point.first
120
- x2 += @last_point.first
121
- y += @last_point.last
122
- y2 += @last_point.last
123
- end
124
-
125
- if @previous_control_point
126
- x1 = 2 * @last_point.first - @previous_control_point.first
127
- y1 = 2 * @last_point.last - @previous_control_point.last
128
- else
129
- x1, y1 = @last_point
130
- end
131
-
132
- @last_point = [x, y]
133
- @previous_control_point = [x2, y2]
134
- @calls << ["curve_to", [x, y, x1, y1, x2, y2]]
135
- end
136
-
137
- when 'Q', 'T' # quadratic curveto
138
- while values.any?
139
- if shorthand = upcase_command == 'T'
140
- x, y = (1..2).collect {values.shift}
141
- else
142
- x1, y1, x, y = (1..4).collect {values.shift}
143
- end
144
-
145
- if relative && @last_point
146
- x += @last_point.first
147
- x1 += @last_point.first if x1
148
- y += @last_point.last
149
- y1 += @last_point.last if y1
150
- end
151
-
152
- if shorthand
153
- if @previous_quadratic_control_point
154
- x1 = 2 * @last_point.first - @previous_quadratic_control_point.first
155
- y1 = 2 * @last_point.last - @previous_quadratic_control_point.last
156
- else
157
- x1, y1 = @last_point
158
- end
159
- end
160
-
161
- # convert from quadratic to cubic
162
- cx1 = @last_point.first + (x1 - @last_point.first) * 2 / 3.0
163
- cy1 = @last_point.last + (y1 - @last_point.last) * 2 / 3.0
164
- cx2 = cx1 + (x - @last_point.first) / 3.0
165
- cy2 = cy1 + (y - @last_point.last) / 3.0
166
-
167
- @last_point = [x, y]
168
- @previous_quadratic_control_point = [x1, y1]
169
-
170
- @calls << ["curve_to", [x, y, cx1, cy1, cx2, cy2]]
171
- end
172
-
173
- when 'A'
174
- # unsupported
175
- end
176
-
177
- @previous_control_point = nil unless %w(C S).include?(upcase_command)
178
- @previous_quadratic_control_point = nil unless %w(Q T).include?(upcase_command)
179
- end
180
- end
data/lib/prawn/svg/svg.rb DELETED
@@ -1,83 +0,0 @@
1
- #
2
- # Prawn::Svg makes a Prawn::Svg::Parser instance, uses that object to parse the supplied
3
- # SVG into Prawn-compatible method calls, and then calls the Prawn methods.
4
- #
5
- class Prawn::Svg
6
- DEFAULT_FONT_PATHS = ["/Library/Fonts", "/usr/share/fonts/truetype/**"]
7
-
8
- @font_path = []
9
- DEFAULT_FONT_PATHS.each {|path| @font_path << path if File.exists?(path)}
10
-
11
- class << self; attr_accessor :font_path; end
12
-
13
- attr_reader :data, :prawn, :parser, :options
14
-
15
- # An +Array+ of warnings that occurred while parsing the SVG data. If this array is non-empty,
16
- # it's likely that the SVG failed to render correctly.
17
- attr_reader :parser_warnings
18
-
19
- #
20
- # Creates a Prawn::Svg object.
21
- #
22
- # +data+ is the SVG data to convert. +prawn+ is your Prawn::Document object.
23
- #
24
- # +options+ must contain the key :at, which takes a tuple of x and y co-ordinates.
25
- #
26
- # +options+ can optionally contain the key :width or :height. If both are
27
- # specified, only :width will be used.
28
- #
29
- def initialize(data, prawn, options)
30
- @data = data
31
- @prawn = prawn
32
- @options = options
33
-
34
- @options[:at] or raise "options[:at] must be specified"
35
-
36
- @parser = Parser.new(data, [prawn.bounds.width, prawn.bounds.height], options)
37
- @parser_warnings = @parser.warnings
38
- end
39
-
40
- #
41
- # Draws the SVG to the Prawn::Document object.
42
- #
43
- def draw
44
- prawn.bounding_box(@options[:at], :width => @parser.width, :height => @parser.height) do
45
- prawn.save_graphics_state do
46
- proc_creator(prawn, @parser.parse).call
47
- end
48
- end
49
- end
50
-
51
-
52
- private
53
- def proc_creator(prawn, calls)
54
- Proc.new {issue_prawn_command(prawn, calls)}
55
- end
56
-
57
- def issue_prawn_command(prawn, calls)
58
- calls.each do |call, arguments, children|
59
- if rewrite_call_arguments(prawn, call, arguments) == false
60
- issue_prawn_command(prawn, children) if children.any?
61
- else
62
- if children.empty?
63
- prawn.send(call, *arguments)
64
- else
65
- prawn.send(call, *arguments, &proc_creator(prawn, children))
66
- end
67
- end
68
- end
69
- end
70
-
71
- def rewrite_call_arguments(prawn, call, arguments)
72
- case call
73
- when 'text_box'
74
- if (anchor = arguments.last.delete(:text_anchor)) && %w(middle end).include?(anchor)
75
- width = prawn.width_of(*arguments)
76
- width /= 2 if anchor == 'middle'
77
- arguments.last[:at][0] -= width
78
- end
79
-
80
- arguments.last[:at][1] += prawn.height_of(*arguments) / 3 * 2
81
- end
82
- end
83
- end