prawn-svg 0.15.0.0 → 0.19.0
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.
- 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
|