您好我有以下问题。
我正在生成SVG图像( https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Drawing_DOM_objects_into_a_canvas )。
图像生成正确,看起来不错。 现在我需要获取数据URI,但每次我尝试从canvas.toDataURL()获取此消息时,此消息显示为未捕获DOMException:无法执行' toDataURL' on' HTMLCanvasElement':可能无法导出受污染的画布。(...)
我已经创建了一些示例代码来说明情况。
</!DOCTYPE html>
<html>
<head>
<title>SVG to PNG</title>
</head>
<body>
<canvas id="canvas" style="border:2px solid black;" width="200" height="200">
</canvas>
<script type="text/javascript">
var canvas = document.getElementById('canvas');
var ctx = 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">' +
'<em>I</em> like ' +
'<span style="color:white; text-shadow:0 0 2px blue;">' +
'beer</span>' +
'</div>' +
'</foreignObject>' +
'</svg>';
var domURL = window.URL || window.webkitURL || window;
var img = new Image();
var svg = new Blob([data], {type: 'image/svg+xml'});
var url = domURL.createObjectURL(svg);
img.onload = function () {
ctx.drawImage(img, 0, 0);
domURL.revokeObjectURL(url);
var dataURL = canvas.toDataURL();
console.log(dataURL);
};
img.src = url;
</script>
</body>
</html>
此代码生成以下图像
这是正确的,但是当这些行被执行时
var dataURL = canvas.toDataURL(); 的console.log(dataURL);
它抛出错误。我在图片 onload 方法中执行此操作,以允许图像完成绘制到画布。如果我尝试从onload方法之外获取dataURL,画布还没有完成加载,所以它会给我一个空图像。 我一直在搜索,但我还没有找到答案。这与CORS有关。我已经安装了chrome插件 CORS 并添加了img,事实是这只是一个例子,基于CORS的解决方案没有用,因为我正在努力一个应用程序在一个残缺的铬浏览器上运行(我的意思是浏览器只显示网络应用程序,除了与应用程序交互之外,你无法做任何事情)。
要注意您可以使用
获取数据URI检查 - &gt; 网络 - &gt; 选择图片并在源面板中打开,只有将图片复制为数据uri 。 我得到了base64图像,如果我使用这样的解码器(http://base64online.org/decode/),它会正确显示图像。 所以问题肯定是我在绘制画布之前获取数据URI。
有什么想法吗?
提前致谢!
此致
莫罗
答案 0 :(得分:3)
这与CORS无关。您没有对外部资源发出任何请求。
问题是绘制svg(而且当它包含html元素时)对浏览器来说是一个非常敏感的操作。
这就是为什么这项技术存在很多限制(你无法加载外部资源,忽略脚本,不能从外部CSS设置内容样式,禁用所有默认浏览器和操作系统样式以避免指纹识别等) )。
我不参加safari或chrome,所以我无法确定,但我认为他们无法在这些点之一上提供足够的安全性(safari在v9中实现了它,它是{{3} })。
他们所做的是,他们污染画布,锁定其任何导出方法。 (注意,出于类似的安全原因,只要有任何svg被绘制到画布上,IE&lt; Edge也会污染画布)。
如果你想要的是光栅化DOM元素,那么你应该解析DOM及其所有应用的样式,并使用画布绘图方法重现它。
这样做,您可以绕过大多数安全问题,并且没有UA会污染画布。有些图书馆正是这样做的,最着名的就是known issue in chrome too。
如果您想要绘制此图像,那么您可以在不使用foreignObject的情况下重写它(svg文本具有比canvas更多的选项),然后使用像html2canvas这样的库在画布上呈现它< sub>(因为否则IE会像前面所说的那样污染画布)。
注意:chrome的问题可以解决,但我不确定这是一个好主意,它仍然无法在Safari中运行,也无法在IE&lt; Edge和chrome也可能忘记阻止它,并且在下一个版本中,无论如何,这里是如何:
var canvas = document.getElementById('c');
var ctx = 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">' +
'<em>I</em> like ' +
'<span style="color:white; text-shadow:0 0 2px blue;">' +
'beer</span>' +
'</div>' +
'</foreignObject>' +
'</svg>';
var img = new Image();
// instead of a blobURL, if we use a dataURL, chrome seems happy...
var url = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(data);
img.onload = function() {
c.width = this.width;
c.height = this.height;
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL();
console.log(dataURL);
};
img.src = url;
<canvas id="c"></canvas>