prawn-svg 0.36.0 → 0.36.2
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/Gemfile.lock +1 -1
- data/lib/prawn/svg/document.rb +15 -12
- data/lib/prawn/svg/elements/base.rb +8 -0
- data/lib/prawn/svg/elements/gradient.rb +11 -6
- data/lib/prawn/svg/gradient_renderer.rb +13 -2
- data/lib/prawn/svg/version.rb +1 -1
- data/lib/prawn-svg.rb +1 -1
- data/spec/prawn/svg/document_spec.rb +18 -4
- data/spec/prawn/svg/elements/gradient_spec.rb +25 -7
- data/spec/sample_svg/gradient_offset_transparency.svg +45 -0
- metadata +4 -3
- /data/lib/prawn/svg/{transform_utils.rb → pdfmatrix.rb} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e2b791daa33f85948c08bdafec3f1a3ab8dffa8b07dd50ce7bb7a55320d663b
|
4
|
+
data.tar.gz: 78e45c7790de4b1cf2d328ad6ec8bbb77bab707cdeb8e75fcf52055410f36fc4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da875e08d850fd7d3b74d9e5a629d4f3125bc933614e0d241ddd4c5122ad75495d6b530c01914ad0bc44dbcbdec41ee5e35196e008c484652bbb99ecb0e66e53
|
7
|
+
data.tar.gz: 79f54a51c1acdea4a5d5de5bb72f130b5ca692aed48c72ceb36aced4f16df223be1a81f1152164dbdf3452571b79a676df96a4c38ba825afeedd32748e4f3919
|
data/Gemfile.lock
CHANGED
data/lib/prawn/svg/document.rb
CHANGED
@@ -18,18 +18,9 @@ class Prawn::SVG::Document
|
|
18
18
|
|
19
19
|
def initialize(data, bounds, options, font_registry: nil, css_parser: CssParser::Parser.new, attribute_overrides: {})
|
20
20
|
begin
|
21
|
-
@root = REXML::Document.new(data).root
|
22
|
-
rescue REXML::ParseException
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
if @root.nil?
|
27
|
-
if data.respond_to?(:end_with?) && data.end_with?('.svg')
|
28
|
-
raise InvalidSVGData,
|
29
|
-
"The data supplied is not a valid SVG document. It looks like you've supplied a filename instead; use IO.read(filename) to get the data before you pass it to prawn-svg."
|
30
|
-
else
|
31
|
-
raise InvalidSVGData, 'The data supplied is not a valid SVG document.'
|
32
|
-
end
|
21
|
+
@root = REXML::Document.new(data).root or raise_parse_error(data)
|
22
|
+
rescue REXML::ParseException => e
|
23
|
+
raise_parse_error(data, e.message)
|
33
24
|
end
|
34
25
|
|
35
26
|
@warnings = []
|
@@ -73,4 +64,16 @@ class Prawn::SVG::Document
|
|
73
64
|
raise ArgumentError, ':color_mode must be set to :rgb (default) or :cmyk'
|
74
65
|
end
|
75
66
|
end
|
67
|
+
|
68
|
+
def raise_parse_error(data, exception_message = nil)
|
69
|
+
message = 'The data supplied is not a valid SVG document.'
|
70
|
+
|
71
|
+
if data.respond_to?(:end_with?) && data.end_with?('.svg')
|
72
|
+
message += " It looks like you've supplied a filename instead; use File.read(filename) to get the data from the file before you pass it to prawn-svg."
|
73
|
+
end
|
74
|
+
|
75
|
+
message += "\n#{exception_message}" if exception_message
|
76
|
+
|
77
|
+
raise InvalidSVGData, message
|
78
|
+
end
|
76
79
|
end
|
@@ -262,6 +262,14 @@ class Prawn::SVG::Elements::Base
|
|
262
262
|
['hidden', 'scroll'].include?(computed_properties.overflow)
|
263
263
|
end
|
264
264
|
|
265
|
+
def stroke_width
|
266
|
+
if computed_properties.stroke.none?
|
267
|
+
0
|
268
|
+
else
|
269
|
+
pixels(properties.stroke_width) || 1.0
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
265
273
|
def clone_element_source(source)
|
266
274
|
new_source = source.dup
|
267
275
|
document.element_styles[new_source] = document.element_styles[source]
|
@@ -28,6 +28,9 @@ class Prawn::SVG::Elements::Gradient < Prawn::SVG::Elements::Base
|
|
28
28
|
def gradient_arguments(element)
|
29
29
|
bbox = element.bounding_box
|
30
30
|
|
31
|
+
stroke_width = element.stroke_width
|
32
|
+
bbox_with_stroke = bbox&.zip([-stroke_width, stroke_width, stroke_width, -stroke_width])&.map(&:sum)
|
33
|
+
|
31
34
|
if type == :radial
|
32
35
|
{
|
33
36
|
from: [fx, fy],
|
@@ -35,18 +38,18 @@ class Prawn::SVG::Elements::Gradient < Prawn::SVG::Elements::Base
|
|
35
38
|
to: [cx, cy],
|
36
39
|
r2: r,
|
37
40
|
stops: stops,
|
38
|
-
matrix: matrix_for_bounding_box(
|
41
|
+
matrix: matrix_for_bounding_box(bbox),
|
39
42
|
wrap: wrap,
|
40
|
-
bounding_box:
|
43
|
+
bounding_box: bbox_with_stroke
|
41
44
|
}
|
42
45
|
else
|
43
46
|
{
|
44
47
|
from: [x1, y1],
|
45
48
|
to: [x2, y2],
|
46
49
|
stops: stops,
|
47
|
-
matrix: matrix_for_bounding_box(
|
50
|
+
matrix: matrix_for_bounding_box(bbox),
|
48
51
|
wrap: wrap,
|
49
|
-
bounding_box:
|
52
|
+
bounding_box: bbox_with_stroke
|
50
53
|
}
|
51
54
|
end
|
52
55
|
end
|
@@ -57,8 +60,10 @@ class Prawn::SVG::Elements::Gradient < Prawn::SVG::Elements::Base
|
|
57
60
|
|
58
61
|
private
|
59
62
|
|
60
|
-
def matrix_for_bounding_box(
|
61
|
-
if units == :bounding_box
|
63
|
+
def matrix_for_bounding_box(bbox)
|
64
|
+
if bbox && units == :bounding_box
|
65
|
+
bounding_x1, bounding_y1, bounding_x2, bounding_y2 = *bbox
|
66
|
+
|
62
67
|
width = bounding_x2 - bounding_x1
|
63
68
|
height = bounding_y1 - bounding_y2
|
64
69
|
|
@@ -79,10 +79,21 @@ class Prawn::SVG::GradientRenderer
|
|
79
79
|
|
80
80
|
repeat_count, repeat_offset, transform = compute_wrapping(wrap, from, to, current_pdf_translation)
|
81
81
|
|
82
|
+
x0, y0, x1, y1 = bounding_box || prawn_bounding_box
|
83
|
+
|
84
|
+
offset_x, offset_y = prawn.bounds.anchor
|
85
|
+
x0 += offset_x
|
86
|
+
y0 += offset_y
|
87
|
+
x1 += offset_x
|
88
|
+
y1 += offset_y
|
89
|
+
|
90
|
+
width = x1 - x0
|
91
|
+
height = y0 - y1
|
92
|
+
|
82
93
|
transparency_group = prawn.ref!(
|
83
94
|
Type: :XObject,
|
84
95
|
Subtype: :Form,
|
85
|
-
BBox:
|
96
|
+
BBox: [x0, y1, x1, y0],
|
86
97
|
Group: {
|
87
98
|
Type: :Group,
|
88
99
|
S: :Transparency,
|
@@ -108,7 +119,7 @@ class Prawn::SVG::GradientRenderer
|
|
108
119
|
)
|
109
120
|
|
110
121
|
transparency_group.stream << begin
|
111
|
-
box = PDF::Core.real_params(
|
122
|
+
box = PDF::Core.real_params([x0, y1, width, height])
|
112
123
|
|
113
124
|
<<~CMDS.strip
|
114
125
|
/Pattern cs
|
data/lib/prawn/svg/version.rb
CHANGED
data/lib/prawn-svg.rb
CHANGED
@@ -10,7 +10,7 @@ require 'prawn/svg/calculators/arc_to_bezier_curve'
|
|
10
10
|
require 'prawn/svg/calculators/aspect_ratio'
|
11
11
|
require 'prawn/svg/calculators/document_sizing'
|
12
12
|
require 'prawn/svg/calculators/pixels'
|
13
|
-
require 'prawn/svg/
|
13
|
+
require 'prawn/svg/pdfmatrix'
|
14
14
|
require 'prawn/svg/transform_parser'
|
15
15
|
require 'prawn/svg/url_loader'
|
16
16
|
require 'prawn/svg/loaders/data'
|
@@ -25,10 +25,22 @@ describe Prawn::SVG::Document do
|
|
25
25
|
context 'when unparsable XML is provided' do
|
26
26
|
let(:svg) { "this isn't SVG data" }
|
27
27
|
|
28
|
-
it
|
28
|
+
it "raises an exception, passing on REXML's error message" do
|
29
29
|
expect do
|
30
30
|
Prawn::SVG::Document.new(svg, bounds, options)
|
31
|
-
end.to raise_error Prawn::SVG::Document::InvalidSVGData,
|
31
|
+
end.to raise_error Prawn::SVG::Document::InvalidSVGData,
|
32
|
+
/\AThe data supplied is not a valid SVG document.+Malformed.+#{Regexp.escape(svg)}/m
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when broken XML is provided' do
|
37
|
+
let(:svg) { '<svg><g><rect></rect></svg>' }
|
38
|
+
|
39
|
+
it "raises an exception, passing on REXML's error message" do
|
40
|
+
expect do
|
41
|
+
Prawn::SVG::Document.new(svg, bounds, options)
|
42
|
+
end.to raise_error Prawn::SVG::Document::InvalidSVGData,
|
43
|
+
/\AThe data supplied is not a valid SVG document.+Missing end tag for 'g'/m
|
32
44
|
end
|
33
45
|
end
|
34
46
|
|
@@ -36,10 +48,12 @@ describe Prawn::SVG::Document do
|
|
36
48
|
let(:svg) { 'some_file.svg' }
|
37
49
|
|
38
50
|
it "raises an exception letting them know what they've done" do
|
51
|
+
message = "The data supplied is not a valid SVG document. It looks like you've supplied a filename " \
|
52
|
+
'instead; use File.read(filename) to get the data from the file before you pass it to prawn-svg.'
|
53
|
+
|
39
54
|
expect do
|
40
55
|
Prawn::SVG::Document.new(svg, bounds, options)
|
41
|
-
end.to raise_error Prawn::SVG::Document::InvalidSVGData,
|
42
|
-
"The data supplied is not a valid SVG document. It looks like you've supplied a filename instead; use IO.read(filename) to get the data before you pass it to prawn-svg."
|
56
|
+
end.to raise_error Prawn::SVG::Document::InvalidSVGData, /\A#{Regexp.escape(message)}/
|
43
57
|
end
|
44
58
|
end
|
45
59
|
end
|
@@ -24,8 +24,26 @@ describe Prawn::SVG::Elements::Gradient do
|
|
24
24
|
expect(document.gradients['flag']).to eq element
|
25
25
|
end
|
26
26
|
|
27
|
+
it 'returns correct gradient arguments for an element with no bounding box' do
|
28
|
+
arguments = element.gradient_arguments(double(bounding_box: nil, stroke_width: 0))
|
29
|
+
expect(arguments).to eq(
|
30
|
+
from: [0.0, 0.0],
|
31
|
+
to: [0.2, 1.0],
|
32
|
+
wrap: :pad,
|
33
|
+
matrix: Matrix[[1.0, 0.0, 0.0], [0.0, -1.0, 600.0], [0.0, 0.0, 1.0]],
|
34
|
+
bounding_box: nil,
|
35
|
+
stops: [
|
36
|
+
{ offset: 0, color: 'ff0000', opacity: 1.0 },
|
37
|
+
{ offset: 0.25, color: 'ff0000', opacity: 1.0 },
|
38
|
+
{ offset: 0.5, color: 'ffffff', opacity: 1.0 },
|
39
|
+
{ offset: 0.75, color: '0000ff', opacity: 1.0 },
|
40
|
+
{ offset: 1, color: '0000ff', opacity: 1.0 }
|
41
|
+
]
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
27
45
|
it 'returns correct gradient arguments for an element' do
|
28
|
-
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
46
|
+
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0], stroke_width: 0))
|
29
47
|
expect(arguments).to eq(
|
30
48
|
from: [0.0, 0.0],
|
31
49
|
to: [0.2, 1.0],
|
@@ -59,7 +77,7 @@ describe Prawn::SVG::Elements::Gradient do
|
|
59
77
|
end
|
60
78
|
|
61
79
|
it 'returns correct gradient arguments for an element' do
|
62
|
-
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
80
|
+
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0], stroke_width: 0))
|
63
81
|
expect(arguments).to eq(
|
64
82
|
from: [0.5, 0.2],
|
65
83
|
to: [0.0, 0.2],
|
@@ -90,7 +108,7 @@ describe Prawn::SVG::Elements::Gradient do
|
|
90
108
|
end
|
91
109
|
|
92
110
|
it 'returns correct gradient arguments for an element' do
|
93
|
-
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
111
|
+
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0], stroke_width: 0))
|
94
112
|
expect(arguments).to eq(
|
95
113
|
from: [100.0, 500.0],
|
96
114
|
to: [200.0, 600.0],
|
@@ -113,7 +131,7 @@ describe Prawn::SVG::Elements::Gradient do
|
|
113
131
|
end
|
114
132
|
|
115
133
|
it 'returns correct gradient arguments for an element' do
|
116
|
-
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
134
|
+
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0], stroke_width: 0))
|
117
135
|
expect(arguments).to eq(
|
118
136
|
from: [100.0, 500.0],
|
119
137
|
to: [200.0, 600.0],
|
@@ -138,7 +156,7 @@ describe Prawn::SVG::Elements::Gradient do
|
|
138
156
|
end
|
139
157
|
|
140
158
|
it 'passes in the transform via the apply_transformations option' do
|
141
|
-
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
159
|
+
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0], stroke_width: 0))
|
142
160
|
|
143
161
|
expect(arguments).to eq(
|
144
162
|
from: [0.0, 0.0],
|
@@ -168,7 +186,7 @@ describe Prawn::SVG::Elements::Gradient do
|
|
168
186
|
end
|
169
187
|
|
170
188
|
it 'correctly inherits the attributes from the parent element' do
|
171
|
-
arguments = document.gradients['flag-2'].gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
189
|
+
arguments = document.gradients['flag-2'].gradient_arguments(double(bounding_box: [100, 100, 200, 0], stroke_width: 0))
|
172
190
|
expect(arguments).to eq(
|
173
191
|
from: [150.0, 500.0],
|
174
192
|
to: [220.0, 600.0],
|
@@ -178,7 +196,7 @@ describe Prawn::SVG::Elements::Gradient do
|
|
178
196
|
bounding_box: [100, 100, 200, 0]
|
179
197
|
)
|
180
198
|
|
181
|
-
arguments = document.gradients['flag-3'].gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
199
|
+
arguments = document.gradients['flag-3'].gradient_arguments(double(bounding_box: [100, 100, 200, 0], stroke_width: 0))
|
182
200
|
expect(arguments).to eq(
|
183
201
|
from: [170.0, 500.0],
|
184
202
|
to: [220.0, 600.0],
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<svg id="Illustration" viewBox="0 0 1275 850" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
3
|
+
<defs>
|
4
|
+
<style>.cls-3{fill:url(#linear-gradient);}.cls-5{fill:url(#linear-gradient-3);}.cls-6{fill:url(#linear-gradient-4);}.cls-7{fill:url(#linear-gradient-2);}</style>
|
5
|
+
<linearGradient gradientTransform="translate(3610.94 -4546.2)" gradientUnits="userSpaceOnUse" id="linear-gradient" x1="-3428.66" x2="-2829.15" y1="4803.57" y2="4803.57">
|
6
|
+
<stop offset="0" stop-color="orange" stop-opacity="0"/>
|
7
|
+
<stop offset=".04" stop-color="orange" stop-opacity=".04"/>
|
8
|
+
<stop offset=".12" stop-color="orange" stop-opacity=".16"/>
|
9
|
+
<stop offset=".21" stop-color="orange" stop-opacity=".34"/>
|
10
|
+
<stop offset=".32" stop-color="orange" stop-opacity=".6"/>
|
11
|
+
<stop offset=".44" stop-color="orange" stop-opacity=".92"/>
|
12
|
+
<stop offset=".47" stop-color="orange"/>
|
13
|
+
<stop offset=".58" stop-color="darksalmon"/>
|
14
|
+
<stop offset=".8" stop-color="darksalmon"/>
|
15
|
+
<stop offset=".9" stop-color="red"/>
|
16
|
+
</linearGradient>
|
17
|
+
<linearGradient gradientTransform="translate(5391.8 -3148.45)" gradientUnits="userSpaceOnUse" id="linear-gradient-2" x1="-4854.3" x2="-4254.78" y1="3443.47" y2="3443.47">
|
18
|
+
<stop offset=".06" stop-color="orange" stop-opacity="0"/>
|
19
|
+
<stop offset=".11" stop-color="orange" stop-opacity=".07"/>
|
20
|
+
<stop offset=".19" stop-color="orange" stop-opacity=".26"/>
|
21
|
+
<stop offset=".31" stop-color="orange" stop-opacity=".56"/>
|
22
|
+
<stop offset=".46" stop-color="orange" stop-opacity=".97"/>
|
23
|
+
<stop offset=".47" stop-color="orange"/>
|
24
|
+
<stop offset="1" stop-color="red"/>
|
25
|
+
</linearGradient>
|
26
|
+
<linearGradient gradientTransform="translate(-1037.04 -401.09)" id="linear-gradient-3" x1="1460.82" x2="2060.34" xlink:href="#linear-gradient-2" y1="1006.26" y2="1006.26"/>
|
27
|
+
<linearGradient gradientTransform="translate(-295.18 -2362.64)" gradientUnits="userSpaceOnUse" id="linear-gradient-4" x1="610.99" x2="1210.5" y1="2682.84" y2="2682.84">
|
28
|
+
<stop offset=".09" stop-color="orange" stop-opacity="0"/>
|
29
|
+
<stop offset=".13" stop-color="orange" stop-opacity=".05"/>
|
30
|
+
<stop offset=".21" stop-color="orange" stop-opacity=".19"/>
|
31
|
+
<stop offset=".31" stop-color="orange" stop-opacity=".41"/>
|
32
|
+
<stop offset=".42" stop-color="orange" stop-opacity=".72"/>
|
33
|
+
<stop offset=".52" stop-color="orange"/>
|
34
|
+
<stop offset=".92" stop-color="red"/>
|
35
|
+
</linearGradient>
|
36
|
+
<linearGradient gradientTransform="translate(520.38 -911.81)" gradientUnits="userSpaceOnUse" id="linear-gradient-5" x1="-366.91" x2="258.33" y1="1381.44" y2="1381.44">
|
37
|
+
<stop offset="0" stop-color="#fff" stop-opacity="0"/>
|
38
|
+
<stop offset="1" stop-color="#fff"/>
|
39
|
+
</linearGradient>
|
40
|
+
</defs>
|
41
|
+
<rect class="cls-3" height="138.93" rx="69.47" ry="69.47" transform="translate(1004.69 98.45) rotate(135)" width="599.51" x="182.2" y="187.85"/>
|
42
|
+
<rect class="cls-7" height="138.93" rx="69.47" ry="69.47" transform="translate(1637.84 -88.45) rotate(135)" width="599.51" x="537.48" y="225.52"/>
|
43
|
+
<rect class="cls-5" height="138.93" rx="69.47" ry="69.47" transform="translate(-216.02 688.88) rotate(-45)" width="599.51" x="423.77" y="535.72"/>
|
44
|
+
<rect class="cls-6" height="138.93" rx="69.47" ry="69.47" transform="translate(-46.13 529.06) rotate(-45)" width="599.51" x="315.78" y="250.74"/>
|
45
|
+
</svg>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prawn-svg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.36.
|
4
|
+
version: 0.36.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mog Nesbitt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-01
|
11
|
+
date: 2025-02-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: css_parser
|
@@ -150,12 +150,12 @@ files:
|
|
150
150
|
- lib/prawn/svg/loaders/web.rb
|
151
151
|
- lib/prawn/svg/paint.rb
|
152
152
|
- lib/prawn/svg/pathable.rb
|
153
|
+
- lib/prawn/svg/pdfmatrix.rb
|
153
154
|
- lib/prawn/svg/percentage.rb
|
154
155
|
- lib/prawn/svg/properties.rb
|
155
156
|
- lib/prawn/svg/renderer.rb
|
156
157
|
- lib/prawn/svg/state.rb
|
157
158
|
- lib/prawn/svg/transform_parser.rb
|
158
|
-
- lib/prawn/svg/transform_utils.rb
|
159
159
|
- lib/prawn/svg/ttf.rb
|
160
160
|
- lib/prawn/svg/url_loader.rb
|
161
161
|
- lib/prawn/svg/version.rb
|
@@ -216,6 +216,7 @@ files:
|
|
216
216
|
- spec/sample_svg/ellipse01.svg
|
217
217
|
- spec/sample_svg/gistfile1.svg
|
218
218
|
- spec/sample_svg/google_charts.svg
|
219
|
+
- spec/sample_svg/gradient_offset_transparency.svg
|
219
220
|
- spec/sample_svg/gradient_stress_test.svg
|
220
221
|
- spec/sample_svg/gradient_transform.svg
|
221
222
|
- spec/sample_svg/gradients-cmyk.svg
|
File without changes
|