prawn-svg 0.32.0 → 0.34.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +20 -3
  3. data/.gitignore +1 -0
  4. data/README.md +32 -24
  5. data/lib/prawn/svg/attributes/stroke.rb +5 -0
  6. data/lib/prawn/svg/color.rb +46 -22
  7. data/lib/prawn/svg/css/selector_parser.rb +11 -11
  8. data/lib/prawn/svg/css/stylesheets.rb +4 -4
  9. data/lib/prawn/svg/document.rb +20 -4
  10. data/lib/prawn/svg/elements/base.rb +10 -11
  11. data/lib/prawn/svg/elements/gradient.rb +2 -2
  12. data/lib/prawn/svg/elements/image.rb +54 -21
  13. data/lib/prawn/svg/elements/path.rb +0 -2
  14. data/lib/prawn/svg/elements/root.rb +1 -1
  15. data/lib/prawn/svg/elements/text_component.rb +12 -3
  16. data/lib/prawn/svg/elements/use.rb +20 -12
  17. data/lib/prawn/svg/elements.rb +1 -0
  18. data/lib/prawn/svg/gradients.rb +48 -0
  19. data/lib/prawn/svg/interface.rb +17 -187
  20. data/lib/prawn/svg/loaders/data.rb +4 -3
  21. data/lib/prawn/svg/properties.rb +2 -0
  22. data/lib/prawn/svg/renderer.rb +236 -0
  23. data/lib/prawn/svg/version.rb +1 -1
  24. data/lib/prawn-svg.rb +2 -0
  25. data/prawn-svg.gemspec +18 -16
  26. data/spec/prawn/svg/color_spec.rb +29 -16
  27. data/spec/prawn/svg/document_spec.rb +17 -0
  28. data/spec/prawn/svg/elements/marker_spec.rb +1 -1
  29. data/spec/prawn/svg/elements/root_spec.rb +28 -0
  30. data/spec/prawn/svg/elements/text_spec.rb +27 -0
  31. data/spec/prawn/svg/interface_spec.rb +10 -2
  32. data/spec/sample_images/image_svg_embed.svg +6 -0
  33. data/spec/sample_svg/cmyk.svg +5 -0
  34. data/spec/sample_svg/gradients-cmyk.svg +40 -0
  35. data/spec/sample_svg/image_svg.svg +9 -0
  36. data/spec/sample_svg/ordering.svg +12 -0
  37. data/spec/sample_svg/symbol.svg +12 -0
  38. data/spec/spec_helper.rb +29 -5
  39. metadata +67 -23
data/prawn-svg.gemspec CHANGED
@@ -1,27 +1,29 @@
1
- # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/prawn/svg/version', __FILE__)
1
+ require File.expand_path('lib/prawn/svg/version', __dir__)
3
2
 
4
3
  Gem::Specification.new do |gem|
5
4
  gem.name = 'prawn-svg'
6
5
  gem.version = Prawn::SVG::VERSION
7
- gem.summary = "SVG renderer for Prawn PDF library"
8
- gem.description = "This gem allows you to render SVG directly into a PDF using the 'prawn' gem. Since PDF is vector-based, you'll get nice scaled graphics if you use SVG instead of an image."
9
- gem.author = "Roger Nesbitt"
10
- gem.email = "roger@seriousorange.com"
11
- gem.homepage = "http://github.com/mogest/prawn-svg"
6
+ gem.summary = 'SVG renderer for Prawn PDF library'
7
+ gem.description = <<-EOT.strip
8
+ This gem allows you to render SVG directly into a PDF using the 'prawn' gem. Since PDF is vector-based, you'll get nice scaled graphics if you use SVG instead of an image.
9
+ EOT
10
+ gem.author = 'Mog Nesbitt'
11
+ gem.email = 'mog@seriousorange.com'
12
+ gem.homepage = 'http://github.com/mogest/prawn-svg'
12
13
  gem.license = 'MIT'
13
14
 
14
- gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
+ gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
15
16
  gem.files = `git ls-files`.split("\n")
16
17
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
- gem.name = "prawn-svg"
18
- gem.require_paths = ["lib"]
18
+ gem.require_paths = ['lib']
19
19
 
20
- gem.required_ruby_version = '>= 2.3.0'
20
+ gem.required_ruby_version = '>= 2.5.0'
21
21
 
22
- gem.add_runtime_dependency "prawn", ">= 0.11.1", "< 3"
23
- gem.add_runtime_dependency "css_parser", "~> 1.6"
24
- gem.add_runtime_dependency "rexml", "~> 3.2"
25
- gem.add_development_dependency "rspec", "~> 3.0"
26
- gem.add_development_dependency "rake", "~> 13.0"
22
+ gem.add_runtime_dependency 'base64', '~> 0.1.0'
23
+ gem.add_runtime_dependency 'css_parser', '~> 1.6'
24
+ gem.add_runtime_dependency 'matrix', '~> 0.4.2'
25
+ gem.add_runtime_dependency 'prawn', '>= 0.11.1', '< 3'
26
+ gem.add_runtime_dependency 'rexml', '~> 3.2'
27
+ gem.add_development_dependency 'rake', '~> 13.0'
28
+ gem.add_development_dependency 'rspec', '~> 3.0'
27
29
  end
@@ -1,38 +1,43 @@
1
1
  require File.dirname(__FILE__) + '/../../spec_helper'
2
2
 
3
3
  describe Prawn::SVG::Color do
4
- describe "::color_to_hex" do
4
+ describe "::css_color_to_prawn_color" do
5
5
  it "converts #xxx to a hex value" do
6
- Prawn::SVG::Color.color_to_hex("#9ab").should == "99aabb"
6
+ Prawn::SVG::Color.css_color_to_prawn_color("#9ab").should == "99aabb"
7
7
  end
8
8
 
9
9
  it "converts #xxxxxx to a hex value" do
10
- Prawn::SVG::Color.color_to_hex("#9ab123").should == "9ab123"
10
+ Prawn::SVG::Color.css_color_to_prawn_color("#9ab123").should == "9ab123"
11
11
  end
12
12
 
13
13
  it "converts an html colour name to a hex value" do
14
- Prawn::SVG::Color.color_to_hex("White").should == "ffffff"
14
+ Prawn::SVG::Color.css_color_to_prawn_color("White").should == "ffffff"
15
15
  end
16
16
 
17
17
  it "converts an rgb string to a hex value" do
18
- Prawn::SVG::Color.color_to_hex("rgb(16, 32, 48)").should == "102030"
19
- Prawn::SVG::Color.color_to_hex("rgb(-5, 50%, 120%)").should == "007fff"
18
+ Prawn::SVG::Color.css_color_to_prawn_color("rgb(16, 32, 48)").should == "102030"
19
+ Prawn::SVG::Color.css_color_to_prawn_color("rgb(-5, 50%, 120%)").should == "007fff"
20
+ end
21
+
22
+ it "converts a CMYK string to an array of numbers" do
23
+ expect(Prawn::SVG::Color.css_color_to_prawn_color("device-cmyk(0, 0.32, 0.48, 1)")).to eq [0, 32, 48, 100]
24
+ expect(Prawn::SVG::Color.css_color_to_prawn_color("device-cmyk(-5, 50%, 120%, -5%)")).to eq [0, 50, 100, 0]
20
25
  end
21
26
 
22
27
  it "scans the string and finds the first colour it can parse" do
23
- Prawn::SVG::Color.color_to_hex("function(#someurl, 0) nonexistent rgb( 3 ,4,5 ) white").should == "030405"
28
+ Prawn::SVG::Color.css_color_to_prawn_color("function(#someurl, 0) nonexistent rgb( 3 ,4,5 ) white").should == "030405"
24
29
  end
25
30
 
26
31
  it "ignores url()s" do
27
- expect(Prawn::SVG::Color.color_to_hex("url(#someplace) red")).to eq 'ff0000'
32
+ expect(Prawn::SVG::Color.css_color_to_prawn_color("url(#someplace) red")).to eq 'ff0000'
28
33
  end
29
34
 
30
35
  it "returns black if the color doesn't exist" do
31
- expect(Prawn::SVG::Color.color_to_hex("blurble")).to eq '000000'
36
+ expect(Prawn::SVG::Color.css_color_to_prawn_color("blurble")).to eq '000000'
32
37
  end
33
38
 
34
39
  it "returns nil if there's no fallback after a url()" do
35
- expect(Prawn::SVG::Color.color_to_hex("url(#someplace)")).to be nil
40
+ expect(Prawn::SVG::Color.css_color_to_prawn_color("url(#someplace)")).to be nil
36
41
  end
37
42
  end
38
43
 
@@ -42,19 +47,27 @@ describe Prawn::SVG::Color do
42
47
  let(:drob_gradient) { double }
43
48
 
44
49
  it "returns a list of all colors parsed, ignoring impossible or non-existent colors" do
45
- results = Prawn::SVG::Color.parse("url(#nope) url(#flan) blurble green #123", gradients)
50
+ results = Prawn::SVG::Color.parse("url(#nope) url(#flan) blurble green #123", gradients, :rgb)
46
51
  expect(results).to eq [
47
52
  flan_gradient,
48
- Prawn::SVG::Color::Hex.new("008000"),
49
- Prawn::SVG::Color::Hex.new("112233")
53
+ Prawn::SVG::Color::RGB.new("008000"),
54
+ Prawn::SVG::Color::RGB.new("112233")
50
55
  ]
51
56
  end
52
57
 
53
58
  it "appends black to the list if there aren't any url() references" do
54
- results = Prawn::SVG::Color.parse("blurble green", gradients)
59
+ results = Prawn::SVG::Color.parse("blurble green", gradients, :rgb)
60
+ expect(results).to eq [
61
+ Prawn::SVG::Color::RGB.new("008000"),
62
+ Prawn::SVG::Color::RGB.new("000000")
63
+ ]
64
+ end
65
+
66
+ it "works in CMYK color mode" do
67
+ results = Prawn::SVG::Color.parse("blurble green", gradients, :cmyk)
55
68
  expect(results).to eq [
56
- Prawn::SVG::Color::Hex.new("008000"),
57
- Prawn::SVG::Color::Hex.new("000000")
69
+ Prawn::SVG::Color::CMYK.new([100, 0, 100, 50]),
70
+ Prawn::SVG::Color::CMYK.new([0, 0, 0, 100])
58
71
  ]
59
72
  end
60
73
  end
@@ -5,6 +5,23 @@ describe Prawn::SVG::Document do
5
5
  let(:options) { {} }
6
6
 
7
7
  describe "#initialize" do
8
+ context "with a well-formed document" do
9
+ let(:svg) { "<svg></svg>" }
10
+ let(:options) { {color_mode: :cmyk} }
11
+
12
+ it "parses the XML and yields itself to its block" do
13
+ yielded = nil
14
+
15
+ document = Prawn::SVG::Document.new(svg, bounds, options) do |doc|
16
+ yielded = doc
17
+ end
18
+
19
+ expect(yielded).to eq document
20
+ expect(document.color_mode).to eq :cmyk
21
+ expect(document.root.name).to eq 'svg'
22
+ end
23
+ end
24
+
8
25
  context "when unparsable XML is provided" do
9
26
  let(:svg) { "this isn't SVG data" }
10
27
 
@@ -73,10 +73,10 @@ RSpec.describe Prawn::SVG::Elements::Marker do
73
73
  ["stroke_color", ["000000"], {}, []],
74
74
  ["line_width", [100.0], {}, []],
75
75
  ["cap_style", [:butt], {}, []],
76
+ ["join_style", [:miter], {}, []],
76
77
  ["undash", [], {}, []],
77
78
  ["save", [], {}, []],
78
79
  ["fill", [], {}, [
79
- ["join_style", [:bevel], {}, []],
80
80
  ["move_to", [[0.0, 600.0]], {}, []],
81
81
  ["line_to", [[10.0, 595.0]], {}, []],
82
82
  ["line_to", [[0.0, 590.0]], {}, []],
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Prawn::SVG::Elements::Root do
4
+ let(:color_mode) { :rgb }
5
+ let(:sizing) do
6
+ instance_double(Prawn::SVG::Calculators::DocumentSizing, x_offset: 0, y_offset: 0, x_scale: 1, y_scale: 1)
7
+ end
8
+ let(:document) do
9
+ instance_double(Prawn::SVG::Document, color_mode: color_mode, sizing: sizing)
10
+ end
11
+ let(:source) { double(name: 'svg', attributes: {}) }
12
+ let(:state) { Prawn::SVG::State.new }
13
+ let(:element) { Prawn::SVG::Elements::Root.new(document, source, [], state) }
14
+
15
+ it 'uses RGB black as the default color' do
16
+ element.apply
17
+ expect(element.calls.first).to eq ['fill_color', ['000000'], {}, []]
18
+ end
19
+
20
+ context 'when in CMYK mode' do
21
+ let(:color_mode) { :cmyk }
22
+
23
+ it 'uses CMYK black as the default color' do
24
+ element.apply
25
+ expect(element.calls.first).to eq ['fill_color', [[0, 0, 0, 100]], {}, []]
26
+ end
27
+ end
28
+ end
@@ -237,4 +237,31 @@ Even more
237
237
  ]
238
238
  end
239
239
  end
240
+
241
+ describe "when there's a comment inside the text element" do
242
+ let(:svg) { '<text>Hi <!-- comment --> there</text>' }
243
+
244
+ it "ignores the comment" do
245
+ element.process
246
+
247
+ expect(flatten_calls(element.calls)).to eq [
248
+ ["text_group", [], {}],
249
+ ["font", ["Helvetica"], {:style=>:normal}],
250
+ ["draw_text",
251
+ ["Hi "],
252
+ {:size=>16,
253
+ :style=>:normal,
254
+ :text_anchor=>"start",
255
+ :at=>[:relative, :relative],
256
+ :offset=>[0, 0]}],
257
+ ["draw_text",
258
+ ["there"],
259
+ {:size=>16,
260
+ :style=>:normal,
261
+ :text_anchor=>"start",
262
+ :at=>[:relative, :relative],
263
+ :offset=>[0, 0]}]
264
+ ]
265
+ end
266
+ end
240
267
  end
@@ -39,11 +39,19 @@ describe Prawn::SVG::Interface do
39
39
  end
40
40
 
41
41
  context "when fill_and_stroke is issued" do
42
+ def expect_rectangle
43
+ if RUBY_VERSION.start_with?("2.7.")
44
+ expect(prawn).to receive(:rectangle)
45
+ else
46
+ expect(prawn).to receive(:rectangle).with([0, 100], 10, 10)
47
+ end
48
+ end
49
+
42
50
  context "and fill rule is not set" do
43
51
  let(:interface) { Prawn::SVG::Interface.new('<svg width="250" height="100"><rect width="10" height="10" stroke="red"></rect></svg>', prawn, {}) }
44
52
 
45
53
  it "adds content 'B'" do
46
- expect(prawn).to receive(:rectangle).with([0, 100], 10, 10)
54
+ expect_rectangle
47
55
  expect(prawn).to receive(:add_content).with("W n")
48
56
  expect(prawn).to receive(:add_content).with("B")
49
57
  interface.draw
@@ -54,7 +62,7 @@ describe Prawn::SVG::Interface do
54
62
  let(:interface) { Prawn::SVG::Interface.new('<svg width="250" height="100"><rect width="10" height="10" stroke="red" fill-rule="evenodd"></rect></svg>', prawn, {}) }
55
63
 
56
64
  it "adds content 'B*'" do
57
- expect(prawn).to receive(:rectangle).with([0, 100], 10, 10)
65
+ expect_rectangle
58
66
  expect(prawn).to receive(:add_content).with("W n")
59
67
  expect(prawn).to receive(:add_content).with("B*")
60
68
  interface.draw
@@ -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,5 @@
1
+ <svg width="154" height="28" viewBox="0 0 154 28" xmlns="http://www.w3.org/2000/svg">
2
+ <g fill="device-cmyk(0.5, 50%, 0.0, 0)" fill-rule="evenodd">
3
+ <path d="m19.88 23.715-4.083 3.337a4.243 4.243 0 0 1-1.626-.965c-.463-.44-.768-.943-.915-1.508l-3.185 1.812c-.125.068-.336.138-.635.212a3.29 3.29 0 0 1-.754.11c-2.451 0-4.476-.841-6.073-2.524C1.011 22.506.212 20.168.212 17.175c0-2.846.83-5.192 2.491-7.039 1.66-1.847 3.777-2.77 6.353-2.77 1.027 0 1.988.203 2.88.61.892.407 1.479.768 1.762 1.084l2.948-1.067 1.034.305V19.92c0 1.016.178 1.824.533 2.422.354.599.91 1.057 1.667 1.373zm-7.166-2.541v-7.945a4.404 4.404 0 0 0-1.33-1.087c-.548-.303-1.217-.454-2.008-.454-1.141 0-2.086.416-2.837 1.248-.751.831-1.126 2.208-1.126 4.131 0 1.527.35 2.752 1.05 3.674.7.922 1.683 1.383 2.948 1.383.723 0 1.4-.113 2.033-.339.632-.227 1.055-.431 1.27-.611zM39.463 26.51h-3.947l-1.118-1.66-2.728 1.491c-.226.125-.553.217-.982.28a7.964 7.964 0 0 1-1.118.093c-2.666 0-4.69-.897-6.073-2.693s-2.081-4.049-2.092-6.759c-.011-2.937.822-5.274 2.499-7.014 1.677-1.739 3.894-2.609 6.649-2.609.79 0 1.485.062 2.083.187a5.903 5.903 0 0 1 1.728.661V.491h5.099V26.51zm-5.099-5.607v-8.03c-.283-.35-.751-.652-1.406-.906a5.855 5.855 0 0 0-2.134-.381c-1.423 0-2.482.415-3.177 1.245-.694.83-1.042 2.149-1.042 3.956 0 1.841.37 3.216 1.109 4.125.74.91 1.742 1.364 3.007 1.364.813 0 1.527-.135 2.143-.406.616-.271 1.116-.595 1.5-.967zM67.009 26.51h-5.184V15.075c0-.666-.237-1.256-.711-1.77-.475-.514-1.203-.771-2.186-.771-.938 0-1.722.195-2.354.584-.633.39-1.135.754-1.508 1.093V26.51h-5.184V8.299l5.184-.373v1.779l2.155-1.237a7.47 7.47 0 0 1 1.976-.805 8.464 8.464 0 0 1 2.01-.246c1.798 0 3.215.557 4.25 1.669 1.035 1.112 1.553 2.578 1.553 4.396V26.51h-.001zM89.303 17.057c0 2.993-.857 5.376-2.572 7.149-1.716 1.773-4.068 2.66-7.059 2.66-3.216 0-5.625-.892-7.227-2.677-1.603-1.784-2.404-4.162-2.404-7.132 0-2.699.863-5.008 2.59-6.929 1.726-1.92 4.073-2.88 7.041-2.88 2.979 0 5.328.887 7.05 2.66 1.72 1.774 2.581 4.156 2.581 7.149zm-5.252 0c0-1.479-.387-2.795-1.16-3.947-.773-1.152-1.844-1.728-3.21-1.728-1.57 0-2.694.525-3.372 1.575-.677 1.05-1.016 2.417-1.016 4.1 0 1.57.406 2.908 1.22 4.015.813 1.107 1.903 1.66 3.27 1.66 1.524 0 2.617-.449 3.278-1.347.66-.897.99-2.34.99-4.328zM101.145 23.325l-3.762 3.541c-1.559-.643-2.727-1.581-3.506-2.814-.779-1.233-1.17-2.708-1.17-4.42v-7.944H90.98V8.3h1.727V2.286l5.185-.373v6.404h2.71v3.354h-2.71v6.486c0 1.295.294 2.37.881 3.226.587.856 1.377 1.503 2.372 1.942zM121.981 23.715l-4.083 3.337a4.243 4.243 0 0 1-1.626-.965c-.464-.44-.769-.943-.915-1.508l-3.185 1.812c-.124.068-.337.138-.636.212a3.29 3.29 0 0 1-.754.11c-2.451 0-4.475-.841-6.072-2.524-1.599-1.683-2.398-4.021-2.398-7.014 0-2.846.83-5.192 2.491-7.039 1.66-1.847 3.777-2.77 6.353-2.77 1.027 0 1.988.203 2.88.61.892.407 1.479.768 1.762 1.084l2.948-1.067 1.033.305V19.92c0 1.016.178 1.824.533 2.422.355.598.913 1.057 1.669 1.373zm-7.166-2.541v-7.945a4.412 4.412 0 0 0-1.329-1.087c-.549-.303-1.218-.454-2.008-.454-1.141 0-2.087.416-2.838 1.248-.752.831-1.127 2.208-1.127 4.131 0 1.527.35 2.752 1.051 3.674.7.922 1.683 1.383 2.947 1.383.723 0 1.4-.113 2.033-.339.634-.227 1.057-.431 1.271-.611zM153.068 26.51h-5.15V15.075c0-.666-.229-1.256-.687-1.77-.457-.514-1.177-.771-2.159-.771-.803 0-1.52.155-2.152.466a4.972 4.972 0 0 0-1.592 1.211V26.51h-5.15V15.075c0-.666-.229-1.256-.686-1.77-.458-.514-1.178-.771-2.16-.771-.926 0-1.705.189-2.338.567-.633.378-1.096.749-1.389 1.11V26.51h-5.15V8.299l5.15-.373v1.779l2.016-1.237c.666-.406 1.32-.683 1.965-.83a8.86 8.86 0 0 1 1.965-.22c1.197 0 2.219.246 3.066.737a4.986 4.986 0 0 1 1.948 2.024l2.796-1.711a6.749 6.749 0 0 1 1.846-.788 8.17 8.17 0 0 1 2.084-.263c1.795 0 3.207.557 4.234 1.669 1.028 1.112 1.543 2.578 1.543 4.396V26.51zm0 0"/>
4
+ </g>
5
+ </svg>
@@ -0,0 +1,40 @@
1
+ <svg width="240" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <style type="text/css"><![CDATA[
4
+ #rect1 { fill: url(#Gradient1); }
5
+ .stop1 { stop-color: device-cmyk(0, 1, 1, 0); }
6
+ .stop2 { stop-color: device-cmyk(0, 0, 0, 1); stop-opacity: 0; }
7
+ .stop3 { stop-color: device-cmyk(1, 0, 1, 0); }
8
+ ]]></style>
9
+ <linearGradient id="Gradient1">
10
+ <stop class="stop1" offset="0%"/>
11
+ <stop class="stop2" offset="50%"/>
12
+ <stop class="stop3" offset="100%"/>
13
+ </linearGradient>
14
+ <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
15
+ <stop offset="25%" stop-color="device-cmyk(0, 1, 1, 0)"/>
16
+ <stop offset="50%" stop-color="device-cmyk(0, 0, 0, 1)" stop-opacity="0"/>
17
+ <stop offset="75%" stop-color="device-cmyk(1, 0, 1, 0)"/>
18
+ </linearGradient>
19
+ <linearGradient id="Gradient3" x1="0" x2="1" y1="0" y2="1">
20
+ <stop offset="0%" stop-color="device-cmyk(0, 1, 1, 0)"/>
21
+ <stop offset="30%" stop-color="device-cmyk(1, 0, 1, 0)"/>
22
+ <stop offset="60%" stop-color="device-cmyk(1, 0, 1, 0)"/>
23
+ <stop offset="100%" stop-color="device-cmyk(1, 0, 1, 0)"/>
24
+ </linearGradient>
25
+ <linearGradient id="userspace" gradientUnits="userSpaceOnUse" x1="160" y1="90" x2="220" y2="90">
26
+ <stop offset="0" stop-color="device-cmyk(0, 1, 1, 0)"/>
27
+ <stop offset="1" stop-color="device-cmyk(1, 0, 1, 0)"/>
28
+ </linearGradient>
29
+ </defs>
30
+
31
+ <rect id="rect1" x="10" y="10" rx="15" ry="15" width="50" height="100" stroke="black"/>
32
+ <rect x="10" y="120" rx="15" ry="15" width="50" height="100" fill="url(#Gradient2)" stroke="black"/>
33
+ <circle cx="110" cy="40" r="30" stroke="black" fill="url(#Gradient3)"/>
34
+ <ellipse cx="110" cy="100" rx="30" ry="20" stroke="black" fill="url(#Gradient1)"/>
35
+ <line x1="65" y1="120" x2="200" y2="200" stroke="url(#Gradient3)" stroke-width="5"/>
36
+ <path d="M80,140l0,50l30,20l0-40z" stroke="url(#Gradient3)" fill="url(#Gradient1)" stroke-width="3"/>
37
+ <polygon points="150,30 170,80 190,55 200,10" fill="url(#Gradient1)"/>
38
+ <rect x="150" y="90" width="80" height="30" fill="url(#userspace)" stroke="black"/>
39
+ <polyline points="150,130 170,170 190,155 200,110" stroke="url(#Gradient1)" stroke-width="3" fill="none"/>
40
+ </svg>
@@ -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"?>
2
+ <svg width="177.649" height="244.929" version="1.1" viewBox="0 0 177.649 244.929" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <g transform="translate(-21.1667 -31.75)">
4
+ <rect x="21.1667" y="31.75" width="177.649" height="244.929" fill="url(#linearGradient18)" stroke-width=".264583"/>
5
+ </g>
6
+ <defs>
7
+ <linearGradient id="linearGradient18" x1="109.032" x2="109.74" y1="34.6919" y2="273.287" gradientUnits="userSpaceOnUse">
8
+ <stop stop-color="orange" offset="0"/>
9
+ <stop stop-color="blue" offset="1"/>
10
+ </linearGradient>
11
+ </defs>
12
+ </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