Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing an svg containing html in a canvas with safari

I'm trying to create some thumbnails of dynamically created pages for a website, i have found a solution by adding the html in a svg which I then draw on an image inside a canvas that I resize after the image has been drawn.

This solution works in firefox and chrome but not in safari, the svg doesn't seem to be drawn I just get a blank page. I don't get any error even if i put some try catch and I couldn't find a solution on the web.

My html is just a basic test page with a canvas, I tried to add a meta tag on the head

<meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8" />

but it didn't work either.

Here's the code I wrote :

var canvas = document.getElementById('canvasTest'),
            context = canvas.getContext('2d');

            var data = "<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'>" +
                 "<foreignObject width='100%' height='100%'>" +
                   "<div xmlns='http://www.w3.org/1999/xhtml' style='font-size:40px'>" +
                     "<div>TEST<span>TEST</span></div>" +
                   "</div>" +
                 "</foreignObject>" +
               "</svg>"
            ;

            var DOMURL = self.URL || self.webkitURL || self;
            var img = new Image();                                                                              

            try {
                var svg = new Blob([data], {type: "image/svg+xml;charset=utf-8"});                      
            } catch(e) {                    
                window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
                console.log(window.BlobBuilder);

                if(e.name == 'TypeError' && window.BlobBuilder){
                    var bb = new BlobBuilder();
                    bb.append(data);
                    var svg = bb.getBlob("image/svg+xml;charset=utf-8");
                } else if(e.name == "InvalidStateError") {                      
                    var svg = new Blob(data, {type : "image/svg+xml;charset=utf-8"});
                } else {

                }
            }               

            var url = DOMURL.createObjectURL(svg);              

            img.onload = function() {                   
                    context.drawImage(img, 100, 100);                                       
            };

            img.src = url;
            DOMURL.revokeObjectURL(url);

            context.translate(canvas.width / 2, canvas.height / 2);
            context.scale(0.4, 0.4);

Safari can use the Blob constructor so it doesn't go in the catch. It seems like the problem is when I pass the svg reference (img.src = url) but i can't figure out what to do differently, if someone has some ideas or solution it would be great.

Edit: console output for safari

Blob: Blob {size=232, type="image/svg+xml;charset=utf-8", webkitSlice}

Url: blob:http://myPage.com/96fb502f-46bb-492b-af35-5313bb39bd31

like image 244
Francois Morier-Genoud Avatar asked Jan 10 '14 16:01

Francois Morier-Genoud


1 Answers

Basically the solution was to put the mime type(data:image/svg+xml) in the variable containing the svg, this way you don't need to use the blob anymore and then to set the img src with the svg before drawing it to the canvas.

var canvas = document.getElementById('canvasTest'),
            context = canvas.getContext('2d');

            var data = "data:image/svg+xml,"+"<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'>" +
                 "<foreignObject width='100%' height='100%'>" +
                   "<div xmlns='http://www.w3.org/1999/xhtml' style='font-size:40px'>" +
                     "<div xmlns='http://www.w3.org/1999/xhtml'>aaaa<span>aaaa</span></div>" +
                   "</div>" +
                 "</foreignObject>" +
               "</svg>"
            ;

            var img = new Image();

            img.src = data;

            img.onload = function() {
                context.drawImage(img, 100, 100);                   
            };

            context.translate(canvas.width / 2, canvas.height / 2);
            context.scale(0.4, 0.4);
like image 124
Francois Morier-Genoud Avatar answered Sep 22 '22 16:09

Francois Morier-Genoud