There might be some character that doesn't pass well into the blob.
(as pointed out by Robert Longson, its actually an FF bug, but there were other issues reported with this method anyway)
The solution, is to replace the [string
to blob
to blobURI
] into [encodedString
to dataURI
] :
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var data = '<svg xmlns="http://www.w3.org/2000/svg" width="223" height="223">' +
'<defs>' +
'<filter id="f1" x="0" y="0">' +
'<feGaussianBlur in="SourceGraphic" stdDeviation="5" />' +
'</filter>' +
'</defs>' +
'<rect class="shape" x="0" y="0" width="100" height="150" transform="translate(40,15) rotate(15,50,75)" fill="#006791" filter="url(#f1)"></rect></svg>';
// first encode the special characters
var svg_data = encodeURIComponent(data);
// create a dataURI version
var url = 'data:image/svg+xml; charset=utf8, ' + svg_data;
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0, 223, 223);
}
img.src = url;
<canvas id="canvas" style="border:2px solid black;" width="223" height="223">
</canvas>
Ps : an even sanitizer solution, but a little bit heavier, is to use a DOMParser, to parse your string, then serialize its results to string with an XMLSerializer, encode this string and finally make this a dataURI :
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var data = '<svg xmlns="http://www.w3.org/2000/svg" width="223" height="223">' +
'<defs>' +
'<filter id="f1" x="0" y="0">' +
'<feGaussianBlur in="SourceGraphic" stdDeviation="5" />' +
'</filter>' +
'</defs>' +
'<rect class="shape" x="0" y="0" width="100" height="150" transform="translate(40,15) rotate(15,50,75)" fill="#006791" filter="url(#f1)"></rect></svg>';
// create a new DOMParser
var parser = new DOMParser();
// Parse our string as an svg document
var doc = parser.parseFromString(data, 'image/svg+xml');
// Serialize the new svg document
var svg_data = new XMLSerializer().serializeToString(doc.documentElement);
// set it to a dataURI
var url = 'data:image/svg+xml; charset=utf8, '+encodeURIComponent(svg_data);
var img = new Image();
img.onload = function () {
ctx.drawImage(img, 0, 0, 223, 223);
}
img.src = url;
<canvas id="canvas" style="border:2px solid black;" width="223" height="223">
</canvas>
Now that you've got a solution, we can try to answer the "What's going on?"
Chrome is buggy in its way to get the external elements referenced with the xlink:href
attribute, or with a <funcIRI>
(url(#xxx)
) inside attributes.
e.g, it doesn't refer to the good URI path if you do such reference inside an external CSS stylesheet, and it isn't able to get the references specified inside an external reference.
See this codepen for more clarity about this :
The ball should be painted with two radialGradient
s, placed inside an external svg document. The radial gradients do themselves reference to a linearGradient
in the same doc.
Firefox does fetch correctly every of the requested elements, when chrome only is able to fetch direct elements (the check-mark).
Firefox :
Chrome : 
When you do use URL.createObjectURL()
, you are creating a new file in the browser's memory, with a special location (its location.origin
will be set to the one of the page where have created it but no pathName
nor host
will be set.).
I didn't gone into FF fetching code, but I guess that they do something in here that will make even inner references wrong when you are inside such a special url scheme and that's what does break in your case.
So yes, here FF is broken, but certainly because of something other browsers don't even try to do...