[英]Canvas toDataURL() returns blank image
我正在使用glfx.js来编辑我的图像,但是当我尝试使用toDataURL()
函数获取该图像的数据时,我得到了一个空白图像(宽度与原始图像大小相同)。
奇怪的是,在 Chrome 中,脚本运行完美。
我想提到的是,图像是使用 onload 事件加载到canvas
中的:
img.onload = function(){
try {
canvas = fx.canvas();
} catch (e) {
alert(e);
return;
}
// convert the image to a texture
texture = canvas.texture(img);
// draw and update canvas
canvas.draw(texture).update();
// replace the image with the canvas
img.parentNode.insertBefore(canvas, img);
img.parentNode.removeChild(img);
}
我的图像路径也在同一个域中;
问题(在 Firefox 中)是当我点击保存按钮时。 Chrome 返回预期结果,但 Firefox 返回:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA7YAAAIWCAYAAABjkRHCAAAHxklEQVR4nO3BMQEAAADCoPVPbQZ/oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
... [ lots of A s ] ...
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAzwD6aAABkwvPRgAAAABJRU5ErkJggg==
什么可能导致这种结果,我该如何解决?
很可能在您绘制到画布的时间和您调用toDataURL
的时间之间存在一些异步事件。 默认情况下,每次合成后都会清除画布。 通过使用preserveDrawingBuffer: true
创建 WebGL 上下文来防止画布被清除,如
var gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});
或者确保在退出您用来呈现的任何事件之前调用 toDataURL。 例如,如果你这样做
function render() {
drawScene();
requestAnimationFrame(render);
}
render();
在其他地方这样做
someElement.addEventListener('click', function() {
var data = someCanvas.toDataURL();
}, false);
这两个事件、 animation frame
和click
不同步,并且在调用它们之间可能会清除画布。 注意:画布不会显示为已清除,因为它是双缓冲的,但缓冲区 toDataURL 和影响该缓冲区正在查看的其他命令已被清除。
解决方案是使用preserveDrawingBuffer
或在与渲染相同的事件中调用toDataURL
。 例如
var captureFrame = false;
function render() {
drawScene();
if (captureFrame) {
captureFrame = false;
var data = someCanvas.toDataURL();
...
}
requestAnimationFrame(render);
}
render();
someElement.addEventListener('click', function() {
captureFrame = true;
}, false);
默认的preserveDrawingBuffer: false
有什么意义? 它可以明显更快,尤其是在移动设备上,不必保留绘图缓冲区。 另一种看待它的方式是浏览器需要 2 个画布副本。 您正在绘制的那个和它正在显示的那个。 它有两种方法来处理这 2 个缓冲区。 (一)双缓冲。 让您绘制到一个,显示另一个,在您完成渲染后交换缓冲区,这是从退出发出绘制命令的任何事件推断出来的 (B) 复制您正在绘制的缓冲区的内容以执行正在显示的缓冲区. 交换比复制快得多。 因此,交换是默认设置。 实际发生的事情取决于浏览器。 唯一的要求是,如果preserveDrawingBuffer
为false
,则在合成后清除绘图缓冲区(这是另一个异步事件,因此不可预测),如果preserveDrawingBuffer
为true
则它必须复制,以便保留绘图缓冲区的内容。
请注意,一旦画布具有上下文,它将始终具有相同的上下文。 因此,换句话说,假设您更改了初始化 WebGL 上下文的代码,但您仍然希望设置preserveDrawingBuffer: true
至少有2种方式。
因为稍后的代码将以相同的上下文结束。
<script>
document.querySelector('#somecanvasid').getContext(
'webgl', {preserveDrawingBuffer: true});
</script>
<script src="script/that/will/use/somecanvasid.js"></script>
因为您已经为该画布创建了上下文,所以后面的任何脚本都将获得相同的上下文。
getContext
<script>
HTMLCanvasElement.prototype.getContext = function(origFn) {
return function(type, attributes) {
if (type === 'webgl') {
attributes = Object.assign({}, attributes, {
preserveDrawingBuffer: true,
});
}
return origFn.call(this, type, attributes);
};
}(HTMLCanvasElement.prototype.getContext);
</script>
<script src="script/that/will/use/webgl.js"></script>
在这种情况下,在增加getContext
之后创建的任何 webgl 上下文都会将preserveDrawingBuffer
设置为 true。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.