Canvas toDataURL()仅在Firefox中返回空白图像

时间:2014-11-06 15:48:45

标签: javascript firefox canvas webgl todataurl

我正在使用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==

可能导致此结果的原因以及如何解决?

1 个答案:

答案 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: falsepreserveDrawingBuffer,那么如果falsepreserveDrawingBuffer,那么绘图缓冲区会在复合之后被清除(这是另一个异步事件因此是不可预测的)它必须复制,以便保留绘图缓冲区的内容。

请注意,一旦画布具有上下文,它将始终具有相同的上下文。换句话说,让我们假设您更改了初始化WebGL上下文的代码,但您仍想设置true

至少有两种方式。

首先找到画布,然后获取上下文

因为稍后代码将以相同的上下文结束。

preserveDrawingBuffer: true

因为您已经为该画布创建了一个上下文,无论后面的脚本将获得相同的上下文。

augment <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。