Drawing an svg containing html in a canvas with sa

2019-04-21 02:27发布

问题:

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

回答1:

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);


回答2:

You don't state what you get in console on the Blob nor the URL.

Just a shot but you are revoking the url right after setting it as source on the image. You need to revoke if after the image has been loaded in the onload event:

img.onload = function() {                   
    DOMURL.revokeObjectURL(url);      /// here
    context.drawImage(img, 100, 100);                                       
};

img.src = url;
//DOMURL.revokeObjectURL(url);        /// not here

See that helps out. If not then you're probably dealing with a Safari specific issue. (your canvas specific translate etc. should also be inside the onload event or at least called before you set the src property).