prawn-svg 0.33.0 → 0.34.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9f71b82858f8ee91e1ccaf2903c2e2a0d49108b1532a81d15c2275362a0d136
4
- data.tar.gz: f3336c6a727df24e6a5877e4d26cf030eabbb1c9af9852f95c35c5bfe5128995
3
+ metadata.gz: fa5a995fd0ec6d8426dcc87603695e91ff743e1fddc559da6cc7fcc08ab5eb88
4
+ data.tar.gz: d76a03c53c2d7dab41db812e3309f59f32baefb730970015a8bb35d6fb791653
5
5
  SHA512:
6
- metadata.gz: 94f1a140e837ab37b088cc659bc8ef63a3e89778539236441f43e7b4885b9028cce1cb83c9e9636b00ff2ac740770ec8d853c123aa42b0764fb1264405269e76
7
- data.tar.gz: 4d02f2e14875214bb5460ace33925f9ab17302b39f46e0a37e0e5521e63b0fdd2f23f6018c8e048bf2bce7d148548aa86b5b9967dca827faddccfa23e8e09b13
6
+ metadata.gz: 0a686e69f4759243fc9b672a4bad663f17bf3f4f1a7016e560d816859d3d49464dfbb6416d877cf35f5362cd316111661e96817b645f707cc19999bae7e98f17
7
+ data.tar.gz: 57fbf5408c56228a286ca10221759440c4fc1326c0855acc4c5a74a30652ca59af277d170cf5bcb7f40b24bfe511e6ff82fd24e81da301e15595dc7f9d283e7a
@@ -6,7 +6,7 @@ jobs:
6
6
  strategy:
7
7
  fail-fast: false
8
8
  matrix:
9
- ruby: [2.6, 2.7, '3.0', 3.1, 3.2]
9
+ ruby: [2.6, 2.7, '3.0', 3.1, 3.2, 3.3]
10
10
  steps:
11
11
  - uses: actions/checkout@v4
12
12
  - name: Set up Ruby
data/.gitignore CHANGED
@@ -7,3 +7,4 @@ Gemfile.lock
7
7
  .ruby-version
8
8
  vendor/bundle/
9
9
  .bundle/
10
+ .mise.toml
data/README.md CHANGED
@@ -10,7 +10,7 @@ This will take an SVG document as input and render it into your PDF. Find out m
10
10
  http://github.com/prawnpdf/prawn
11
11
 
12
12
  prawn-svg is compatible with all versions of Prawn from 0.11.1 onwards, including the 1.x and 2.x series.
13
- The minimum Ruby version required is 2.3.0.
13
+ The minimum Ruby version required is 2.5.0.
14
14
 
15
15
  ## Using prawn-svg
16
16
 
@@ -33,7 +33,7 @@ Option | Data type | Description
33
33
  :enable_web_requests | boolean | If true, prawn-svg will make http and https requests to fetch images. Defaults to true.
34
34
  :enable_file_requests_with_root | string | If not nil, prawn-svg will serve `file:` URLs from your local disk if the file is located under the specified directory. It is very dangerous to specify the root path ("/") if you're not fully in control of your input SVG. Defaults to `nil` (off).
35
35
  :cache_images | boolean | If true, prawn-svg will cache the result of all URL requests. Defaults to false.
36
- :fallback_font_name | string | A font name which will override the default fallback font of Times-Roman. If this value is set to <tt>nil</tt>, prawn-svg will ignore a request for an unknown font and log a warning.
36
+ :fallback_font_name | string | A font name which will override the default fallback font of Times-Roman. If this value is set to `nil`, prawn-svg will ignore a request for an unknown font and log a warning.
37
37
  :color_mode | :rgb, :cmyk | Output color mode. Defaults to :rgb.
38
38
 
39
39
  ## Examples
@@ -54,52 +54,57 @@ Option | Data type | Description
54
54
 
55
55
  prawn-svg supports most but not all of the full SVG 1.1 specification. It currently supports:
56
56
 
57
- - <tt>&lt;line&gt;</tt>, <tt>&lt;polyline&gt;</tt>, <tt>&lt;polygon&gt;</tt>, <tt>&lt;circle&gt;</tt> and <tt>&lt;ellipse&gt;</tt>
57
+ - `<line>`, `<polyline>`, `<polygon>`, `<circle>` and `<ellipse>`
58
58
 
59
- - <tt>&lt;rect&gt;</tt>. Rounded rects are supported, but only one radius is applied to all corners.
59
+ - `<rect>`. Rounded rects are supported, but only one radius is applied to all corners.
60
60
 
61
- - <tt>&lt;path&gt;</tt> supports all commands defined in SVG 1.1, although the
61
+ - `<path>` supports all commands defined in SVG 1.1, although the
62
62
  implementation of elliptical arc is a bit rough at the moment.
63
63
 
64
- - `<text>`, `<tspan>` and `<tref>` with attributes `x`, `y`, `dx`, `dy`, `rotate`, 'textLength', 'lengthAdjust', and with extra properties
65
- `text-anchor`, `text-decoration` (underline only), `font-size`, `font-family`, `font-weight`, `font-style`, `letter-spacing`, `dominant-baseline` (middle only)
64
+ - `<text>`, `<tspan>` and `<tref>` with attributes `x`, `y`, `dx`, `dy`, `rotate`, `textLength`, `lengthAdjust`,
65
+ and with extra properties `text-anchor`, `text-decoration` (underline only), `font-size`, `font-family`,
66
+ `font-weight`, `font-style`, `letter-spacing`, `dominant-baseline` (middle only)
66
67
 
67
- - <tt>&lt;svg&gt;</tt>, <tt>&lt;g&gt;</tt> and <tt>&lt;symbol&gt;</tt>
68
+ - `<svg>`, `<g>` and `<symbol>`
68
69
 
69
- - <tt>&lt;use&gt;</tt>
70
+ - `<use>`
70
71
 
71
- - <tt>&lt;style&gt;</tt> (see CSS section below)
72
+ - `<style>` (see CSS section below)
72
73
 
73
- - `<image>` referencing a JPEG or PNG image, with `http:`, `https:`, `data:image/jpeg;base64`, `data:image/png;base64` and `file:` schemes
74
- (`file:` is disabled by default for security reasons, see Options section above)
74
+ - `<image>` referencing a JPEG, PNG, or SVG image, with `http:`, `https:`, `data:image/jpeg;base64`,
75
+ `data:image/png;base64`, `data:image/svg+xml;base64` and `file:` schemes (`file:` is disabled by default for
76
+ security reasons, see Options section above)
75
77
 
76
- - <tt>&lt;clipPath&gt;</tt>
78
+ - `<clipPath>`
77
79
 
78
80
  - `<marker>`
79
81
 
80
- - `<linearGradient>` and `<radialGradient>` are implemented on Prawn 2.2.0+ with attributes `gradientUnits` and `gradientTransform` (spreadMethod and stop-opacity are unimplemented.)
82
+ - `<linearGradient>` and `<radialGradient>` are implemented on Prawn 2.2.0+ with attributes `gradientUnits` and
83
+ `gradientTransform` (`spreadMethod` and `stop-opacity` are unimplemented.)
81
84
 
82
85
  - `<switch>` and `<foreignObject>`, although prawn-svg cannot handle any data that is not SVG so `<foreignObject>`
83
86
  tags are always ignored.
84
87
 
85
- - properties: `clip-path`, `color`, `display`, `fill`, `fill-opacity`, `fill-rule`, `opacity`, `overflow`, `stroke`, `stroke-dasharray`, `stroke-linecap`, `stroke-opacity`, `stroke-width`
88
+ - properties: `clip-path`, `color`, `display`, `fill`, `fill-opacity`, `fill-rule`, `opacity`, `overflow`,
89
+ `stroke`, `stroke-dasharray`, `stroke-linecap`, `stroke-linejoin`, `stroke-opacity`, `stroke-width`
86
90
 
87
91
  - properties on lines, polylines, polygons and paths: `marker-end`, `marker-mid`, `marker-start`
88
92
 
89
93
  - attributes on all elements: `class`, `id`, `style`, `transform`, `xml:space`
90
94
 
91
- - the <tt>viewBox</tt> attribute on <tt>&lt;svg&gt;</tt> and `<marker>` elements
95
+ - the `viewBox` attribute on `<svg>` and `<marker>` elements
92
96
 
93
- - the <tt>preserveAspectRatio</tt> attribute on <tt>&lt;svg&gt;</tt>, <tt>&lt;image&gt;</tt> and `<marker>` elements
97
+ - the `preserveAspectRatio` attribute on `<svg>`, `<image>` and `<marker>` elements
94
98
 
95
99
  - transform methods: `translate`, `translateX`, `translateY`, `rotate`, `scale`, `skewX`, `skewY`, `matrix`
96
100
 
97
- - colors: HTML standard names, <tt>#xxx</tt>, <tt>#xxxxxx</tt>, <tt>rgb(1, 2, 3)</tt>, <tt>rgb(1%, 2%, 3%)</tt>,
98
- and also the non-standard `device-cmyk(1, 2, 3, 4)` for CMYK colors
101
+ - colors: HTML standard names, `#xxx`, `#xxxxxx`, `rgb(1, 2, 3)`, `rgb(1%, 2%, 3%)`, and also the non-standard
102
+ `device-cmyk(1, 2, 3, 4)` for CMYK colors
99
103
 
100
- - 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>
104
+ - measurements specified in `pt`, `cm`, `dm`, `ft`, `in`, `m`, `mm`, `yd`, `pc`, `%`
101
105
 
102
- - fonts: generic CSS fonts, built-in PDF fonts, and any TTF fonts in your fonts path, specified in any of the measurements above plus `em` or `rem`
106
+ - fonts: generic CSS fonts, built-in PDF fonts, and any TTF fonts in your fonts path, specified in any of the
107
+ measurements above plus `em` or `rem`
103
108
 
104
109
  ## CSS
105
110
 
@@ -126,8 +131,9 @@ It does not support text in the clip area, but you can clip shapes and text by a
126
131
 
127
132
  ### Fonts
128
133
 
129
- By default, prawn-svg has a fonts path of <tt>["/Library/Fonts", "/System/Library/Fonts", "#{ENV["HOME"]}/Library/Fonts", "/usr/share/fonts/truetype"]</tt> to catch
130
- Mac OS X and Debian Linux users. You can add to the font path:
134
+ By default, prawn-svg has a fonts path of `["/Library/Fonts", "/System/Library/Fonts",
135
+ "#{ENV["HOME"]}/Library/Fonts", "/usr/share/fonts/truetype"]` to catch MacOS and Debian Linux users. You can add
136
+ to the font path:
131
137
 
132
138
  ```ruby
133
139
  Prawn::SVG::FontRegistry.font_path << "/my/font/directory"
@@ -139,4 +145,4 @@ In your Gemfile, put `gem 'prawn-svg'` before `gem 'prawn-rails'` so that prawn-
139
145
 
140
146
  ## Licence
141
147
 
142
- MIT licence. Copyright Roger Nesbitt.
148
+ MIT licence. Copyright Mog Nesbitt.
@@ -16,7 +16,7 @@ class Prawn::SVG::Document
16
16
  :element_styles,
17
17
  :color_mode
18
18
 
19
- def initialize(data, bounds, options, font_registry: nil, css_parser: CssParser::Parser.new)
19
+ def initialize(data, bounds, options, font_registry: nil, css_parser: CssParser::Parser.new, attribute_overrides: {})
20
20
  @root = REXML::Document.new(data).root
21
21
 
22
22
  if @root.nil?
@@ -41,7 +41,10 @@ class Prawn::SVG::Document
41
41
  enable_file_with_root: options[:enable_file_requests_with_root]
42
42
  )
43
43
 
44
- @sizing = Prawn::SVG::Calculators::DocumentSizing.new(bounds, @root.attributes)
44
+ attributes = @root.attributes.dup
45
+ attribute_overrides.each { |key, value| attributes.add(REXML::Attribute.new(key, value)) }
46
+
47
+ @sizing = Prawn::SVG::Calculators::DocumentSizing.new(bounds, attributes)
45
48
  calculate_sizing(requested_width: options[:width], requested_height: options[:height])
46
49
 
47
50
  @element_styles = Prawn::SVG::CSS::Stylesheets.new(css_parser, root).load
@@ -3,29 +3,32 @@ class Prawn::SVG::Elements::Image < Prawn::SVG::Elements::Base
3
3
  def initialize(data)
4
4
  @data = data
5
5
  end
6
+
6
7
  def read
7
8
  @data
8
9
  end
9
- def rewind
10
- end
10
+
11
+ def rewind; end
11
12
  end
12
13
 
14
+ ImageData = Struct.new(:dimensions, :document)
15
+
13
16
  def parse
14
17
  require_attributes 'width', 'height'
15
18
 
16
- raise SkipElementQuietly if state.computed_properties.display == "none"
19
+ raise SkipElementQuietly if state.computed_properties.display == 'none'
17
20
 
18
21
  @url = href_attribute
19
- if @url.nil?
20
- raise SkipElementError, "image tag must have an href or xlink:href"
21
- end
22
+ raise SkipElementError, 'image tag must have an href or xlink:href' if @url.nil?
22
23
 
23
24
  x = x(attributes['x'] || 0)
24
25
  y = y(attributes['y'] || 0)
25
26
  width = x_pixels(attributes['width'])
26
27
  height = y_pixels(attributes['height'])
28
+ preserveAspectRatio = attributes['preserveAspectRatio']
27
29
 
28
30
  raise SkipElementQuietly if width.zero? || height.zero?
31
+
29
32
  require_positive_value width, height
30
33
 
31
34
  @image = begin
@@ -34,7 +37,9 @@ class Prawn::SVG::Elements::Image < Prawn::SVG::Elements::Base
34
37
  raise SkipElementError, "Error retrieving URL #{@url}: #{e.message}"
35
38
  end
36
39
 
37
- @aspect = Prawn::SVG::Calculators::AspectRatio.new(attributes['preserveAspectRatio'], [width, height], image_dimensions(@image))
40
+ @image_data = process_image(@image, width, height, preserveAspectRatio)
41
+
42
+ @aspect = Prawn::SVG::Calculators::AspectRatio.new(preserveAspectRatio, [width, height], @image_data.dimensions)
38
43
 
39
44
  @clip_x = x
40
45
  @clip_y = y
@@ -49,15 +54,21 @@ class Prawn::SVG::Elements::Image < Prawn::SVG::Elements::Base
49
54
 
50
55
  def apply
51
56
  if @aspect.slice?
52
- add_call "save"
53
- add_call "rectangle", [@clip_x, @clip_y], @clip_width, @clip_height
54
- add_call "clip"
57
+ add_call 'save'
58
+ add_call 'rectangle', [@clip_x, @clip_y], @clip_width, @clip_height
59
+ add_call 'clip'
55
60
  end
56
61
 
57
- options = {:width => @width, :height => @height, :at => [@x, @y]}
62
+ if (document = @image_data.document)
63
+ add_call_and_enter 'translate', @x, @y
64
+ add_call 'svg:render_sub_document', document
65
+ else
66
+ options = { width: @width, height: @height, at: [@x, @y] }
67
+
68
+ add_call 'image', FakeIO.new(@image), options
69
+ end
58
70
 
59
- add_call "image", FakeIO.new(@image), options
60
- add_call "restore" if @aspect.slice?
71
+ add_call 'restore' if @aspect.slice?
61
72
  end
62
73
 
63
74
  def bounding_box
@@ -66,15 +77,38 @@ class Prawn::SVG::Elements::Image < Prawn::SVG::Elements::Base
66
77
 
67
78
  protected
68
79
 
69
- def image_dimensions(data)
70
- unless (handler = find_image_handler(data))
71
- raise SkipElementError, 'Unsupported image type supplied to image tag'
80
+ def process_image(data, width, height, preserveAspectRatio)
81
+ if (handler = find_image_handler(data))
82
+ image = handler.new(data)
83
+ ImageData.new([image.width.to_f, image.height.to_f], nil)
84
+
85
+ elsif potentially_svg?(data)
86
+ document = Prawn::SVG::Document.new(
87
+ data, [width, height], { width: width, height: height },
88
+ attribute_overrides: { 'preserveAspectRatio' => preserveAspectRatio }
89
+ )
90
+
91
+ dimensions = [document.sizing.output_width, document.sizing.output_height]
92
+ ImageData.new(dimensions, document)
93
+
94
+ else
95
+ raise_invalid_image_type
72
96
  end
73
- image = handler.new(data)
74
- [image.width.to_f, image.height.to_f]
97
+ rescue Prawn::SVG::Document::InvalidSVGData
98
+ raise_invalid_image_type
75
99
  end
76
100
 
77
101
  def find_image_handler(data)
78
- Prawn.image_handler.find(data) rescue nil
102
+ Prawn.image_handler.find(data)
103
+ rescue StandardError
104
+ nil
105
+ end
106
+
107
+ def potentially_svg?(data)
108
+ data.include?('<svg')
109
+ end
110
+
111
+ def raise_invalid_image_type
112
+ raise SkipElementError, 'Unsupported image type supplied to image tag'
79
113
  end
80
114
  end
@@ -9,6 +9,10 @@ class Prawn::SVG::Elements::TextComponent < Prawn::SVG::Elements::DepthFirstBase
9
9
  raise SkipElementError, "<text> elements are not supported in clip paths"
10
10
  end
11
11
 
12
+ if state.text.nil?
13
+ raise SkipElementError, "attempted to <use> an component inside a text element, this is not supported"
14
+ end
15
+
12
16
  state.text.x = (attributes['x'] || "").split(COMMA_WSP_REGEXP).collect { |n| x(n) }
13
17
  state.text.y = (attributes['y'] || "").split(COMMA_WSP_REGEXP).collect { |n| y(n) }
14
18
  state.text.dx = (attributes['dx'] || "").split(COMMA_WSP_REGEXP).collect { |n| x_pixels(n) }
@@ -1,15 +1,12 @@
1
1
  class Prawn::SVG::Elements::Use < Prawn::SVG::Elements::Base
2
- attr_reader :referenced_element_class
3
- attr_reader :referenced_element_source
2
+ attr_reader :referenced_element_class, :referenced_element_source
4
3
 
5
4
  def parse
6
5
  href = href_attribute
7
- if href.nil?
8
- raise SkipElementError, "use tag must have an href or xlink:href"
9
- end
6
+ raise SkipElementError, 'use tag must have an href or xlink:href' if href.nil?
10
7
 
11
8
  if href[0..0] != '#'
12
- raise SkipElementError, "use tag has an href that is not a reference to an id; this is not supported"
9
+ raise SkipElementError, 'use tag has an href that is not a reference to an id; this is not supported'
13
10
  end
14
11
 
15
12
  id = href[1..-1]
@@ -29,14 +26,18 @@ class Prawn::SVG::Elements::Use < Prawn::SVG::Elements::Base
29
26
  end
30
27
  end
31
28
 
32
- if referenced_element_class.nil?
33
- raise SkipElementError, "no tag with ID '#{id}' was found, referenced by use tag"
29
+ raise SkipElementError, "no tag with ID '#{id}' was found, referenced by use tag" if referenced_element_class.nil?
30
+
31
+ if referenced_element_source.name == 'symbol'
32
+ @referenced_element_class = Prawn::SVG::Elements::Viewport
34
33
  end
35
34
 
36
35
  state.inside_use = true
37
36
 
38
37
  @x = attributes['x']
39
38
  @y = attributes['y']
39
+ @width = attributes['width']
40
+ @height = attributes['height']
40
41
  end
41
42
 
42
43
  def container?
@@ -45,16 +46,23 @@ class Prawn::SVG::Elements::Use < Prawn::SVG::Elements::Base
45
46
 
46
47
  def apply
47
48
  if @x || @y
48
- add_call_and_enter "translate", x_pixels(@x || 0), -y_pixels(@y || 0)
49
+ add_call_and_enter 'translate', x_pixels(@x || 0), -y_pixels(@y || 0)
49
50
  end
50
51
  end
51
52
 
52
53
  def process_child_elements
53
- add_call "save"
54
+ add_call 'save'
55
+
56
+ source = referenced_element_source.dup
57
+
58
+ if referenced_element_class == Prawn::SVG::Elements::Viewport
59
+ source.attributes['width'] = @width || '100%'
60
+ source.attributes['height'] = @height || '100%'
61
+ end
54
62
 
55
- child = referenced_element_class.new(document, referenced_element_source, calls, state.dup)
63
+ child = referenced_element_class.new(document, source, calls, state.dup)
56
64
  child.process
57
65
 
58
- add_call "restore"
66
+ add_call 'restore'
59
67
  end
60
68
  end
@@ -37,5 +37,6 @@ module Prawn::SVG::Elements
37
37
  foreignObject: Prawn::SVG::Elements::Ignored,
38
38
  :"font-face" => Prawn::SVG::Elements::Ignored,
39
39
  filter: Prawn::SVG::Elements::Ignored, # unsupported
40
+ mask: Prawn::SVG::Elements::Ignored, # unsupported
40
41
  }
41
42
  end
@@ -5,7 +5,15 @@
5
5
  module Prawn
6
6
  module SVG
7
7
  class Interface
8
- VALID_OPTIONS = [:at, :position, :vposition, :width, :height, :cache_images, :enable_web_requests, :enable_file_requests_with_root, :fallback_font_name, :color_mode]
8
+ VALID_OPTIONS = %i[
9
+ at position vposition width height cache_images enable_web_requests
10
+ enable_file_requests_with_root fallback_font_name color_mode
11
+ ]
12
+
13
+ INHERITABLE_OPTIONS = %i[
14
+ enable_web_requests enable_file_requests_with_root
15
+ cache_images fallback_font_name color_mode
16
+ ]
9
17
 
10
18
  attr_reader :data, :prawn, :document, :options
11
19
 
@@ -25,33 +33,19 @@ module Prawn
25
33
 
26
34
  font_registry = Prawn::SVG::FontRegistry.new(prawn.font_families)
27
35
 
28
- @document = Document.new(data, [prawn.bounds.width, prawn.bounds.height], options, font_registry: font_registry, &block)
36
+ @document = Document.new(
37
+ data, [prawn.bounds.width, prawn.bounds.height], options,
38
+ font_registry: font_registry, &block
39
+ )
40
+
41
+ @renderer = Renderer.new(prawn, document, options)
29
42
  end
30
43
 
31
44
  #
32
45
  # Draws the SVG to the Prawn::Document object.
33
46
  #
34
47
  def draw
35
- if @document.sizing.invalid?
36
- @document.warnings << "Zero or negative sizing data means this SVG cannot be rendered"
37
- return
38
- end
39
-
40
- @document.warnings.clear
41
-
42
- prawn.save_font do
43
- prawn.bounding_box(position, :width => @document.sizing.output_width, :height => @document.sizing.output_height) do
44
- prawn.save_graphics_state do
45
- clip_rectangle 0, 0, @document.sizing.output_width, @document.sizing.output_height
46
-
47
- calls = []
48
- root_element = Prawn::SVG::Elements::Root.new(@document, @document.root, calls)
49
- root_element.process
50
-
51
- proc_creator(prawn, calls).call
52
- end
53
- end
54
- end
48
+ @renderer.draw
55
49
  end
56
50
 
57
51
  def sizing
@@ -63,183 +57,12 @@ module Prawn
63
57
  end
64
58
 
65
59
  def position
66
- @options[:at] || [x_based_on_requested_alignment, y_based_on_requested_alignment]
60
+ @renderer.position
67
61
  end
68
62
 
69
63
  def self.font_path # backwards support for when the font_path used to be stored on this class
70
64
  Prawn::SVG::FontRegistry.font_path
71
65
  end
72
-
73
- private
74
-
75
- def x_based_on_requested_alignment
76
- case options[:position]
77
- when :left, nil
78
- 0
79
- when :center, :centre
80
- (@document.sizing.bounds[0] - @document.sizing.output_width) / 2.0
81
- when :right
82
- @document.sizing.bounds[0] - @document.sizing.output_width
83
- when Numeric
84
- options[:position]
85
- else
86
- raise ArgumentError, "options[:position] must be one of nil, :left, :right, :center or a number"
87
- end
88
- end
89
-
90
- def y_based_on_requested_alignment
91
- case options[:vposition]
92
- when nil
93
- prawn.cursor
94
- when :top
95
- @document.sizing.bounds[1]
96
- when :center, :centre
97
- @document.sizing.bounds[1] - (@document.sizing.bounds[1] - @document.sizing.output_height) / 2.0
98
- when :bottom
99
- @document.sizing.output_height
100
- when Numeric
101
- @document.sizing.bounds[1] - options[:vposition]
102
- else
103
- raise ArgumentError, "options[:vposition] must be one of nil, :top, :right, :bottom or a number"
104
- end
105
- end
106
-
107
- def proc_creator(prawn, calls)
108
- Proc.new {issue_prawn_command(prawn, calls)}
109
- end
110
-
111
- def issue_prawn_command(prawn, calls)
112
- calls.each do |call, arguments, kwarguments, children|
113
- skip = false
114
-
115
- rewrite_call_arguments(prawn, call, arguments, kwarguments) do
116
- issue_prawn_command(prawn, children) if children.any?
117
- skip = true
118
- end
119
-
120
- if skip
121
- # the call has been overridden
122
- elsif children.empty? && call != 'transparent' # some prawn calls complain if they aren't supplied a block
123
- if RUBY_VERSION >= '2.7' || !kwarguments.empty?
124
- prawn.send(call, *arguments, **kwarguments)
125
- else
126
- prawn.send(call, *arguments)
127
- end
128
- else
129
- if RUBY_VERSION >= '2.7' || !kwarguments.empty?
130
- prawn.send(call, *arguments, **kwarguments, &proc_creator(prawn, children))
131
- else
132
- prawn.send(call, *arguments, &proc_creator(prawn, children))
133
- end
134
- end
135
- end
136
- end
137
-
138
- def rewrite_call_arguments(prawn, call, arguments, kwarguments)
139
- case call
140
- when 'text_group'
141
- @cursor = [0, document.sizing.output_height]
142
- yield
143
-
144
- when 'draw_text'
145
- text, options = arguments.first, kwarguments
146
-
147
- at = options.fetch(:at)
148
-
149
- at[0] = @cursor[0] if at[0] == :relative
150
- at[1] = @cursor[1] if at[1] == :relative
151
-
152
- case options.delete(:dominant_baseline)
153
- when 'middle'
154
- height = prawn.font.height
155
- at[1] -= height / 2.0
156
- @cursor = [at[0], at[1]]
157
- end
158
-
159
- if offset = options.delete(:offset)
160
- at[0] += offset[0]
161
- at[1] -= offset[1]
162
- end
163
-
164
- width = prawn.width_of(text, options.merge(kerning: true))
165
-
166
- if stretch_to_width = options.delete(:stretch_to_width)
167
- factor = stretch_to_width.to_f * 100 / width.to_f
168
- prawn.add_content "#{factor} Tz"
169
- width = stretch_to_width.to_f
170
- end
171
-
172
- if pad_to_width = options.delete(:pad_to_width)
173
- padding_required = pad_to_width.to_f - width.to_f
174
- padding_per_character = padding_required / text.length.to_f
175
- prawn.add_content "#{padding_per_character} Tc"
176
- width = pad_to_width.to_f
177
- end
178
-
179
- case options.delete(:text_anchor)
180
- when 'middle'
181
- at[0] -= width / 2
182
- @cursor = [at[0] + width / 2, at[1]]
183
- when 'end'
184
- at[0] -= width
185
- @cursor = at.dup
186
- else
187
- @cursor = [at[0] + width, at[1]]
188
- end
189
-
190
- decoration = options.delete(:decoration)
191
- if decoration == 'underline'
192
- prawn.save_graphics_state do
193
- prawn.line_width 1
194
- prawn.line [at[0], at[1] - 1.25], [at[0] + width, at[1] - 1.25]
195
- prawn.stroke
196
- end
197
- end
198
-
199
- when 'transformation_matrix'
200
- left = prawn.bounds.absolute_left
201
- top = prawn.bounds.absolute_top
202
- arguments[4] += left - (left * arguments[0] + top * arguments[2])
203
- arguments[5] += top - (left * arguments[1] + top * arguments[3])
204
-
205
- when 'clip'
206
- prawn.add_content "W n" # clip to path
207
- yield
208
-
209
- when 'save'
210
- prawn.save_graphics_state
211
- yield
212
-
213
- when 'restore'
214
- prawn.restore_graphics_state
215
- yield
216
-
217
- when "end_path"
218
- yield
219
- prawn.add_content "n" # end path
220
-
221
- when 'fill_and_stroke'
222
- yield
223
- # prawn (as at 2.0.1 anyway) uses 'b' for its fill_and_stroke. 'b' is 'h' (closepath) + 'B', and we
224
- # never want closepath to be automatically run as it stuffs up many drawing operations, such as dashes
225
- # and line caps, and makes paths close that we didn't ask to be closed when fill is specified.
226
- even_odd = kwarguments[:fill_rule] == :even_odd
227
- content = even_odd ? 'B*' : 'B'
228
- prawn.add_content content
229
-
230
- when 'noop'
231
- yield
232
- end
233
- end
234
-
235
- def clip_rectangle(x, y, width, height)
236
- prawn.move_to x, y
237
- prawn.line_to x + width, y
238
- prawn.line_to x + width, y + height
239
- prawn.line_to x, y + height
240
- prawn.close_path
241
- prawn.add_content "W n" # clip to path
242
- end
243
66
  end
244
67
  end
245
68
  end
@@ -2,14 +2,15 @@ require 'base64'
2
2
 
3
3
  module Prawn::SVG::Loaders
4
4
  class Data
5
- REGEXP = %r[\Adata:image/(png|jpeg);base64(;[a-z0-9]+)*,]i
5
+ REGEXP = %r{\Adata:image/(png|jpeg|svg\+xml);base64(;[a-z0-9]+)*,}i
6
6
 
7
7
  def from_url(url)
8
- return if url[0..4].downcase != "data:"
8
+ return if url[0..4].downcase != 'data:'
9
9
 
10
10
  matches = url.match(REGEXP)
11
11
  if matches.nil?
12
- raise Prawn::SVG::UrlLoader::Error, "prawn-svg only supports base64-encoded image/png and image/jpeg data URLs"
12
+ raise Prawn::SVG::UrlLoader::Error,
13
+ 'prawn-svg only supports base64-encoded image/png, image/jpeg, and image/svg+xml data URLs'
13
14
  end
14
15
 
15
16
  Base64.decode64(matches.post_match)
@@ -0,0 +1,236 @@
1
+ module Prawn
2
+ module SVG
3
+ class Renderer
4
+ attr_reader :prawn, :document, :options
5
+
6
+ #
7
+ # Creates a Prawn::SVG object.
8
+ #
9
+ # +data+ is the SVG data to convert. +prawn+ is your Prawn::Document object.
10
+ #
11
+ # See README.md for the options that can be passed to this method.
12
+ #
13
+ def initialize(prawn, document, options)
14
+ @prawn = prawn
15
+ @document = document
16
+ @options = options
17
+ end
18
+
19
+ #
20
+ # Draws the SVG to the Prawn::Document object.
21
+ #
22
+ def draw
23
+ if sizing.invalid?
24
+ document.warnings << 'Zero or negative sizing data means this SVG cannot be rendered'
25
+ return
26
+ end
27
+
28
+ document.warnings.clear
29
+
30
+ prawn.save_font do
31
+ prawn.bounding_box(position, width: sizing.output_width, height: sizing.output_height) do
32
+ prawn.save_graphics_state do
33
+ clip_rectangle 0, 0, sizing.output_width, sizing.output_height
34
+
35
+ calls = []
36
+ root_element = Prawn::SVG::Elements::Root.new(document, document.root, calls)
37
+ root_element.process
38
+
39
+ proc_creator(prawn, calls).call
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ def sizing
46
+ document.sizing
47
+ end
48
+
49
+ def position
50
+ options[:at] || [x_based_on_requested_alignment, y_based_on_requested_alignment]
51
+ end
52
+
53
+ private
54
+
55
+ def x_based_on_requested_alignment
56
+ case options[:position]
57
+ when :left, nil
58
+ 0
59
+ when :center, :centre
60
+ (sizing.bounds[0] - sizing.output_width) / 2.0
61
+ when :right
62
+ sizing.bounds[0] - sizing.output_width
63
+ when Numeric
64
+ options[:position]
65
+ else
66
+ raise ArgumentError, 'options[:position] must be one of nil, :left, :right, :center or a number'
67
+ end
68
+ end
69
+
70
+ def y_based_on_requested_alignment
71
+ case options[:vposition]
72
+ when nil
73
+ prawn.cursor
74
+ when :top
75
+ sizing.bounds[1]
76
+ when :center, :centre
77
+ sizing.bounds[1] - (sizing.bounds[1] - sizing.output_height) / 2.0
78
+ when :bottom
79
+ sizing.output_height
80
+ when Numeric
81
+ sizing.bounds[1] - options[:vposition]
82
+ else
83
+ raise ArgumentError, 'options[:vposition] must be one of nil, :top, :right, :bottom or a number'
84
+ end
85
+ end
86
+
87
+ def proc_creator(prawn, calls)
88
+ proc { issue_prawn_command(prawn, calls) }
89
+ end
90
+
91
+ def issue_prawn_command(prawn, calls)
92
+ calls.each do |call, arguments, kwarguments, children|
93
+ skip = false
94
+
95
+ rewrite_call_arguments(prawn, call, arguments, kwarguments) do
96
+ issue_prawn_command(prawn, children) if children.any?
97
+ skip = true
98
+ end
99
+
100
+ if skip
101
+ # the call has been overridden
102
+ elsif children.empty? && call != 'transparent' # some prawn calls complain if they aren't supplied a block
103
+ if RUBY_VERSION >= '2.7' || !kwarguments.empty?
104
+ prawn.send(call, *arguments, **kwarguments)
105
+ else
106
+ prawn.send(call, *arguments)
107
+ end
108
+ elsif RUBY_VERSION >= '2.7' || !kwarguments.empty?
109
+ prawn.send(call, *arguments, **kwarguments, &proc_creator(prawn, children))
110
+ else
111
+ prawn.send(call, *arguments, &proc_creator(prawn, children))
112
+ end
113
+ end
114
+ end
115
+
116
+ def rewrite_call_arguments(prawn, call, arguments, kwarguments)
117
+ case call
118
+ when 'text_group'
119
+ @cursor = [0, sizing.output_height]
120
+ yield
121
+
122
+ when 'draw_text'
123
+ text = arguments.first
124
+ options = kwarguments
125
+
126
+ at = options.fetch(:at)
127
+
128
+ at[0] = @cursor[0] if at[0] == :relative
129
+ at[1] = @cursor[1] if at[1] == :relative
130
+
131
+ case options.delete(:dominant_baseline)
132
+ when 'middle'
133
+ height = prawn.font.height
134
+ at[1] -= height / 2.0
135
+ @cursor = [at[0], at[1]]
136
+ end
137
+
138
+ if offset = options.delete(:offset)
139
+ at[0] += offset[0]
140
+ at[1] -= offset[1]
141
+ end
142
+
143
+ width = prawn.width_of(text, options.merge(kerning: true))
144
+
145
+ if stretch_to_width = options.delete(:stretch_to_width)
146
+ factor = stretch_to_width.to_f * 100 / width.to_f
147
+ prawn.add_content "#{factor} Tz"
148
+ width = stretch_to_width.to_f
149
+ end
150
+
151
+ if pad_to_width = options.delete(:pad_to_width)
152
+ padding_required = pad_to_width.to_f - width.to_f
153
+ padding_per_character = padding_required / text.length.to_f
154
+ prawn.add_content "#{padding_per_character} Tc"
155
+ width = pad_to_width.to_f
156
+ end
157
+
158
+ case options.delete(:text_anchor)
159
+ when 'middle'
160
+ at[0] -= width / 2
161
+ @cursor = [at[0] + width / 2, at[1]]
162
+ when 'end'
163
+ at[0] -= width
164
+ @cursor = at.dup
165
+ else
166
+ @cursor = [at[0] + width, at[1]]
167
+ end
168
+
169
+ decoration = options.delete(:decoration)
170
+ if decoration == 'underline'
171
+ prawn.save_graphics_state do
172
+ prawn.line_width 1
173
+ prawn.line [at[0], at[1] - 1.25], [at[0] + width, at[1] - 1.25]
174
+ prawn.stroke
175
+ end
176
+ end
177
+
178
+ when 'transformation_matrix'
179
+ left = prawn.bounds.absolute_left
180
+ top = prawn.bounds.absolute_top
181
+ arguments[4] += left - (left * arguments[0] + top * arguments[2])
182
+ arguments[5] += top - (left * arguments[1] + top * arguments[3])
183
+
184
+ when 'clip'
185
+ prawn.add_content 'W n' # clip to path
186
+ yield
187
+
188
+ when 'save'
189
+ prawn.save_graphics_state
190
+ yield
191
+
192
+ when 'restore'
193
+ prawn.restore_graphics_state
194
+ yield
195
+
196
+ when 'end_path'
197
+ yield
198
+ prawn.add_content 'n' # end path
199
+
200
+ when 'fill_and_stroke'
201
+ yield
202
+ # prawn (as at 2.0.1 anyway) uses 'b' for its fill_and_stroke. 'b' is 'h' (closepath) + 'B', and we
203
+ # never want closepath to be automatically run as it stuffs up many drawing operations, such as dashes
204
+ # and line caps, and makes paths close that we didn't ask to be closed when fill is specified.
205
+ even_odd = kwarguments[:fill_rule] == :even_odd
206
+ content = even_odd ? 'B*' : 'B'
207
+ prawn.add_content content
208
+
209
+ when 'noop'
210
+ yield
211
+
212
+ when 'svg:render_sub_document'
213
+ sub_document = arguments.first
214
+ sub_options = inheritable_options.merge({ at: [0, 0] })
215
+
216
+ Renderer.new(prawn, sub_document, sub_options).draw
217
+ document.warnings.concat(sub_document.warnings)
218
+ yield
219
+ end
220
+ end
221
+
222
+ def inheritable_options
223
+ (options || {}).slice(Prawn::SVG::Interface::INHERITABLE_OPTIONS)
224
+ end
225
+
226
+ def clip_rectangle(x, y, width, height)
227
+ prawn.move_to x, y
228
+ prawn.line_to x + width, y
229
+ prawn.line_to x + width, y + height
230
+ prawn.line_to x, y + height
231
+ prawn.close_path
232
+ prawn.add_content 'W n' # clip to path
233
+ end
234
+ end
235
+ end
236
+ end
@@ -1,5 +1,5 @@
1
1
  module Prawn
2
2
  module SVG
3
- VERSION = '0.33.0'
3
+ VERSION = '0.34.0'
4
4
  end
5
5
  end
data/lib/prawn-svg.rb CHANGED
@@ -21,6 +21,7 @@ require 'prawn/svg/properties'
21
21
  require 'prawn/svg/pathable'
22
22
  require 'prawn/svg/elements'
23
23
  require 'prawn/svg/extension'
24
+ require 'prawn/svg/renderer'
24
25
  require 'prawn/svg/interface'
25
26
  require 'prawn/svg/css/font_family_parser'
26
27
  require 'prawn/svg/css/selector_parser'
data/prawn-svg.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.required_ruby_version = '>= 2.5.0'
21
21
 
22
+ gem.add_runtime_dependency 'base64', '~> 0.1.0'
22
23
  gem.add_runtime_dependency 'css_parser', '~> 1.6'
23
24
  gem.add_runtime_dependency 'matrix', '~> 0.4.2'
24
25
  gem.add_runtime_dependency 'prawn', '>= 0.11.1', '< 3'
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
4
+ <rect x="0" y="0" width="100" height="100" fill="red" stroke="blue" stroke-width="5" />
5
+ </svg>
6
+
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
4
+ <rect x="20" y="20" width="960" height="460" stroke="black" fill="white" />
5
+ <image xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjExMDAiIGhlaWdodD0iNDAwIj4KICA8cmVjdCB4PSIxMDAiIHk9IjEwMCIgd2lkdGg9IjkwMCIgaGVpZ2h0PSIzMDAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmx1ZSIgc3Ryb2tlLXdpZHRoPSIyIiAvPgoKICA8cGF0aCBkPSJNMjAwIDIwMCBMODAwIDMwMCBMODAwIDIwMCIgc3Ryb2tlPSJncmVlbiIgc3Ryb2tlLXdpZHRoPSIxMCIgZmlsbD0icmVkIiAvPgo8L3N2Zz4K" x="100" y="200" width="200" height="200" />
6
+ <image xlink:href="sample_images/image_svg_embed.svg" x="400" y="200" width="200" height="200" />
7
+ <image xlink:href="sample_images/image_svg_embed.svg" x="650" y="200" width="100" height="200" />
8
+ <image xlink:href="sample_images/image_svg_embed.svg" x="800" y="200" width="100" height="200" preserveAspectRatio="none" />
9
+ </svg>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink='http://www.w3.org/1999/xlink' version="1.1">
4
+ <symbol id="rects" viewBox="0 0 100 100">
5
+ <rect x="10" y="10" width="80" height="80" fill="none" stroke="red"/>
6
+ <rect x="20" y="20" width="60" height="60" fill="none" stroke="green"/>
7
+ <rect x="30" y="30" width="40" height="40" fill="none" stroke="blue"/>
8
+ </symbol>
9
+ <rect width="1000" height="1000" fill="none" stroke="black"/>
10
+ <use x="100" y="100" width="800" height="800" xlink:href="#rects"/>
11
+ <use x="400" y="400" width="200" height="200" xlink:href="#rects"/>
12
+ </svg>
data/spec/spec_helper.rb CHANGED
@@ -3,12 +3,12 @@ Bundler.require(:default, :development)
3
3
 
4
4
  # Requires supporting files with custom matchers and macros, etc,
5
5
  # in ./support/ and its subdirectories.
6
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
6
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
7
7
 
8
8
  module Support
9
- def flatten_calls(calls)
9
+ def flatten_calls(_calls)
10
10
  [].tap do |flattened_calls|
11
- add = -> (local_calls) do
11
+ add = lambda do |local_calls|
12
12
  local_calls.each do |call|
13
13
  flattened_calls << call[0..2]
14
14
  add.call call[3]
@@ -28,12 +28,36 @@ end
28
28
 
29
29
  RSpec.configure do |config|
30
30
  config.mock_with :rspec do |c|
31
- c.syntax = [:should, :expect]
31
+ c.syntax = %i[should expect]
32
32
  end
33
33
 
34
34
  config.expect_with :rspec do |c|
35
- c.syntax = [:should, :expect]
35
+ c.syntax = %i[should expect]
36
36
  end
37
37
 
38
38
  config.include Support
39
+
40
+ config.before(:suite) do
41
+ # calculate the MD5 of all files in spec/sample_output and store in a hash
42
+ $hashes = {}
43
+
44
+ Dir["#{File.dirname(__FILE__)}/sample_output/*.pdf"].each do |file|
45
+ hash = Digest::MD5.file(file).hexdigest
46
+ $hashes[file] = hash
47
+ end
48
+ end
49
+
50
+ config.after(:suite) do
51
+ # print out the PDFs that have changed
52
+ changed = $hashes.select do |file, hash|
53
+ new_hash = Digest::MD5.file(file).hexdigest
54
+ new_hash != hash
55
+ end
56
+
57
+ if changed.any?
58
+ puts "\nThese PDFs have changed since the last test run:"
59
+ cwd = "#{Dir.pwd}/"
60
+ changed.each { |file, _| puts " #{file.sub(cwd, '')}" }
61
+ end
62
+ end
39
63
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prawn-svg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.33.0
4
+ version: 0.34.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mog Nesbitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-16 00:00:00.000000000 Z
11
+ date: 2024-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base64
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: css_parser
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +178,7 @@ files:
164
178
  - lib/prawn/svg/loaders/web.rb
165
179
  - lib/prawn/svg/pathable.rb
166
180
  - lib/prawn/svg/properties.rb
181
+ - lib/prawn/svg/renderer.rb
167
182
  - lib/prawn/svg/state.rb
168
183
  - lib/prawn/svg/transform_parser.rb
169
184
  - lib/prawn/svg/ttf.rb
@@ -201,6 +216,7 @@ files:
201
216
  - spec/prawn/svg/transform_parser_spec.rb
202
217
  - spec/prawn/svg/ttf_spec.rb
203
218
  - spec/prawn/svg/url_loader_spec.rb
219
+ - spec/sample_images/image_svg_embed.svg
204
220
  - spec/sample_images/mushroom-long.jpg
205
221
  - spec/sample_images/mushroom-wide.jpg
206
222
  - spec/sample_output/.keep
@@ -227,6 +243,7 @@ files:
227
243
  - spec/sample_svg/image01.svg
228
244
  - spec/sample_svg/image02_base64.svg
229
245
  - spec/sample_svg/image03.svg
246
+ - spec/sample_svg/image_svg.svg
230
247
  - spec/sample_svg/line01.svg
231
248
  - spec/sample_svg/links.svg
232
249
  - spec/sample_svg/marker.svg
@@ -257,6 +274,7 @@ files:
257
274
  - spec/sample_svg/subviewports.svg
258
275
  - spec/sample_svg/subviewports2.svg
259
276
  - spec/sample_svg/svg_fill.svg
277
+ - spec/sample_svg/symbol.svg
260
278
  - spec/sample_svg/text-decoration.svg
261
279
  - spec/sample_svg/text_entities.svg
262
280
  - spec/sample_svg/text_stroke.svg
@@ -296,7 +314,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
296
314
  - !ruby/object:Gem::Version
297
315
  version: '0'
298
316
  requirements: []
299
- rubygems_version: 3.4.10
317
+ rubygems_version: 3.5.3
300
318
  signing_key:
301
319
  specification_version: 4
302
320
  summary: SVG renderer for Prawn PDF library
@@ -332,6 +350,7 @@ test_files:
332
350
  - spec/prawn/svg/transform_parser_spec.rb
333
351
  - spec/prawn/svg/ttf_spec.rb
334
352
  - spec/prawn/svg/url_loader_spec.rb
353
+ - spec/sample_images/image_svg_embed.svg
335
354
  - spec/sample_images/mushroom-long.jpg
336
355
  - spec/sample_images/mushroom-wide.jpg
337
356
  - spec/sample_output/.keep
@@ -358,6 +377,7 @@ test_files:
358
377
  - spec/sample_svg/image01.svg
359
378
  - spec/sample_svg/image02_base64.svg
360
379
  - spec/sample_svg/image03.svg
380
+ - spec/sample_svg/image_svg.svg
361
381
  - spec/sample_svg/line01.svg
362
382
  - spec/sample_svg/links.svg
363
383
  - spec/sample_svg/marker.svg
@@ -388,6 +408,7 @@ test_files:
388
408
  - spec/sample_svg/subviewports.svg
389
409
  - spec/sample_svg/subviewports2.svg
390
410
  - spec/sample_svg/svg_fill.svg
411
+ - spec/sample_svg/symbol.svg
391
412
  - spec/sample_svg/text-decoration.svg
392
413
  - spec/sample_svg/text_entities.svg
393
414
  - spec/sample_svg/text_stroke.svg