【问题标题】:Canvas toDataURL() returns blank image画布 toDataURL() 返回空白图像
【发布时间】:2015-01-03 04:51:36
【问题描述】:

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

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

【问题讨论】:

  • 您正在编辑的图像是否在同一个域中?只是为了排除明显的。
  • 是的。我将编辑我的帖子以提及这一点! Firefox(而不是 chrome)中的图像不在同一个域中存在问题?
  • 似乎是某处发生的异步操作。如果调用 toDataURL() 时未加载图像,则画布将为空白。
  • 图像已加载到画布上,我可以查看和编辑它。问题是 toDataURL 没有从画布中获取正确的信息。
  • 作为额外的检查,如果画布的宽度或高度为 0,根据文档,getDataURL() 返回"data:," 。在(错误地)将画布的大小设置为 0 之后,我得到了这个。

标签: javascript firefox canvas webgl todataurl


【解决方案1】:

很可能在您绘制到画布的时间和您调用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 frameclick 这 2 个事件不同步,在调用它们之间可能会清除画布。注意:画布不会显示为已清除,因为它是双缓冲的,但缓冲区 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 个画布副本。您正在绘制的那个和它正在显示的那个。它有两种方法来处理这两个缓冲区。 (A) 双缓冲。让您绘制到一个,显示另一个,在完成渲染时交换缓冲区,这是从退出任何发出绘制命令的事件中推断出来的 (B) 复制您正在绘制的缓冲区的内容以执行正在显示的缓冲区.交换比复制快得多。因此,交换是默认设置。实际发生的事情取决于浏览器。唯一的要求是,如果preserveDrawingBufferfalse,则绘图缓冲区在复合后被清除(这是另一个异步事件,因此不可预测)如果preserveDrawingBuffertrue,那么它必须复制以便绘图缓冲区的内容被保留。

请注意,一旦画布具有上下文,它将始终具有相同的上下文。所以换句话说,假设您更改了初始化 WebGL 上下文的代码,但您仍想设置 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>

在这种情况下,在扩充 getContext 之后创建的任何 webgl 上下文都将 preserveDrawingBuffer 设置为 true。

【讨论】:

  • 因为我使用的是 glfx.js 库,所以我无法直接访问画布和渲染方法。我以 5 秒的超时时间调用了 toDataURL 函数事件,但它不起作用。我不认为这里有什么异步的......可以是别的什么吗?
  • 以 5 秒的超时调用 toDataURL 是一个异步事件。你在 JavaScript 中。你有 glfx.js 的源代码。改变它。
  • 我设法通过使用 glfx 函数 (update()) 更新 canvas 元素解决了这个问题。但是我不知道为什么这个问题只出现在 FF 而不是 Chrome。谢谢!
  • 它是 FF 只是因为这里的规范不明确。 WebGL 规范有效地说,如果向 WebGL 上下文发出绘图命令,则下次网页与页面合成时,画布的绘图缓冲区将被清除。当合成发生时是异步的。换句话说,您不知道它什么时候会发生,以及在您绘制某些东西和合成发生的时间以及缓冲区被清除之间会发生什么事件。这意味着它在每个浏览器上都不同。在 Chrome 的情况下,您在清除之前获得画布,在清除后获得 FF。
  • 这就解释了。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-07
  • 2016-04-23
  • 2012-08-13
  • 1970-01-01
  • 1970-01-01
  • 2015-09-20
相关资源
最近更新 更多