prawn-svg 0.12.0.11 → 0.12.0.12

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
  SHA1:
3
- metadata.gz: a14b8e4dc51812f13ac2defaf8ea8e1ec09f5183
4
- data.tar.gz: c8fd5023335201e38d03c83921b10c7666321543
3
+ metadata.gz: 9f60ffdf19d946bf97ba8cd7fdf732cdef8f3d6f
4
+ data.tar.gz: 3885db032ea679b2993f359cb4728feaad8a7ccd
5
5
  SHA512:
6
- metadata.gz: bac4b67bd32a2be9f148cffce11e3df1f3b66873281dc5434cfb7f0090493754e126995073d0401a10d60dbb06354e201c739e03e10fb145efbe165033eafe2b
7
- data.tar.gz: 13bf35b240fbf40f4c9d1be3377a6dc87535898fb4f78a98a53473f588a8bf02d69ad3bb636ac331516242021f18bc949e1dd32325056b502eac1c15c0d65d00
6
+ metadata.gz: 65587a6f9fae146ac42583ecf9aebb60671834e92038b2845aaa3c79d7e3e848a47d7526f7cb525cad7b06032b3da500b181966a88bbdc88041a470b80e621e5
7
+ data.tar.gz: d3fe9134e90fce9a027f7e8b5d824006ee92a7e9ca6c8d912e509807db95b8b45783bfa11e86eb6436b99e37b090a5a5c4e13eb8e787bfef0fb32233499ea433
@@ -41,9 +41,8 @@ module Prawn
41
41
  #
42
42
  def draw
43
43
  prawn.bounding_box(@options[:at], :width => @document.width, :height => @document.height) do
44
- clip_rectangle 0, 0, @document.width, @document.height
45
-
46
44
  prawn.save_graphics_state do
45
+ clip_rectangle 0, 0, @document.width, @document.height
47
46
  proc_creator(prawn, Parser.new(@document).parse).call
48
47
  end
49
48
  end
@@ -167,7 +167,85 @@ module Prawn
167
167
  end
168
168
 
169
169
  when 'A'
170
- # unsupported
170
+ return unless @last_point
171
+
172
+ while values.any?
173
+ rx, ry, phi, fa, fs, x2, y2 = (1..7).collect {values.shift}
174
+ x1, y1 = @last_point
175
+
176
+ if relative
177
+ x2 += x1
178
+ y2 += y1
179
+ end
180
+
181
+ rx = rx.abs
182
+ ry = ry.abs
183
+ phi = (phi % 360) * 2 * Math::PI / 360.0
184
+
185
+ # We need to get the center co-ordinates, as well as the angles from the X axis to the start and end
186
+ # points. To do this, we use the algorithm documented in the SVG specification section F.6.5.
187
+
188
+ # F.6.5.1
189
+ xp1 = Math.cos(phi) * ((x1-x2)/2.0) + Math.sin(phi) * ((y1-y2)/2.0)
190
+ yp1 = -Math.sin(phi) * ((x1-x2)/2.0) + Math.cos(phi) * ((y1-y2)/2.0)
191
+
192
+ # F.6.6.2
193
+ r2x = rx * rx
194
+ r2y = ry * ry
195
+ hat = xp1 * xp1 / r2x + yp1 * yp1 / r2y
196
+ if hat > 1
197
+ rx *= Math.sqrt(hat)
198
+ ry *= Math.sqrt(hat)
199
+ end
200
+
201
+ # F.6.5.2
202
+ r2x = rx * rx
203
+ r2y = ry * ry
204
+ square = (r2x * r2y - r2x * yp1 * yp1 - r2y * xp1 * xp1) / (r2x * yp1 * yp1 + r2y * xp1 * xp1)
205
+ square = 0 if square < 0 && square > -1e-10 # catch rounding errors
206
+ base = Math.sqrt(square)
207
+ base *= -1 if fa == fs
208
+ cpx = base * rx * yp1 / ry
209
+ cpy = base * -ry * xp1 / rx
210
+
211
+ # F.6.5.3
212
+ cx = Math.cos(phi) * cpx + -Math.sin(phi) * cpy + (x1 + x2) / 2
213
+ cy = Math.sin(phi) * cpx + Math.cos(phi) * cpy + (y1 + y2) / 2
214
+
215
+ # F.6.5.5
216
+ vx = (xp1 - cpx) / rx
217
+ vy = (yp1 - cpy) / ry
218
+ theta_1 = Math.acos(vx / Math.sqrt(vx * vx + vy * vy))
219
+ theta_1 *= -1 if vy < 0
220
+
221
+ # F.6.5.6
222
+ ux = vx
223
+ uy = vy
224
+ vx = (-xp1 - cpx) / rx
225
+ vy = (-yp1 - cpy) / ry
226
+
227
+ numerator = ux * vx + uy * vy
228
+ denominator = Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy)
229
+ division = numerator / denominator
230
+ division = -1 if division < -1 # for rounding errors
231
+
232
+ d_theta = Math.acos(division) % (2 * Math::PI)
233
+ d_theta *= -1 if ux * vy - uy * vx < 0
234
+
235
+ # Adjust range
236
+ if fs == 0
237
+ d_theta -= 2 * Math::PI if d_theta > 0
238
+ else
239
+ d_theta += 2 * Math::PI if d_theta < 0
240
+ end
241
+
242
+ theta_2 = theta_1 + d_theta
243
+
244
+ calculate_bezier_curve_points_for_arc(cx, cy, rx, ry, theta_1, theta_2, phi).each do |points|
245
+ @calls << ["curve_to", points[:p2] + points[:q1] + points[:q2]]
246
+ @last_point = points[:p2]
247
+ end
248
+ end
171
249
  end
172
250
 
173
251
  @previous_control_point = nil unless %w(C S).include?(upcase_command)
@@ -184,6 +262,113 @@ module Prawn
184
262
  end
185
263
  result
186
264
  end
265
+
266
+ def calculate_eta_from_lambda(a, b, lambda_1, lambda_2)
267
+ # 2.2.1
268
+ eta1 = Math.atan2(Math.sin(lambda_1) / b, Math.cos(lambda_1) / a)
269
+ eta2 = Math.atan2(Math.sin(lambda_2) / b, Math.cos(lambda_2) / a)
270
+
271
+ # ensure eta1 <= eta2 <= eta1 + 2*PI
272
+ eta2 -= 2 * Math::PI * ((eta2 - eta1) / (2 * Math::PI)).floor
273
+ eta2 += 2 * Math::PI if lambda_2 - lambda_1 > Math::PI && eta2 - eta1 < Math::PI
274
+
275
+ [eta1, eta2]
276
+ end
277
+
278
+ # Convert the elliptical arc to a cubic bézier curve using this algorithm:
279
+ # http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf
280
+ def calculate_bezier_curve_points_for_arc(cx, cy, a, b, lambda_1, lambda_2, theta)
281
+ e = lambda do |eta|
282
+ [
283
+ cx + a * Math.cos(theta) * Math.cos(eta) - b * Math.sin(theta) * Math.sin(eta),
284
+ cy + a * Math.sin(theta) * Math.cos(eta) + b * Math.cos(theta) * Math.sin(eta)
285
+ ]
286
+ end
287
+
288
+ ep = lambda do |eta|
289
+ [
290
+ -a * Math.cos(theta) * Math.sin(eta) - b * Math.sin(theta) * Math.cos(eta),
291
+ -a * Math.sin(theta) * Math.sin(eta) + b * Math.cos(theta) * Math.cos(eta)
292
+ ]
293
+ end
294
+
295
+ iterations = 1
296
+ d_lambda = lambda_2 - lambda_1
297
+
298
+ while iterations < 1024
299
+ if d_lambda.abs <= Math::PI / 2.0
300
+ # TODO : run error algorithm, see whether it meets threshold or not
301
+ # puts "error = #{calculate_curve_approximation_error(a, b, eta1, eta1 + d_eta)}"
302
+ break
303
+ end
304
+ iterations *= 2
305
+ d_lambda = (lambda_2 - lambda_1) / iterations
306
+ end
307
+
308
+ (0...iterations).collect do |iteration|
309
+ eta_a, eta_b = calculate_eta_from_lambda(a, b, lambda_1+iteration*d_lambda, lambda_1+(iteration+1)*d_lambda)
310
+ d_eta = eta_b - eta_a
311
+
312
+ alpha = Math.sin(d_eta) * ((Math.sqrt(4 + 3 * Math.tan(d_eta / 2) ** 2) - 1) / 3)
313
+
314
+ x1, y1 = e[eta_a]
315
+ x2, y2 = e[eta_b]
316
+
317
+ ep_eta1_x, ep_eta1_y = ep[eta_a]
318
+ q1_x = x1 + alpha * ep_eta1_x
319
+ q1_y = y1 + alpha * ep_eta1_y
320
+
321
+ ep_eta2_x, ep_eta2_y = ep[eta_b]
322
+ q2_x = x2 - alpha * ep_eta2_x
323
+ q2_y = y2 - alpha * ep_eta2_y
324
+
325
+ {:p2 => [x2, y2], :q1 => [q1_x, q1_y], :q2 => [q2_x, q2_y]}
326
+ end
327
+ end
328
+
329
+ ERROR_COEFFICIENTS_A = [
330
+ [
331
+ [3.85268, -21.229, -0.330434, 0.0127842],
332
+ [-1.61486, 0.706564, 0.225945, 0.263682],
333
+ [-0.910164, 0.388383, 0.00551445, 0.00671814],
334
+ [-0.630184, 0.192402, 0.0098871, 0.0102527]
335
+ ],
336
+ [
337
+ [-0.162211, 9.94329, 0.13723, 0.0124084],
338
+ [-0.253135, 0.00187735, 0.0230286, 0.01264],
339
+ [-0.0695069, -0.0437594, 0.0120636, 0.0163087],
340
+ [-0.0328856, -0.00926032, -0.00173573, 0.00527385]
341
+ ]
342
+ ]
343
+
344
+ ERROR_COEFFICIENTS_B = [
345
+ [
346
+ [0.0899116, -19.2349, -4.11711, 0.183362],
347
+ [0.138148, -1.45804, 1.32044, 1.38474],
348
+ [0.230903, -0.450262, 0.219963, 0.414038],
349
+ [0.0590565, -0.101062, 0.0430592, 0.0204699]
350
+ ],
351
+ [
352
+ [0.0164649, 9.89394, 0.0919496, 0.00760802],
353
+ [0.0191603, -0.0322058, 0.0134667, -0.0825018],
354
+ [0.0156192, -0.017535, 0.00326508, -0.228157],
355
+ [-0.0236752, 0.0405821, -0.0173086, 0.176187]
356
+ ]
357
+ ]
358
+
359
+ def calculate_curve_approximation_error(a, b, eta1, eta2)
360
+ b_over_a = b / a
361
+ coefficents = b_over_a < 0.25 ? ERROR_COEFFICIENTS_A : ERROR_COEFFICIENTS_B
362
+
363
+ c = lambda do |i|
364
+ (0..3).inject(0) do |accumulator, j|
365
+ coef = coefficents[i][j]
366
+ accumulator + ((coef[0] * b_over_a**2 + coef[1] * b_over_a + coef[2]) / (b_over_a * coef[3])) * Math.cos(j * (eta1 + eta2))
367
+ end
368
+ end
369
+
370
+ ((0.001 * b_over_a**2 + 4.98 * b_over_a + 0.207) / (b_over_a * 0.0067)) * a * Math.exp(c[0] + c[1] * (eta2 - eta1))
371
+ end
187
372
  end
188
373
  end
189
374
  end
@@ -1,5 +1,5 @@
1
1
  module Prawn
2
2
  module Svg
3
- VERSION = '0.12.0.11'
3
+ VERSION = '0.12.0.12'
4
4
  end
5
5
  end
data/spec/lib/svg_spec.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Prawn::Svg::Interface do
4
+ root = "#{File.dirname(__FILE__)}/../.."
5
+
4
6
  describe "sample file rendering" do
5
- root = "#{File.dirname(__FILE__)}/../.."
6
7
  files = Dir["#{root}/spec/sample_svg/*.svg"]
7
8
 
8
9
  it "has at least 10 SVG sample files to test" do
@@ -20,4 +21,27 @@ describe Prawn::Svg::Interface do
20
21
  end
21
22
  end
22
23
  end
24
+
25
+ describe "multiple file rendering" do
26
+ it "renders multiple files on to the same PDF" do
27
+ Prawn::Document.generate("#{root}/spec/sample_output/multiple.pdf") do |prawn|
28
+ width = prawn.bounds.width
29
+
30
+ y = prawn.bounds.top - 12
31
+ prawn.draw_text "This is multiple SVGs being output to the same PDF", :at => [0, y]
32
+
33
+ y -= 12
34
+ prawn.svg IO.read("#{root}/spec/sample_svg/arcs01.svg"), :at => [0, y], :width => width / 2
35
+ prawn.svg IO.read("#{root}/spec/sample_svg/circle01.svg"), :at => [width / 2, y], :width => width / 2
36
+
37
+ y -= 120
38
+ prawn.draw_text "Here are some more PDFs below", :at => [0, y]
39
+
40
+ y -= 12
41
+ prawn.svg IO.read("#{root}/spec/sample_svg/quad01.svg"), :at => [0, y], :width => width / 3
42
+ prawn.svg IO.read("#{root}/spec/sample_svg/rect01.svg"), :at => [width / 3, y], :width => width / 3
43
+ prawn.svg IO.read("#{root}/spec/sample_svg/rect02.svg"), :at => [width / 3 * 2, y], :width => width / 3
44
+ end
45
+ end
46
+ end
23
47
  end
@@ -8,10 +8,12 @@
8
8
  a picture of a line with arc blips</desc>
9
9
  <rect x="1" y="1" width="1198" height="398"
10
10
  fill="none" stroke="blue" stroke-width="1" />
11
+
11
12
  <path d="M300,200 h-150 a150,150 0 1,0 150,-150 z"
12
13
  fill="red" stroke="blue" stroke-width="5" />
13
14
  <path d="M275,175 v-150 a150,150 0 0,0 -150,150 z"
14
15
  fill="yellow" stroke="blue" stroke-width="5" />
16
+
15
17
  <path d="M600,350 l 50,-25
16
18
  a25,25 -30 0,1 50,-25 l 50,-25
17
19
  a25,50 -30 0,1 50,-25 l 50,-25
@@ -0,0 +1,52 @@
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 xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" width="700" height="700">
4
+ <desc>Created with Highcharts 3.0.7</desc>
5
+ <defs>
6
+ <clipPath id="highcharts-1">
7
+ <rect fill="none" x="0" y="0" width="680" height="675"/>
8
+ </clipPath>
9
+ </defs>
10
+ <rect rx="5" ry="5" fill="#FFFFFF" x="0" y="0" width="700" height="700"/>
11
+ <g class="highcharts-series-group" zIndex="3">
12
+ <g class="highcharts-series highcharts-tracker" visibility="visible" zIndex="0.1" transform="translate(10,10) scale(1 1)" style="cursor:pointer;">
13
+ <path fill="none" d="M 398.21842343360134 47.01407539537521 C 393.21842343360134 47.01407539537521 391.6876463101181 54.86625479973296 389.5828277653285 65.66300148072486 L 387.47800922053887 76.45974816171676" stroke="#DF000D" stroke-width="1" visibility="visible"/>
14
+ <path fill="none" d="M 402.2770459083969 592.163288554881 C 397.2770459083969 592.163288554881 395.62952638563803 584.3347714908305 393.3641870418453 573.570560527761 L 391.09884769805257 562.8063495646916" stroke="#df424c" stroke-width="1" visibility="visible"/>
15
+ <path fill="none" d="M 226.7036279754776 63.82542782054614 C 231.7036279754776 63.82542782054614 234.81866968764356 71.19404472817988 239.10185204187187 81.32589297617625 L 243.38503439610017 91.45774122417262" stroke="#df878c" stroke-width="1" visibility="visible"/>
16
+ <path fill="#DF000D" d="M 339.94946358633314 71.87500514645669 A 248.125 248.125 0 0 1 432.9087444368945 89.92614048493073 L 405.3871617019353 158.07900164103185 A 174.625 174.625 0 0 0 339.96443356680476 145.37500362196474 Z" stroke="#FFFFFF" stroke-width="1" stroke-linejoin="round" transform="translate(0,0)"/>
17
+ <path fill="#df424c" d="M 433.13877180369553 90.01916425080302 A 248.125 248.125 0 1 1 161.76607819326867 147.3770445670913 L 214.56282681914172 198.51170340565568 A 174.625 174.625 0 1 0 405.5490499797293 158.14446975232838 Z" stroke="#FFFFFF" stroke-width="1" stroke-linejoin="round" transform="translate(0,0)"/>
18
+ <path fill="#df878c" d="M 161.93879023688453 147.19889698646077 A 248.125 248.125 0 0 1 339.65535935286596 71.87523934958779 L 339.7574493783142 145.375168449055 A 174.625 174.625 0 0 0 214.68437781406936 198.3863269975243 Z" stroke="#FFFFFF" stroke-width="1" stroke-linejoin="round" transform="translate(0,0)"/>
19
+ </g>
20
+ <g class="highcharts-markers" visibility="visible" zIndex="0.1" transform="translate(10,10) scale(1 1)"/>
21
+ </g>
22
+ <g class="highcharts-data-labels highcharts-tracker" visibility="visible" zIndex="6" transform="translate(10,10) scale(1 1)" style="cursor:pointer;">
23
+ <g zIndex="1" style="cursor:pointer;" transform="translate(403,37)" visibility="visible">
24
+ <text x="3" y="26" style="font-family:&quot;Open Sans&quot;, Verdana, Arial, Helvetica, sans-serif;font-size:24px;color:#000000;line-height:14px;fill:#000000;" zIndex="1">
25
+ <tspan x="3">Mobili&#xE8;re</tspan>
26
+ </text>
27
+ </g>
28
+ <g zIndex="1" style="cursor:pointer;" transform="translate(407,582)" visibility="visible">
29
+ <text x="3" y="26" style="font-family:&quot;Open Sans&quot;, Verdana, Arial, Helvetica, sans-serif;font-size:24px;color:#000000;line-height:14px;fill:#000000;" zIndex="1">
30
+ <tspan x="3">B&#xE2;loise</tspan>
31
+ </text>
32
+ </g>
33
+ <g zIndex="1" style="cursor:pointer;" transform="translate(130,54)" visibility="visible">
34
+ <text x="3" y="26" style="font-family:&quot;Open Sans&quot;, Verdana, Arial, Helvetica, sans-serif;font-size:24px;color:#000000;line-height:14px;fill:#000000;" zIndex="1">
35
+ <tspan x="3">Generali</tspan>
36
+ </text>
37
+ </g>
38
+ </g>
39
+ <g class="highcharts-legend" zIndex="7">
40
+ <rect rx="5" ry="5" fill="none" x="0.5" y="0.5" width="7" height="7" stroke="#909090" stroke-width="1" visibility="hidden"/>
41
+ <g zIndex="1">
42
+ <g/>
43
+ </g>
44
+ </g>
45
+ <g class="highcharts-tooltip" zIndex="8" style="cursor:default;padding:0;white-space:nowrap;" transform="translate(0,-999)">
46
+ <rect rx="3" ry="3" fill="none" x="0.5" y="0.5" width="16" height="16" fill-opacity="0.85" isShadow="true" stroke="black" stroke-width="5" transform="translate(1, 1)" opacity="0.049999999999999996"/>
47
+ <rect rx="3" ry="3" fill="none" x="0.5" y="0.5" width="16" height="16" fill-opacity="0.85" isShadow="true" stroke="black" stroke-width="3" transform="translate(1, 1)" opacity="0.09999999999999999"/>
48
+ <rect rx="3" ry="3" fill="none" x="0.5" y="0.5" width="16" height="16" fill-opacity="0.85" isShadow="true" stroke="black" stroke-width="1" transform="translate(1, 1)" opacity="0.15"/>
49
+ <rect rx="3" ry="3" fill="rgb(255,255,255)" x="0.5" y="0.5" width="16" height="16" fill-opacity="0.85"/>
50
+ <text x="8" y="21" style="font-family:&quot;Lucida Grande&quot;, &quot;Lucida Sans Unicode&quot;, Verdana, Arial, Helvetica, sans-serif;font-size:12px;color:#333333;fill:#333333;" zIndex="1"/>
51
+ </g>
52
+ </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.12.0.11
4
+ version: 0.12.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roger Nesbitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-08 00:00:00.000000000 Z
11
+ date: 2013-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prawn
@@ -95,6 +95,7 @@ files:
95
95
  - spec/sample_svg/cubic02.svg
96
96
  - spec/sample_svg/ellipse01.svg
97
97
  - spec/sample_svg/google_charts.svg
98
+ - spec/sample_svg/highcharts.svg
98
99
  - spec/sample_svg/image01.svg
99
100
  - spec/sample_svg/image02_base64.svg
100
101
  - spec/sample_svg/line01.svg
@@ -140,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
141
  version: '0'
141
142
  requirements: []
142
143
  rubyforge_project:
143
- rubygems_version: 2.0.14
144
+ rubygems_version: 2.1.11
144
145
  signing_key:
145
146
  specification_version: 4
146
147
  summary: SVG renderer for Prawn PDF library
@@ -163,6 +164,7 @@ test_files:
163
164
  - spec/sample_svg/cubic02.svg
164
165
  - spec/sample_svg/ellipse01.svg
165
166
  - spec/sample_svg/google_charts.svg
167
+ - spec/sample_svg/highcharts.svg
166
168
  - spec/sample_svg/image01.svg
167
169
  - spec/sample_svg/image02_base64.svg
168
170
  - spec/sample_svg/line01.svg