prawn-svg 0.15.0.0 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +20 -12
- data/lib/prawn/svg/calculators/aspect_ratio.rb +58 -0
- data/lib/prawn/svg/calculators/document_sizing.rb +75 -0
- data/lib/prawn/svg/calculators/pixels.rb +21 -0
- data/lib/prawn/svg/document.rb +16 -43
- data/lib/prawn/svg/element.rb +71 -18
- data/lib/prawn/svg/extension.rb +3 -3
- data/lib/prawn/svg/interface.rb +80 -19
- data/lib/prawn/svg/parser/image.rb +9 -62
- data/lib/prawn/svg/parser/path.rb +19 -1
- data/lib/prawn/svg/parser/text.rb +2 -0
- data/lib/prawn/svg/parser.rb +53 -18
- data/lib/prawn/svg/url_loader.rb +34 -0
- data/lib/prawn/svg/version.rb +1 -1
- data/lib/prawn-svg.rb +4 -0
- data/prawn-svg.gemspec +7 -4
- data/spec/integration_spec.rb +83 -0
- data/spec/prawn/svg/calculators/aspect_ratio_spec.rb +95 -0
- data/spec/prawn/svg/calculators/document_sizing_spec.rb +73 -0
- data/spec/prawn/svg/document_spec.rb +21 -17
- data/spec/prawn/svg/element_spec.rb +1 -1
- data/spec/prawn/svg/interface_spec.rb +59 -0
- data/spec/prawn/svg/parser/path_spec.rb +89 -0
- data/spec/prawn/svg/url_loader_spec.rb +46 -0
- data/spec/sample_images/mushroom-long.jpg +0 -0
- data/spec/sample_images/mushroom-wide.jpg +0 -0
- data/spec/sample_svg/cap_styles.svg +13 -0
- data/spec/sample_svg/display_none.svg +13 -0
- data/spec/sample_svg/gistfile1.svg +36 -0
- data/spec/sample_svg/hidden_paths.svg +6 -0
- data/spec/sample_svg/image01.svg +31 -31
- data/spec/sample_svg/negminy.svg +25 -0
- data/spec/sample_svg/path.svg +5 -0
- data/spec/sample_svg/pie_piece.svg +7 -0
- data/spec/sample_svg/viewbox.svg +4 -0
- data/spec/sample_svg/viewport.svg +23 -0
- data/spec/spec_helper.rb +7 -0
- metadata +81 -25
- data/spec/lib/path_spec.rb +0 -54
- data/spec/lib/svg_spec.rb +0 -47
- /data/spec/{lib → prawn/svg}/parser_spec.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcccb8c6d35a2f33debf7f17d04dc1a8b3099398
|
4
|
+
data.tar.gz: 3ac53d2c35c41f1de03582e46175a9bf296a6cd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea4c6fb099669924881a72e4d983a5b890a4e74d38eb5bc7e1173223485acc35a69b0dabf95c41329bc1c254a6be53771d98f5e13fcf5d5c118c2fa1b2bd85ce
|
7
|
+
data.tar.gz: d3440e0c86365ad251beec2011f1f243dfc35e24ee82af3684c925e2e9c08d4b44e416e366cbd036343908241567cfd75878929bc5ce98fa9e4f81cdde963317
|
data/README.md
CHANGED
@@ -6,6 +6,8 @@ This will take an SVG file as input and render it into your PDF. Find out more
|
|
6
6
|
|
7
7
|
http://wiki.github.com/sandal/prawn/
|
8
8
|
|
9
|
+
prawn-svg is compatible with all versions of Prawn from 0.8.4 onwards, including the 1.x and 2.x series.
|
10
|
+
|
9
11
|
## Using prawn-svg
|
10
12
|
|
11
13
|
```ruby
|
@@ -14,10 +16,13 @@ Prawn::Document.generate("svg.pdf") do
|
|
14
16
|
end
|
15
17
|
```
|
16
18
|
|
17
|
-
<tt>:at</tt>
|
19
|
+
Supply <tt>:at</tt> if you want to render it at a specific location on the page.
|
20
|
+
Use <tt>:position</tt> with a value of <tt>:left</tt>, <tt>:center</tt>, <tt>:right</tt> or a number to render it at the current cursor position, or use <tt>:vposition</tt> with a value
|
21
|
+
of <tt>:top</tt>, <tt>:center</tt>, <tt>:bottom</tt> or a number to specify its Y position too.
|
18
22
|
|
19
|
-
<tt>:width</tt>, <tt>:height</tt>, or neither may be specified; if neither is present,
|
20
|
-
the
|
23
|
+
Either <tt>:width</tt>, <tt>:height</tt>, or neither may be specified; if neither is present,
|
24
|
+
the dimensions specified in the SVG will be used, or if the dimensions aren't specified, it'll
|
25
|
+
fit to the space available on the page.
|
21
26
|
|
22
27
|
<tt>:cache_images</tt>, if set to true, will cache images per document based on their URL.
|
23
28
|
|
@@ -26,7 +31,7 @@ If this value is set to <tt>nil</tt>, prawn-svg will ignore a request for an unk
|
|
26
31
|
|
27
32
|
## Supported features
|
28
33
|
|
29
|
-
prawn-svg
|
34
|
+
prawn-svg supports most but not all of the full SVG 1.1 specification. It currently supports:
|
30
35
|
|
31
36
|
- <tt><line></tt>, <tt><polyline></tt>, <tt><polygon></tt>, <tt><circle></tt> and <tt><ellipse></tt>
|
32
37
|
|
@@ -36,36 +41,39 @@ prawn-svg does not support the full SVG specification. It currently supports:
|
|
36
41
|
implementation of elliptical arc is a bit rough at the moment.
|
37
42
|
|
38
43
|
- <tt><text></tt> and <tt><tspan></tt> with attributes
|
39
|
-
<tt>
|
44
|
+
<tt>text-anchor</tt>, <tt>font-size</tt>, <tt>font-family</tt>, <tt>font-weight</tt>, <tt>font-style</tt>, <tt>dx</tt>, <tt>dy</tt>
|
40
45
|
|
41
46
|
- <tt><svg></tt>, <tt><g></tt> and <tt><symbol></tt>
|
42
47
|
|
43
48
|
- <tt><use></tt>
|
44
49
|
|
45
|
-
- <tt><style></tt
|
50
|
+
- <tt><style></tt> plus <tt>id</tt>, <tt>class</tt> and <tt>style</tt> attributes (see CSS section below)
|
46
51
|
|
47
52
|
- <tt><image></tt> with <tt>http:</tt>, <tt>https:</tt> and <tt>data:image/*;base64</tt> schemes
|
48
53
|
|
49
54
|
- <tt><clipPath></tt>
|
50
55
|
|
51
|
-
- attributes/styles: <tt>fill</tt>, <tt>stroke</tt>, <tt>stroke-width</tt>, <tt>opacity</tt>, <tt>fill-opacity</tt>, <tt>stroke-opacity</tt>, <tt>transform</tt>, <tt>clip-path</tt>
|
56
|
+
- attributes/styles: <tt>fill</tt>, <tt>stroke</tt>, <tt>stroke-width</tt>, <tt>stroke-linecap</tt>, <tt>stroke-dasharray</tt>, <tt>opacity</tt>, <tt>fill-opacity</tt>, <tt>stroke-opacity</tt>, <tt>transform</tt>, <tt>clip-path</tt>, <tt>display</tt>
|
57
|
+
|
58
|
+
- the <tt>viewBox</tt> attribute on the <tt><svg></tt> tag
|
59
|
+
|
60
|
+
- the <tt>preserveAspectRatio</tt> attribute on the <tt><svg></tt> and <tt><image></tt> tags
|
52
61
|
|
53
62
|
- transform methods: <tt>translate</tt>, <tt>rotate</tt>, <tt>scale</tt>, <tt>matrix</tt>
|
54
63
|
|
55
64
|
- colors: HTML standard names, <tt>#xxx</tt>, <tt>#xxxxxx</tt>, <tt>rgb(1, 2, 3)</tt>, <tt>rgb(1%, 2%, 3%)</tt>
|
56
65
|
|
57
|
-
- measurements specified in <tt>pt</tt>, <tt>cm</tt>, <tt>dm</tt>, <tt>ft</tt>, <tt>in</tt>, <tt>m</tt>, <tt>mm</tt>, <tt>yd</tt>, <tt>%</tt>
|
66
|
+
- measurements specified in <tt>pt</tt>, <tt>cm</tt>, <tt>dm</tt>, <tt>ft</tt>, <tt>in</tt>, <tt>m</tt>, <tt>mm</tt>, <tt>yd</tt>, <tt>pc</tt>, <tt>%</tt>
|
58
67
|
|
59
|
-
- fonts: generic CSS fonts, built
|
68
|
+
- fonts: generic CSS fonts, built-in PDF fonts, and any TTF fonts in your fonts path
|
60
69
|
|
61
70
|
## CSS
|
62
71
|
|
63
|
-
|
64
|
-
so do not expect too much of it.
|
72
|
+
prawn-svg uses the css_parser gem to parse CSS <tt><style></tt> blocks. It only handles simple tag, class or id selectors; attribute and other advanced selectors are not supported.
|
65
73
|
|
66
74
|
## Not supported
|
67
75
|
|
68
|
-
prawn-svg does not support external references, measurements in <tt>en</tt> or <tt>em</tt>, sub-viewports, gradients/patterns or markers.
|
76
|
+
prawn-svg does not support external <tt>url()</tt> references, measurements in <tt>en</tt> or <tt>em</tt>, sub-viewports, gradients/patterns or markers.
|
69
77
|
|
70
78
|
## Configuration
|
71
79
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Prawn::Svg::Calculators
|
2
|
+
class AspectRatio
|
3
|
+
attr_reader :align, :defer
|
4
|
+
attr_reader :width, :height, :x, :y
|
5
|
+
|
6
|
+
def initialize(value, container_dimensions, object_dimensions)
|
7
|
+
values = (value || "xMidYMid meet").strip.split(/\s+/)
|
8
|
+
@x = @y = 0
|
9
|
+
|
10
|
+
if values.first == "defer"
|
11
|
+
@defer = true
|
12
|
+
values.shift
|
13
|
+
end
|
14
|
+
|
15
|
+
@align, @meet_or_slice = values
|
16
|
+
|
17
|
+
w_container, h_container = container_dimensions
|
18
|
+
w_object, h_object = object_dimensions
|
19
|
+
|
20
|
+
container_ratio = w_container / h_container.to_f
|
21
|
+
object_ratio = w_object / h_object.to_f
|
22
|
+
|
23
|
+
if @align == "none"
|
24
|
+
@width, @height = container_dimensions
|
25
|
+
else
|
26
|
+
matches = @align.to_s.strip.match(/\Ax(Min|Mid|Max)Y(Min|Mid|Max)\z/i) || [nil, "Mid", "Mid"]
|
27
|
+
|
28
|
+
if (container_ratio > object_ratio) == slice?
|
29
|
+
@width, @height = [w_container, w_container / object_ratio]
|
30
|
+
@y = case matches[2].downcase
|
31
|
+
when "min" then 0
|
32
|
+
when "mid" then (h_container - w_container/object_ratio)/2
|
33
|
+
when "max" then h_container - w_container/object_ratio
|
34
|
+
end
|
35
|
+
else
|
36
|
+
@width, @height = [h_container * object_ratio, h_container]
|
37
|
+
@x = case matches[1].downcase
|
38
|
+
when "min" then 0
|
39
|
+
when "mid" then (w_container - h_container*object_ratio)/2
|
40
|
+
when "max" then w_container - h_container*object_ratio
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def slice?
|
47
|
+
@meet_or_slice == "slice"
|
48
|
+
end
|
49
|
+
|
50
|
+
def meet?
|
51
|
+
@meet_or_slice != "slice"
|
52
|
+
end
|
53
|
+
|
54
|
+
def inspect
|
55
|
+
"[AspectRatio: #{@width},#{@height} offset #{@x},#{@y}]"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Prawn::Svg::Calculators
|
2
|
+
class DocumentSizing
|
3
|
+
attr_writer :document_width, :document_height
|
4
|
+
attr_writer :view_box, :preserve_aspect_ratio
|
5
|
+
attr_writer :requested_width, :requested_height
|
6
|
+
|
7
|
+
attr_reader :bounds
|
8
|
+
attr_reader :x_offset, :y_offset, :x_scale, :y_scale
|
9
|
+
attr_reader :viewport_width, :viewport_height, :viewport_diagonal, :output_width, :output_height
|
10
|
+
|
11
|
+
def initialize(bounds, attributes = nil)
|
12
|
+
@bounds = bounds
|
13
|
+
set_from_attributes(attributes) if attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_from_attributes(attributes)
|
17
|
+
@document_width = attributes['width']
|
18
|
+
@document_height = attributes['height']
|
19
|
+
@view_box = attributes['viewBox']
|
20
|
+
@preserve_aspect_ratio = attributes['preserveAspectRatio']
|
21
|
+
end
|
22
|
+
|
23
|
+
def calculate
|
24
|
+
@x_offset = @y_offset = 0
|
25
|
+
@x_scale = @y_scale = 1
|
26
|
+
|
27
|
+
width = Prawn::Svg::Calculators::Pixels.to_pixels(@document_width, @bounds[0])
|
28
|
+
height = Prawn::Svg::Calculators::Pixels.to_pixels(@document_height, @bounds[1])
|
29
|
+
|
30
|
+
default_aspect_ratio = "x#{width ? "Mid" : "Min"}Y#{height ? "Mid" : "Min"} meet"
|
31
|
+
|
32
|
+
width ||= @bounds[0]
|
33
|
+
height ||= @bounds[1]
|
34
|
+
|
35
|
+
if @view_box
|
36
|
+
values = @view_box.strip.split(/\s+/)
|
37
|
+
@x_offset, @y_offset, @viewport_width, @viewport_height = values.map {|value| value.to_f}
|
38
|
+
@x_offset = -@x_offset
|
39
|
+
|
40
|
+
@preserve_aspect_ratio ||= default_aspect_ratio
|
41
|
+
aspect = Prawn::Svg::Calculators::AspectRatio.new(@preserve_aspect_ratio, [width, height], [@viewport_width, @viewport_height])
|
42
|
+
@x_scale = aspect.width / @viewport_width
|
43
|
+
@y_scale = aspect.height / @viewport_height
|
44
|
+
@x_offset -= aspect.x
|
45
|
+
@y_offset -= aspect.y
|
46
|
+
end
|
47
|
+
|
48
|
+
@viewport_width ||= width
|
49
|
+
@viewport_height ||= height
|
50
|
+
|
51
|
+
# SVG 1.1 section 7.10
|
52
|
+
@viewport_diagonal = Math.sqrt(@viewport_width**2 + @viewport_height**2) / Math.sqrt(2)
|
53
|
+
|
54
|
+
if @requested_width
|
55
|
+
scale = @requested_width / width
|
56
|
+
width = @requested_width
|
57
|
+
height *= scale
|
58
|
+
@x_scale *= scale
|
59
|
+
@y_scale *= scale
|
60
|
+
|
61
|
+
elsif @requested_height
|
62
|
+
scale = @requested_height / height
|
63
|
+
height = @requested_height
|
64
|
+
width *= scale
|
65
|
+
@x_scale *= scale
|
66
|
+
@y_scale *= scale
|
67
|
+
end
|
68
|
+
|
69
|
+
@output_width = width
|
70
|
+
@output_height = height
|
71
|
+
|
72
|
+
self
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Prawn::Svg::Calculators
|
2
|
+
class Pixels
|
3
|
+
extend Prawn::Measurements
|
4
|
+
|
5
|
+
def self.to_pixels(value, axis_length)
|
6
|
+
if value.is_a?(String)
|
7
|
+
if match = value.match(/\d(cm|dm|ft|in|m|mm|yd)$/)
|
8
|
+
send("#{match[1]}2pt", value.to_f)
|
9
|
+
elsif match = value.match(/\dpc$/)
|
10
|
+
value.to_f * 15 # according to http://www.w3.org/TR/SVG11/coords.html
|
11
|
+
elsif value[-1..-1] == "%"
|
12
|
+
value.to_f * axis_length / 100.0
|
13
|
+
else
|
14
|
+
value.to_f
|
15
|
+
end
|
16
|
+
elsif value
|
17
|
+
value.to_f
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/prawn/svg/document.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
class Prawn::Svg::Document
|
2
|
-
include Prawn::Measurements
|
3
|
-
|
4
2
|
begin
|
5
3
|
require 'css_parser'
|
6
4
|
CSS_PARSER_LOADED = true
|
@@ -8,18 +6,14 @@ class Prawn::Svg::Document
|
|
8
6
|
CSS_PARSER_LOADED = false
|
9
7
|
end
|
10
8
|
|
11
|
-
DEFAULT_WIDTH = 640
|
12
|
-
DEFAULT_HEIGHT = 480
|
13
9
|
DEFAULT_FALLBACK_FONT_NAME = "Times-Roman"
|
14
10
|
|
15
11
|
# An +Array+ of warnings that occurred while parsing the SVG data.
|
16
12
|
attr_reader :warnings
|
17
|
-
|
18
|
-
# The scaling factor, as determined by the :width or :height options.
|
19
|
-
attr_accessor :scale
|
13
|
+
attr_writer :url_cache
|
20
14
|
|
21
15
|
attr_reader :root,
|
22
|
-
:
|
16
|
+
:sizing,
|
23
17
|
:cache_images, :fallback_font_name,
|
24
18
|
:css_parser, :elements_by_id
|
25
19
|
|
@@ -32,55 +26,34 @@ class Prawn::Svg::Document
|
|
32
26
|
@elements_by_id = {}
|
33
27
|
@cache_images = options[:cache_images]
|
34
28
|
@fallback_font_name = options.fetch(:fallback_font_name, DEFAULT_FALLBACK_FONT_NAME)
|
35
|
-
@actual_width, @actual_height = bounds # set this first so % width/heights can be used
|
36
29
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
else
|
42
|
-
@x_offset, @y_offset = [0, 0]
|
43
|
-
@actual_width = points(@root.attributes['width'] || DEFAULT_WIDTH, :x)
|
44
|
-
@actual_height = points(@root.attributes['height'] || DEFAULT_HEIGHT, :y)
|
45
|
-
end
|
30
|
+
@sizing = Prawn::Svg::Calculators::DocumentSizing.new(bounds, @root.attributes)
|
31
|
+
sizing.requested_width = options[:width]
|
32
|
+
sizing.requested_height = options[:height]
|
33
|
+
sizing.calculate
|
46
34
|
|
47
|
-
|
48
|
-
@width = @options[:width]
|
49
|
-
@scale = @options[:width] / @actual_width.to_f
|
50
|
-
elsif @options[:height]
|
51
|
-
@height = @options[:height]
|
52
|
-
@scale = @options[:height] / @actual_height.to_f
|
53
|
-
else
|
54
|
-
@scale = 1
|
55
|
-
end
|
35
|
+
@axis_to_size = {:x => sizing.viewport_width, :y => sizing.viewport_height}
|
56
36
|
|
57
|
-
|
58
|
-
@height ||= @actual_height * @scale
|
37
|
+
yield self if block_given?
|
59
38
|
end
|
60
39
|
|
61
40
|
def x(value)
|
62
|
-
|
41
|
+
points(value, :x)
|
63
42
|
end
|
64
43
|
|
65
44
|
def y(value)
|
66
|
-
|
45
|
+
sizing.output_height - points(value, :y)
|
67
46
|
end
|
68
47
|
|
69
48
|
def distance(value, axis = nil)
|
70
|
-
value &&
|
49
|
+
value && points(value, axis)
|
71
50
|
end
|
72
51
|
|
73
52
|
def points(value, axis = nil)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
else
|
80
|
-
value.to_f
|
81
|
-
end
|
82
|
-
else
|
83
|
-
value.to_f
|
84
|
-
end
|
53
|
+
Prawn::Svg::Calculators::Pixels.to_pixels(value, @axis_to_size.fetch(axis, sizing.viewport_diagonal))
|
54
|
+
end
|
55
|
+
|
56
|
+
def url_loader
|
57
|
+
@url_loader ||= Prawn::Svg::UrlLoader.new(:enable_cache => cache_images)
|
85
58
|
end
|
86
59
|
end
|
data/lib/prawn/svg/element.rb
CHANGED
@@ -55,14 +55,26 @@ class Prawn::Svg::Element
|
|
55
55
|
parse_opacity_attributes_and_call
|
56
56
|
parse_clip_path_attribute_and_call
|
57
57
|
draw_types = parse_fill_and_stroke_attributes_and_call
|
58
|
-
|
58
|
+
parse_stroke_attributes_and_call
|
59
59
|
parse_font_attributes_and_call
|
60
|
+
parse_display_attribute
|
61
|
+
apply_drawing_call(draw_types)
|
62
|
+
end
|
60
63
|
|
61
|
-
|
62
|
-
|
64
|
+
def apply_drawing_call(draw_types)
|
65
|
+
if !@state[:disable_drawing] && !container?
|
66
|
+
if draw_types.empty? || @state[:display] == "none"
|
67
|
+
add_call_and_enter("end_path")
|
68
|
+
else
|
69
|
+
add_call_and_enter(draw_types.join("_and_"))
|
70
|
+
end
|
63
71
|
end
|
64
72
|
end
|
65
73
|
|
74
|
+
def container?
|
75
|
+
Prawn::Svg::Parser::CONTAINER_TAGS.include?(name)
|
76
|
+
end
|
77
|
+
|
66
78
|
def parse_transform_attribute_and_call
|
67
79
|
return unless transform = @attributes['transform']
|
68
80
|
|
@@ -70,7 +82,7 @@ class Prawn::Svg::Element
|
|
70
82
|
case name
|
71
83
|
when 'translate'
|
72
84
|
x, y = arguments
|
73
|
-
add_call_and_enter name, @document.distance(x), -@document.distance(y)
|
85
|
+
add_call_and_enter name, @document.distance(x, :x), -@document.distance(y, :y)
|
74
86
|
|
75
87
|
when 'rotate'
|
76
88
|
r, x, y = arguments.collect {|a| a.to_f}
|
@@ -90,7 +102,7 @@ class Prawn::Svg::Element
|
|
90
102
|
@document.warnings << "transform 'matrix' must have six arguments"
|
91
103
|
else
|
92
104
|
a, b, c, d, e, f = arguments.collect {|argument| argument.to_f}
|
93
|
-
add_call_and_enter "transformation_matrix", a, -b, -c, d, @document.distance(e), -@document.distance(f)
|
105
|
+
add_call_and_enter "transformation_matrix", a, -b, -c, d, @document.distance(e, :x), -@document.distance(f, :y)
|
94
106
|
end
|
95
107
|
else
|
96
108
|
@document.warnings << "Unknown transformation '#{name}'; ignoring"
|
@@ -129,30 +141,58 @@ class Prawn::Svg::Element
|
|
129
141
|
end
|
130
142
|
|
131
143
|
def parse_fill_and_stroke_attributes_and_call
|
132
|
-
|
133
|
-
|
134
|
-
dec = @attributes[type.to_s]
|
144
|
+
["fill", "stroke"].select do |type|
|
145
|
+
dec = @attributes[type]
|
135
146
|
if dec == "none"
|
136
|
-
state[type] = false
|
147
|
+
state[type.to_sym] = false
|
137
148
|
elsif dec
|
138
|
-
state[type] = true
|
149
|
+
state[type.to_sym] = true
|
139
150
|
if color = Prawn::Svg::Color.color_to_hex(dec)
|
140
151
|
add_call "#{type}_color", color
|
141
152
|
end
|
142
153
|
end
|
143
154
|
|
144
|
-
|
155
|
+
state[type.to_sym]
|
145
156
|
end
|
146
|
-
draw_types
|
147
157
|
end
|
148
158
|
|
149
|
-
|
150
|
-
|
159
|
+
CAP_STYLE_TRANSLATIONS = {"butt" => :butt, "round" => :round, "square" => :projecting_square}
|
160
|
+
|
161
|
+
def parse_stroke_attributes_and_call
|
162
|
+
if width = @attributes['stroke-width']
|
163
|
+
add_call('line_width', @document.distance(width))
|
164
|
+
end
|
165
|
+
|
166
|
+
if (linecap = attribute_value_as_keyword('stroke-linecap')) && linecap != 'inherit'
|
167
|
+
add_call('cap_style', CAP_STYLE_TRANSLATIONS.fetch(linecap, :butt))
|
168
|
+
end
|
169
|
+
|
170
|
+
if dasharray = attribute_value_as_keyword('stroke-dasharray')
|
171
|
+
case dasharray
|
172
|
+
when 'inherit'
|
173
|
+
# don't do anything
|
174
|
+
when 'none'
|
175
|
+
add_call('undash')
|
176
|
+
else
|
177
|
+
array = dasharray.split(Prawn::Svg::Parser::COMMA_WSP_REGEXP)
|
178
|
+
array *= 2 if array.length % 2 == 1
|
179
|
+
number_array = array.map {|value| @document.distance(value)}
|
180
|
+
|
181
|
+
if number_array.any? {|number| number < 0}
|
182
|
+
@document.warnings << "stroke-dasharray cannot have negative numbers; treating as 'none'"
|
183
|
+
add_call('undash')
|
184
|
+
elsif number_array.inject(0) {|a, b| a + b} == 0
|
185
|
+
add_call('undash')
|
186
|
+
else
|
187
|
+
add_call('dash', number_array)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
151
191
|
end
|
152
192
|
|
153
193
|
def parse_font_attributes_and_call
|
154
194
|
if size = @attributes['font-size']
|
155
|
-
@state[:font_size] = size.to_f
|
195
|
+
@state[:font_size] = size.to_f
|
156
196
|
end
|
157
197
|
if weight = @attributes['font-weight']
|
158
198
|
font_updated = true
|
@@ -184,6 +224,9 @@ class Prawn::Svg::Element
|
|
184
224
|
end
|
185
225
|
end
|
186
226
|
|
227
|
+
def parse_display_attribute
|
228
|
+
@state[:display] = @attributes['display'].strip if @attributes['display']
|
229
|
+
end
|
187
230
|
|
188
231
|
def parse_css_method_calls(string)
|
189
232
|
string.scan(/\s*(\w+)\(([^)]+)\)\s*/).collect do |call|
|
@@ -218,7 +261,11 @@ class Prawn::Svg::Element
|
|
218
261
|
end
|
219
262
|
|
220
263
|
@attributes = parse_css_declarations(style)
|
221
|
-
|
264
|
+
|
265
|
+
element.attributes.each do |name, value|
|
266
|
+
name = name.downcase
|
267
|
+
@attributes[name] = value unless @attributes[name]
|
268
|
+
end
|
222
269
|
end
|
223
270
|
|
224
271
|
def parse_css_declarations(declarations)
|
@@ -228,10 +275,16 @@ class Prawn::Svg::Element
|
|
228
275
|
output = {}
|
229
276
|
declarations.split(/[\;$]+/m).each do |decs|
|
230
277
|
if matches = decs.match(/\s*(.[^:]*)\s*\:\s*(.[^;]*)\s*(;|\Z)/i)
|
231
|
-
property, value,
|
232
|
-
output[property] = value
|
278
|
+
property, value, _ = matches.captures
|
279
|
+
output[property.downcase] = value
|
233
280
|
end
|
234
281
|
end
|
235
282
|
output
|
236
283
|
end
|
284
|
+
|
285
|
+
def attribute_value_as_keyword(name)
|
286
|
+
if value = @attributes[name]
|
287
|
+
value.strip.downcase
|
288
|
+
end
|
289
|
+
end
|
237
290
|
end
|
data/lib/prawn/svg/extension.rb
CHANGED
@@ -14,10 +14,10 @@ module Prawn
|
|
14
14
|
#
|
15
15
|
# svg IO.read("example.svg"), :at => [100, 300], :width => 600
|
16
16
|
#
|
17
|
-
def svg(data, options={})
|
18
|
-
svg = Prawn::Svg::Interface.new(data, self, options)
|
17
|
+
def svg(data, options = {}, &block)
|
18
|
+
svg = Prawn::Svg::Interface.new(data, self, options, &block)
|
19
19
|
svg.draw
|
20
|
-
{:warnings => svg.document.warnings, :width => svg.document.
|
20
|
+
{:warnings => svg.document.warnings, :width => svg.document.sizing.output_width, :height => svg.document.sizing.output_height}
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|