Skip to content

Commit f93b771

Browse files
author
Daniel Dotsenko
committed
Adding Silly SVG Renderer plugin
1 parent 1d76396 commit f93b771

5 files changed

Lines changed: 368 additions & 0 deletions

File tree

jspdf.plugin.sillysvgrenderer.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/** ====================================================================
2+
* jsPDF Silly SVG plugin
3+
* Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining
6+
* a copy of this software and associated documentation files (the
7+
* "Software"), to deal in the Software without restriction, including
8+
* without limitation the rights to use, copy, modify, merge, publish,
9+
* distribute, sublicense, and/or sell copies of the Software, and to
10+
* permit persons to whom the Software is furnished to do so, subject to
11+
* the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be
14+
* included in all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
* ====================================================================
24+
*/
25+
26+
;(function(jsPDFAPI) {
27+
'use strict'
28+
29+
/**
30+
Parses SVG XML and converts only some of the SVG elements into
31+
PDF elements.
32+
33+
Supports:
34+
paths
35+
36+
@public
37+
@function
38+
@param
39+
@returns {Type}
40+
*/
41+
jsPDFAPI.addSVG = function(svgtext, x, y, w, h) {
42+
// 'this' is _jsPDF object returned when jsPDF is inited (new jsPDF())
43+
44+
function InjectCSS(cssbody, document) {
45+
var styletag = document.createElement('style')
46+
styletag.type = 'text/css'
47+
if (styletag.styleSheet) {
48+
// ie
49+
styletag.styleSheet.cssText = cssbody
50+
} else {
51+
// others
52+
styletag.appendChild(document.createTextNode(cssbody))
53+
}
54+
document.getElementsByTagName("head")[0].appendChild(styletag)
55+
}
56+
57+
function createWorkerNode(document){
58+
59+
var frameID = 'childframe' // Date.now().toString() + '_' + (Math.random() * 100).toString()
60+
, frame = document.createElement('iframe')
61+
62+
InjectCSS(
63+
'.jsPDF_sillysvg_iframe {display:none;position:absolute;}'
64+
, document
65+
)
66+
67+
frame.name = frameID
68+
frame.setAttribute("width", 0)
69+
frame.setAttribute("height", 0)
70+
frame.setAttribute("frameborder", "0")
71+
frame.setAttribute("scrolling", "no")
72+
frame.setAttribute("seamless", "seamless")
73+
frame.setAttribute("class", "jsPDF_sillysvg_iframe")
74+
75+
document.body.appendChild(frame)
76+
77+
return frame
78+
}
79+
80+
function attachSVGToWorkerNode(svgtext, frame){
81+
var framedoc = ( frame.contentWindow || frame.contentDocument ).document
82+
framedoc.write(svgtext)
83+
framedoc.close()
84+
return framedoc.getElementsByTagName('svg')[0]
85+
}
86+
87+
function convertPathToPDFLinesArgs(path){
88+
// we will use 'lines' method call. it needs:
89+
// - starting coordinate pair
90+
// - array of arrays of vector shifts (2-len for line, 6 len for bezier)
91+
// - scale array [horizontal, vertical] ratios
92+
// - style (stroke, fill, both)
93+
94+
var start = [ parseFloat(path[1]), parseFloat(path[2]) ] // 'm', 'x#', 'y#'
95+
, vectors = []
96+
, position = 3
97+
, len = path.length
98+
99+
while (position < len){
100+
if (path[position] === 'c'){
101+
vectors.push([
102+
parseFloat(path[position + 1])
103+
, parseFloat(path[position + 2])
104+
, parseFloat(path[position + 3])
105+
, parseFloat(path[position + 4])
106+
, parseFloat(path[position + 5])
107+
, parseFloat(path[position + 6])
108+
])
109+
position += 7
110+
} else if (path[position] === 'l') {
111+
vectors.push([
112+
parseFloat(path[position + 1])
113+
, parseFloat(path[position + 2])
114+
])
115+
position += 3
116+
} else {
117+
position += 1
118+
}
119+
}
120+
return [start[0], start[1], vectors]
121+
}
122+
123+
var workernode = createWorkerNode(document)
124+
, svgnode = attachSVGToWorkerNode(svgtext, workernode)
125+
126+
var i, l, tmp, items = svgnode.childNodes
127+
for (i = 0, l = items.length; i < l; i++) {
128+
tmp = items[i]
129+
if (tmp.tagName && tmp.tagName.toUpperCase() === 'PATH') {
130+
tmp = convertPathToPDFLinesArgs( tmp.getAttribute("d").split(' ') )
131+
this.lines.apply(this, tmp)
132+
}
133+
}
134+
135+
// clean up
136+
workernode.parentNode.removeChild(workernode)
137+
138+
return this
139+
}
140+
141+
})(jsPDF.API)

test/013_sillysvgrenderer.svg

Lines changed: 1 addition & 0 deletions
Loading

test/013_sillysvgrenderer.txt

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
%PDF-1.3
2+
3 0 obj
3+
<</Type /Page
4+
/Parent 1 0 R
5+
/Resources 2 0 R
6+
/Contents 4 0 R>>
7+
endobj
8+
4 0 obj
9+
<</Length 2949>>
10+
stream
11+
0.57 w
12+
0 G
13+
82.205 810.709 m
14+
82.205 809.065 80.107 746.476 82.205 717.166 c
15+
82.800 708.747 88.554 700.271 90.709 691.654 c
16+
92.324 685.247 91.786 677.991 93.543 671.811 c
17+
95.443 665.150 100.176 658.772 102.047 651.969 c
18+
105.789 638.306 108.624 623.537 110.551 609.449 c
19+
111.430 602.986 109.729 596.126 110.551 589.607 c
20+
112.564 573.562 117.298 557.915 119.055 541.418 c
21+
123.052 504.029 127.559 430.866 127.559 430.866 c
22+
S
23+
2.835 697.323 m
24+
3.090 697.380 12.586 698.570 17.008 700.158 c
25+
25.569 703.219 34.072 707.131 42.520 711.496 c
26+
62.079 721.616 79.342 735.279 99.213 742.677 c
27+
152.050 762.321 207.723 777.260 263.622 793.701 c
28+
273.005 796.451 291.969 799.370 291.969 799.370 c
29+
S
30+
286.299 518.740 m
31+
286.809 519.392 304.101 544.621 314.646 555.591 c
32+
327.430 568.885 343.701 579.685 357.165 592.441 c
33+
361.502 596.551 364.252 602.788 368.504 606.614 c
34+
373.294 610.923 381.912 613.843 385.512 617.953 c
35+
387.581 620.306 389.395 627.534 388.346 629.292 c
36+
387.298 631.049 380.778 631.956 377.008 632.126 c
37+
359.631 632.892 338.003 634.989 323.150 632.126 c
38+
316.431 630.822 307.956 623.452 303.307 617.953 c
39+
298.460 612.227 294.831 603.128 291.969 595.276 c
40+
287.320 582.492 281.650 568.715 280.630 555.591 c
41+
278.022 522.227 276.775 478.885 280.630 450.709 c
42+
281.594 443.679 291.146 434.636 297.638 430.866 c
43+
307.219 425.310 322.299 420.435 334.488 419.528 c
44+
370.290 416.835 447.874 419.528 447.874 419.528 c
45+
S
46+
643.465 694.488 m
47+
643.068 694.488 627.364 696.133 620.787 694.488 c
48+
613.446 692.646 603.128 688.649 598.110 683.150 c
49+
585.184 669.005 572.513 647.320 561.260 629.292 c
50+
558.624 625.068 555.846 619.796 555.591 615.118 c
51+
554.088 586.375 550.205 542.070 555.591 521.575 c
52+
557.405 514.630 574.243 509.641 583.937 507.402 c
53+
609.307 501.562 638.419 500.259 666.142 496.063 c
54+
670.054 495.468 674.107 494.731 677.480 493.229 c
55+
682.271 491.103 689.102 488.126 691.654 484.725 c
56+
693.893 481.748 694.346 475.285 694.488 470.551 c
57+
695.282 445.465 695.254 419.386 694.488 394.016 c
58+
694.318 388.290 693.893 380.580 691.654 377.008 c
59+
690.009 374.372 683.631 373.748 680.315 371.339 c
60+
660.472 354.331 l
61+
S
62+
796.535 839.055 m
63+
796.535 836.759 798.208 752.939 796.535 708.662 c
64+
795.317 676.772 792.028 646.470 788.031 615.118 c
65+
786.302 601.569 780.038 588.671 779.528 575.433 c
66+
777.260 518.088 775.332 432.624 779.528 399.685 c
67+
780.066 395.405 794.523 397.077 802.205 396.851 c
68+
826.016 396.142 854.844 390.926 873.071 396.851 c
69+
887.556 401.556 901.162 422.731 915.591 433.701 c
70+
920.466 437.414 928.148 438.860 932.598 442.205 c
71+
938.268 450.709 l
72+
S
73+
685.984 549.921 m
74+
685.984 550.262 683.433 564.917 685.984 569.764 c
75+
692.447 582.095 705.373 598.025 717.165 609.449 c
76+
735.052 626.769 756.170 642.898 776.693 657.638 c
77+
786.217 664.470 798.520 667.956 807.874 674.646 c
78+
817.937 681.818 826.243 692.816 836.220 700.158 c
79+
843.846 705.770 853.739 709.002 861.732 714.331 c
80+
867.798 718.384 872.589 725.273 878.740 728.504 c
81+
889.682 734.259 915.591 742.677 915.591 742.677 c
82+
S
83+
endstream
84+
endobj
85+
1 0 obj
86+
<</Type /Pages
87+
/Kids [3 0 R ]
88+
/Count 1
89+
/MediaBox [0 0 595.28 841.89]
90+
>>
91+
endobj
92+
5 0 obj
93+
<</BaseFont/Helvetica/Type/Font
94+
/Subtype/Type1>>
95+
endobj
96+
6 0 obj
97+
<</BaseFont/Helvetica-Bold/Type/Font
98+
/Subtype/Type1>>
99+
endobj
100+
7 0 obj
101+
<</BaseFont/Helvetica-Oblique/Type/Font
102+
/Subtype/Type1>>
103+
endobj
104+
8 0 obj
105+
<</BaseFont/Helvetica-BoldOblique/Type/Font
106+
/Subtype/Type1>>
107+
endobj
108+
9 0 obj
109+
<</BaseFont/Courier/Type/Font
110+
/Subtype/Type1>>
111+
endobj
112+
10 0 obj
113+
<</BaseFont/Courier-Bold/Type/Font
114+
/Subtype/Type1>>
115+
endobj
116+
11 0 obj
117+
<</BaseFont/Courier-Oblique/Type/Font
118+
/Subtype/Type1>>
119+
endobj
120+
12 0 obj
121+
<</BaseFont/Courier-BoldOblique/Type/Font
122+
/Subtype/Type1>>
123+
endobj
124+
13 0 obj
125+
<</BaseFont/Times-Roman/Type/Font
126+
/Subtype/Type1>>
127+
endobj
128+
14 0 obj
129+
<</BaseFont/Times-Bold/Type/Font
130+
/Subtype/Type1>>
131+
endobj
132+
15 0 obj
133+
<</BaseFont/Times-Italic/Type/Font
134+
/Subtype/Type1>>
135+
endobj
136+
16 0 obj
137+
<</BaseFont/Times-BoldItalic/Type/Font
138+
/Subtype/Type1>>
139+
endobj
140+
2 0 obj
141+
<<
142+
/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
143+
/Font <<
144+
/F1 5 0 R
145+
/F2 6 0 R
146+
/F3 7 0 R
147+
/F4 8 0 R
148+
/F5 9 0 R
149+
/F6 10 0 R
150+
/F7 11 0 R
151+
/F8 12 0 R
152+
/F9 13 0 R
153+
/F10 14 0 R
154+
/F11 15 0 R
155+
/F12 16 0 R
156+
>>
157+
/XObject <<
158+
>>
159+
>>
160+
endobj
161+
17 0 obj
162+
<<
163+
/Producer (jsPDF 20120220)
164+
/CreationDate (D:20120616151911)
165+
>>
166+
endobj
167+
18 0 obj
168+
<<
169+
/Type /Catalog
170+
/Pages 1 0 R
171+
/OpenAction [3 0 R /FitH null]
172+
/PageLayout /OneColumn
173+
>>
174+
endobj
175+
xref
176+
0 19
177+
0000000000 65535 f
178+
0000003086 00000 n
179+
0000004003 00000 n
180+
0000000009 00000 n
181+
0000000087 00000 n
182+
0000003173 00000 n
183+
0000003237 00000 n
184+
0000003306 00000 n
185+
0000003378 00000 n
186+
0000003454 00000 n
187+
0000003516 00000 n
188+
0000003584 00000 n
189+
0000003655 00000 n
190+
0000003730 00000 n
191+
0000003797 00000 n
192+
0000003863 00000 n
193+
0000003931 00000 n
194+
0000004227 00000 n
195+
0000004309 00000 n
196+
trailer
197+
<<
198+
/Size 19
199+
/Root 18 0 R
200+
/Info 17 0 R
201+
>>
202+
startxref
203+
4413
204+
%%EOF

test/pdf_generate_tests.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,27 @@ for (var filename in testinventory){
274274
}
275275
}
276276

277+
asyncTest('013_sillysvgrenderer', function() {
278+
//QUnit.stop()
279+
require(['text!013_sillysvgrenderer.svg', 'text!013_sillysvgrenderer.txt'])
280+
.then(function(svgtext, expectedtext){
281+
QUnit.expect(1)
282+
283+
var pdf = jsPDF()
284+
285+
pdf.addSVG(svgtext)
286+
287+
//pdf.output('dataurl')
288+
289+
QUnit.equal(
290+
removeMinorDiffs( pdf.output() )
291+
, removeMinorDiffs( expectedtext )
292+
)
293+
QUnit.start()
294+
//stop()
295+
})
296+
})
297+
277298
// handcrafted tests
278299
asyncTest('014_addImage', function() {
279300

test/test.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ <h2 id="qunit-userAgent"></h2>
1212
<div id="qunit-fixture">test markup, will be hidden</div>
1313

1414
<script src="../jspdf.js"></script>
15+
<script src="../jspdf.plugin.sillysvgrenderer.js"></script>
1516
<script src="../jspdf.plugin.addimage.js"></script>
1617

1718
<script src="../examples/js/jquery/jquery-1.7.1.min.js"></script>

0 commit comments

Comments
 (0)