我正在使用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==
可能导致此结果的原因以及如何解决?
答案 0 :(得分:21)
在您绘制到画布的时间和调用toDataURL
的时间之间,很可能会出现一些异步事件。默认情况下,画布在每个复合后清除。通过使用{/ 1}}创建WebGL上下文来阻止画布被清除,如
preserveDrawingBuffer: true
或确保在退出您用于渲染的任何事件之前调用DataURL。例如,如果你这样做
var gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});
其他地方也这样做
function render() {
drawScene();
requestAnimationFrame(render);
}
render();
这两个事件someElement.addEventListener('click', function() {
var data = someCanvas.toDataURL();
}, false);
和animation frame
不同步,并且可以在调用之间清除画布。注意:画布不会被清除,因为它被双重缓冲,但缓冲区toDataURL和其他影响该缓冲区的命令被清除。
解决方案是使用click
或在与渲染相同的事件内调用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);
的默认点是什么?它可以明显更快,特别是在移动设备上,不必保留绘图缓冲区。另一种看待它的方法是浏览器需要2个画布副本。您正在绘制的那个以及它正在显示的那个。它有两种方法来处理这两个缓冲区。 (A)双缓冲。让你绘制一个,显示另一个,当你完成渲染时交换缓冲区,这是从退出任何发出绘制命令的事件推断出来的。(B)复制你要绘制的缓冲区的内容来做正在显示的缓冲区。交换比复制快得多。因此,交换是默认值。它取决于浏览器实际发生的事情。唯一的要求是,如果preserveDrawingBuffer: false
为preserveDrawingBuffer
,那么如果false
为preserveDrawingBuffer
,那么绘图缓冲区会在复合之后被清除(这是另一个异步事件因此是不可预测的)它必须复制,以便保留绘图缓冲区的内容。
请注意,一旦画布具有上下文,它将始终具有相同的上下文。换句话说,让我们假设您更改了初始化WebGL上下文的代码,但您仍想设置true
至少有两种方式。
因为稍后代码将以相同的上下文结束。
preserveDrawingBuffer: true
因为您已经为该画布创建了一个上下文,无论后面的脚本将获得相同的上下文。
<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>
之后创建的任何webgl上下文都会将getContext
设置为true。