-
Notifications
You must be signed in to change notification settings - Fork 39
/
Copy pathindex.js
219 lines (167 loc) · 6.24 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/**
The missing SVG.toDataURL library for your SVG elements.
Usage: SVGElement.toDataURL( type, { options } )
Returns: the data URL, except when using native PNG renderer (needs callback).
type MIME type of the exported data.
Default: image/svg+xml.
Must support: image/png.
Additional: image/jpeg.
options is a map of options: {
callback: function(dataURL)
Callback function which is called when the data URL is ready.
This is only necessary when using native PNG renderer.
Default: undefined.
[the rest of the options only apply when type="image/png" or type="image/jpeg"]
renderer: "native"|"canvg"
PNG renderer to use. Native renderer¹ might cause a security exception.
Default: canvg if available, otherwise native.
keepNonSafe: true|false
Export non-safe (image and foreignObject) elements.
This will set the Canvas origin-clean property to false, if this data is transferred to Canvas.
Default: false, to keep origin-clean true.
NOTE: not currently supported and is just ignored.
keepOutsideViewport: true|false
Export all drawn content, even if not visible.
Default: false, export only visible viewport, similar to Canvas toDataURL().
NOTE: only supported with canvg renderer.
}
See original paper¹ for more info on SVG to Canvas exporting.
¹ http://svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back/#svg_to_canvas
*/
module.exports = function toDataURL(_svg, type, options) {
function defaultDebug(s) {
console.log("SVG.toDataURL:", s);
}
var debug = options && options.debug ? options.debug : defaultDebug;
var myCanvg = options && options.canvg ? options.canvg : typeof canvg === 'function' ? canvg : window.canvg;
function exportSVG() {
var svg_xml = XMLSerialize(_svg);
var svg_dataurl = base64dataURLencode(svg_xml);
debug(type + " length: " + svg_dataurl.length);
// NOTE double data carrier
if (options.callback) options.callback(svg_dataurl);
return svg_dataurl;
}
function XMLSerialize(svg) {
// quick-n-serialize an SVG dom, needed for IE9 where there's no XMLSerializer nor SVG.xml
// s: SVG dom, which is the <svg> elemennt
function XMLSerializerForIE(s) {
var out = "";
out += "<" + s.nodeName;
for (var n = 0; n < s.attributes.length; n++) {
out += " " + s.attributes[n].name + "=" + "'" + s.attributes[n].value + "'";
}
if (s.hasChildNodes()) {
out += ">\n";
for (var n = 0; n < s.childNodes.length; n++) {
out += XMLSerializerForIE(s.childNodes[n]);
}
out += "</" + s.nodeName + ">" + "\n";
} else out += " />\n";
return out;
}
if (window.XMLSerializer) {
debug("using standard XMLSerializer.serializeToString")
return (new XMLSerializer()).serializeToString(svg);
} else {
debug("using custom XMLSerializerForIE")
return XMLSerializerForIE(svg);
}
}
function base64dataURLencode(s) {
var b64 = "data:image/svg+xml;base64,";
// https://developer.mozilla.org/en/DOM/window.btoa
if (window.btoa) {
debug("using window.btoa for base64 encoding");
b64 += btoa(s);
} else {
debug("using custom base64 encoder");
b64 += Base64.encode(s);
}
return b64;
}
function exportImage(type) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext('2d');
// TODO: if (options.keepOutsideViewport), do some translation magic?
var svg_img = new Image();
var svg_xml = XMLSerialize(_svg);
svg_img.src = base64dataURLencode(svg_xml);
svg_img.onload = function() {
debug("exported image size: " + [svg_img.width, svg_img.height])
canvas.width = svg_img.width;
canvas.height = svg_img.height;
ctx.drawImage(svg_img, 0, 0);
// SECURITY_ERR WILL HAPPEN NOW
var png_dataurl = canvas.toDataURL(type);
debug(type + " length: " + png_dataurl.length);
if (options.callback) options.callback( png_dataurl );
else debug("WARNING: no callback set, so nothing happens.");
}
svg_img.onerror = function() {
console.log(
"Can't export! Maybe your browser doesn't support " +
"SVG in img element or SVG input for Canvas drawImage?\n" +
"http://en.wikipedia.org/wiki/SVG#Native_support"
);
}
// NOTE: will not return anything
}
function exportImageCanvg(type) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext('2d');
var svg_xml = XMLSerialize(_svg);
// NOTE: canvg gets the SVG element dimensions incorrectly if not specified as attributes
//debug("detected svg dimensions " + [_svg.clientWidth, _svg.clientHeight])
//debug("canvas dimensions " + [canvas.width, canvas.height])
var keepBB = options.keepOutsideViewport;
if (keepBB) var bb = _svg.getBBox();
// NOTE: this canvg call is synchronous and blocks
myCanvg(canvas, svg_xml, {
ignoreMouse: true, ignoreAnimation: true,
offsetX: keepBB ? -bb.x : undefined,
offsetY: keepBB ? -bb.y : undefined,
scaleWidth: keepBB ? bb.width+bb.x : undefined,
scaleHeight: keepBB ? bb.height+bb.y : undefined,
renderCallback: function() {
debug("exported image dimensions " + [canvas.width, canvas.height]);
var png_dataurl = canvas.toDataURL(type);
debug(type + " length: " + png_dataurl.length);
if (options.callback) options.callback( png_dataurl );
}
});
// NOTE: return in addition to callback
return canvas.toDataURL(type);
}
// BEGIN MAIN
if (!type) type = "image/svg+xml";
if (!options) options = {};
if (options.keepNonSafe) debug("NOTE: keepNonSafe is NOT supported and will be ignored!");
if (options.keepOutsideViewport) debug("NOTE: keepOutsideViewport is only supported with canvg exporter.");
switch (type) {
case "image/svg+xml":
return exportSVG();
break;
case "image/png":
case "image/jpeg":
if (!options.renderer) {
if (window.canvg) options.renderer = "canvg";
else options.renderer="native";
}
switch (options.renderer) {
case "canvg":
debug("using canvg renderer for png export");
return exportImageCanvg(type);
break;
case "native":
debug("using native renderer for png export. THIS MIGHT FAIL.");
return exportImage(type);
break;
default:
debug("unknown png renderer given, doing noting (" + options.renderer + ")");
}
break;
default:
debug("Sorry! Exporting as '" + type + "' is not supported!")
}
}