Canvas toDataURL() 返回空白图像 [英] Canvas toDataURL() returns blank image

查看:55
本文介绍了Canvas toDataURL() 返回空白图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 glfx.js 来编辑我的图像,但是当我尝试获取该图像的数据时使用 toDataURL() 函数我得到一个空白图像(宽度与原始图像大小相同).

I'm using glfx.js to edit my image but when I'm trying to get that image's data using the toDataURL() function I get a blank image (width the same size as the original image).

奇怪的是,在 Chrome 中,脚本运行完美.

The strange thing is that in Chrome the script works perfect.

我想说的是使用 onload 事件在 canvas 中加载图像:

What I want to mention is that the image is loaded in canvas using the onload event:

           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);

            }

我的图片路径也在同一个域中;

Also my image's path is on the same domain;

问题(在 Firefox 中)是当我点击保存按钮时.Chrome 返回预期结果,但 Firefox 返回:

The problem (in Firefox) is when i hit the save button. Chrome returns the expected result but Firefox return this:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA7YAAAIWCAYAAABjkRHCAAAHxklEQVR4nO3BMQEAAADCoPVPbQZ/oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
... [ lots of A s ] ... 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAzwD6aAABkwvPRgAAAABJRU5ErkJggg==

什么可能导致这种结果,我该如何解决?

What could cause this result and how can I fix it?

推荐答案

很可能在您绘制到画布的时间和您调用 toDataURL 的时间之间存在一些异步事件.默认情况下,每次合成后都会清除画布.通过使用 preserveDrawingBuffer: true 创建 WebGL 上下文来防止画布被清除,如

Most likely there's some async event between the time you draw to the canvas and the time you call toDataURL. By default the canvas is cleared after every composite. Either prevent the canvas from being cleared by creating the WebGL context with preserveDrawingBuffer: true as in

var gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});

或者确保在退出您用来呈现的任何事件之前调用了 toDataURL.例如,如果你这样做

or make sure toDataURL is called before exiting whatever event you're using to render. For example if you do this

function render() {
  drawScene(); 
  requestAnimationFrame(render);
}
render();

在其他地方这样做

someElement.addEventListener('click', function() {
  var data = someCanvas.toDataURL();
}, false);

animation frameclick 这两个事件不同步,在调用它们之间可能会清除画布.注意:画布不会显示为已清除,因为它是双缓冲的,但缓冲区 toDataURL 和影响该缓冲区正在查看的其他命令已被清除.

Those 2 events, the animation frame, and the click are not in sync and the canvas may be cleared between calling them. Note: The canvas won't appear cleared as it's double buffered but the buffer toDataURL and other commands that effect that buffer are looking at is cleared.

解决方案是使用 preserveDrawingBuffer 或在与渲染相同的事件中调用 toDataURL.例如

The solution is either use preserveDrawingBuffer or make your call to toDataURL inside the same event as rendering. For example

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) 复制您正在绘制的缓冲区的内容以执行正在显示的缓冲区.交换比复制快得多.因此,交换是默认设置.实际发生的事情取决于浏览器.唯一的要求是,如果 preserveDrawingBufferfalse,则在合成后绘制缓冲区被清除(这是另一个异步事件,因此不可预测)如果 preserveDrawingBuffertrue 然后它必须复制以便保留绘图缓冲区的内容.

What's the point of preserveDrawingBuffer: false which is the default? It can be significantly faster, especially on mobile to not have to preserve the drawing buffer. Another way to look at it is the browser needs 2 copies of your canvas. The one you're drawing to and the one it's displaying. It has 2 ways to deal with these 2 buffers. (A) double buffer. Let you draw to one, display the other, swap the buffers when you're done rendering which is inferred from exiting any event that issued draw commands (B) Copy the contents of the buffer you're drawing to do the buffer that's being displayed. Swapping is much faster than copying. So, swapping is the default. It's up to the browser what actually happens. The only requirement is that if preserveDrawingBuffer is false that the drawing buffer get cleared after a composite (which is yet another async event and therefore unpredictable) if preserveDrawingBuffer is true then it must copy so that the drawingbuffer's contents is preserved.

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

Note that once a canvas has a context it will always have the same context. So in other words let's say you change the code that initializes the WebGL context but you still want to set preserveDrawingBuffer: true

至少有两种方法.

因为后面的代码会以相同的上下文结束.

since the code later will end up with the same context.

<script>
document.querySelector('#somecanvasid').getContext(
    'webgl', {preserveDrawingBuffer: true});
</script>
<script src="script/that/will/use/somecanvasid.js"></script>

因为您已经为该画布创建了上下文,接下来的任何脚本都将获得相同的上下文.

Because you've already created a context for that canvas whatever script comes after will get the same context.

<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.

In this case any webgl context created after augmenting the getContext will have preserveDrawingBuffer set to true.

这篇关于Canvas toDataURL() 返回空白图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆