通过canvas.toDataURL将画布保存到图像会产生黑色矩形

时间:2015-09-14 03:34:32

标签: javascript canvas html5-canvas webgl pixi.js

我正在使用Pixi.js并尝试将动画帧保存到图像中。 canvas.toDataUrl应该可以工作,但我得到的只是一个黑色矩形。查看实时示例here

我用来提取图像数据和设置图像的代码是:

            var canvas = $('canvas')[0];
            var context = canvas.getContext('2d');

            $('button').click(function() {

                var data = renderer.view.toDataURL("image/png", 1);
                //tried var data = canvas.toDataURL();
                $('img').attr('src', data);
            })

2 个答案:

答案 0 :(得分:13)

我知道至少有5次在SO上已经回答了但是......

Kaiido提到的内容可行,但真正的问题是,当与WebGL一起使用时,canvas默认有2个缓冲区。您要绘制的缓冲区和正在显示的缓冲区。

当您开始绘制到WebGL画布时,只要退出当前事件(例如requestAnimationFrame回调),画布就会标记为交换这两个缓冲区。当浏览器重新绘制页面时,它会进行交换。您正在绘制的缓冲区与正在显示的缓冲区交换。您现在正在绘制到其他缓冲区。该缓冲区被清除。

它清除而不是单独留下的原因是浏览器是否实际交换缓冲区或是否由浏览器决定。例如,如果打开了抗锯齿(这是默认值),那么它实际上并不进行交换。它确实解决了#34;。它将您刚刚绘制的highres缓冲区转换为正常的res抗锯齿副本到显示缓冲区。

因此,为了使其更加一致,无论浏览器以何种方式执行默认操作,它都会一直清除您要绘制的缓冲区。否则,您不知道它是否有1帧旧数据或2帧旧数据。

设置preserveDrawingBuffer: true告诉浏览器"始终复制,永不交换。在这种情况下,它不必清除绘图缓冲区,因为绘图缓冲区中的内容始终是已知的。没有交换。

这一切有什么意义?关键是,如果您想致电toDataURLgl.readPixels,则需要在相同的事件中调用它。

例如,您的代码可以像这样工作

var capture = false;

$('button').click(function() {
   capture = true;
});

function render() {

  renderer.render(...);

  if (capture) {
    capture = false;
    var data = renderer.view.toDataURL("image/png", 1);
    $('img').attr('src', data);
  }

  requestAnimationFrame(render);
}
requestAnimationFrame(render); 

在这种情况下,因为您在呈现的同一个javascript事件中调用toDataURL,所以无论是否preserveDrawingBuffer都是真或假,您都会得到正确的结果。< / p>

如果您正在编写不经常呈现的应用,您也可以执行类似

的操作
$('button').click(function() {
   // render right now
   renderer.render(...);

   // capture immediately
   var data = renderer.view.toDataURL("image/png", 1);
   $('img').attr('src', data);
});

默认情况下preserveDrawingBuffer为假的原因是因为交换比复制更快,因此浏览器可以尽可能快地进行。

另见this answer for one other detail

答案 1 :(得分:0)

[注]

虽然这个答案是公认的,但请在下面的@gman上阅读the one,它确实包含了更好的方法。

您的问题是您正在使用webGL上下文,然后您需要将webGL上下文的true属性设置为toDataURL(),以便能够调用<?php if ($contact->getField('nameLast') !='') { echo ' & <br /> '.$contact->getField('nameLast') ; } ?> 方法。< / p>

或者,您可以使用CanvasRenderer Class

强制pixi使用2D上下文