在Safari中使用画布绘制包含HTML的SVG。

10

我正在尝试为网站创建一些动态页面的缩略图,我找到了一个解决方案,通过将HTML添加到SVG中,然后在画布内绘制图像,之后调整画布大小。

这个解决方案在Firefox和Chrome中有效,但在Safari中却不行,SVG似乎没有被绘制出来,我只得到一个空白页面。即使我加了一些try-catch也没有报错,我在网上也找不到解决方案。

我的HTML只是一个带有画布的基本测试页面,我尝试在头部添加了一个meta标签。

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

但它也没有起作用。

这是我编写的代码:

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可以使用Blob构造函数,因此不会进入catch块。问题似乎出在我传递svg引用时(img.src = url),但我无法想到其他什么方法,如果有人有一些想法或解决方案,那就太好了。

编辑:Safari的控制台输出

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

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


你可以在之后使用 .toDataURL() 吗?或者在 Safari 上会遇到安全错误吗? - Maen
2个回答

13
基本上的解决方案是将mime类型(data:image/svg+xml)放入包含SVG的变量中,这样就不需要再使用Blob了,然后在将其绘制到画布之前,使用SVG设置img src。
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);

1
太厉害了!感谢您提供超级简单的示例。我有一些代码在Chrome和FF中可以工作,但在Safari中无法正常运行。它使用window.URL对象创建一个blob,然后将blob绘制到画布上。您在这里提供的示例更简单,并且可以在Safari以及我需要支持的其他浏览器中正常工作。谢谢! - frosty
2
你可能想说 var data = "data:image/svg+xml;utf8," + encodeURIComponent(svgElementCode); 以便使用 utf-8 并获得更好的浏览器支持。点击这里 - amergin

1
你没有说明在Blob或URL上控制台输出的内容。
只是一个猜测,但你在将URL设置为图像源后立即撤销了它。你需要在图像在onload事件中加载之后撤销。
img.onload = function() {                   
    DOMURL.revokeObjectURL(url);      /// here
    context.drawImage(img, 100, 100);                                       
};

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

如果有帮助,那就太好了。如果没有,那么你可能在处理 Safari 特定的问题。 (你特定于画布的翻译等应该也在 onload 事件内部,或者至少在设置 src 属性之前被调用)。

谢谢你的回答。我尝试了你提供的解决方案,但在Safari上仍然得到一个空白页面。我编辑了我的问题,加入了blob和url的控制台输出,请问你还有什么更好的想法吗? - Francois Morier-Genoud
我终于找到了一个适用于ff chrome和safari的解决方案,稍后我会发布它。感谢您的答案,我为您的帮助点赞。 - Francois Morier-Genoud

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接