prawn-svg 0.12.0.11 → 0.12.0.12

Sign up to get free protection for your applications and to get access to all the features.
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