抓取HTML5画布的每个帧

时间:2010-07-27 17:10:33

标签: javascript animation html5 screen-scraping

这些调色板循环图像令人叹为观止:http://www.effectgames.com/demos/canvascycle/?sound=0

我想将其中的一些(或全部)变成桌面背景。

我可以使用动画gif版本,但我不知道如何从画布“动画”中获得它。是否有任何可用的东西可以沿着这些方面做某事(特别是对于那个链接而言,一般而言)。

5 个答案:

答案 0 :(得分:24)

我有一个解决方案,但依赖于您熟悉Firefox中的Javascript控制台(安装Firebug plugin),Chrome或Safari。

如果您不是,请点击它,或尝试右键单击页面上的任意位置,选择“检查元素”并查找“控制台”。 ..

代码的作用:

它允许您每1/10秒获取10个CANVAS元素的屏幕抓取。这两个值都很容易修改,因为您可以调整以找到您想要获得的迭代次数。对于您提供的示例,canvas元素ID为“ mycanvas ”。

一旦有了屏幕抓取功能,它就会将图像输出到页面中。此时,您可以保存单个图像。

运行代码

将以下代码粘贴到 Javascript控制台

var canvas = document.getElementById("mycanvas");
var shots  = [];
var grabLimit = 10;  // Number of screenshots to take
var grabRate  = 100; // Miliseconds. 500 = half a second

var count     = 0;

function showResults() {
    //console.log(shots);
    for (var i=0; i<shots.length; i++) {
      document.write('<img src="' + shots[i] + '"/>\n');
    }
}

var grabber = setInterval(function(){
  count++;

  if (count>grabLimit) {
    clearInterval(grabber);
    showResults();
  }

  var img     = canvas.toDataURL("image/png");
  shots.push(img);
}, grabRate);

并按 CTRL-Enter 执行该操作。

运行需要几秒钟,请耐心等待。

之后,您应该拥有所有必要的帧(可能更多)以通过ImageMagick,此网站MakeAGif.com或其他应用创建动画GIF。

旁注

如果由于某种原因你需要输出JPG的GIF而不是PNG,只需根据需要更新:

var img     = canvas.toDataURL("image/png");

其中一个:

var img     = canvas.toDataURL("image/gif");
var img     = canvas.toDataURL("image/jpg");

支持 gif jpg 的输出可能不适用于所有浏览器(应该是最多的)。

(BIG)UPDATE#1

首先,我保持上面的代码完整而不是更新它,因为这两种方法都可能对其他人有所帮助。

其次,这个新代码没有解决问题。它只是一个主要的缺点。它创建了一个动画GIF( Yipee!),但它有各种不同的绿色( Boooo!)。不确定如何/为什么,但也许有人可以从这里拿走它,看看我错过了什么。

所以我们去......同样的规则适用 - 将其复制并粘贴到浏览器的Javascript控制台中(它落后于Firefox但谷歌Chrome很快......运行时间大约10秒)。

var jsf  = ["/Demos/b64.js", "LZWEncoder.js", "NeuQuant.js", "GIFEncoder.js"];
var head = document.getElementsByTagName("head")[0];

for (var i=0;i<jsf.length;i++) {
  var newJS = document.createElement('script');
  newJS.type = 'text/javascript';
  newJS.src = 'http://github.com/antimatter15/jsgif/raw/master/' + jsf[i];
  head.appendChild(newJS);
}

// This post was very helpful!
// http://antimatter15.com/wp/2010/07/javascript-to-animated-gif/

var w = setTimeout(function() { // give external JS 1 second of time to load

    console.log('Starting');

    var canvas = document.getElementById("mycanvas");
    var context = canvas.getContext('2d');
    var shots  = [];
    var grabLimit = 10;  // Number of screenshots to take
    var grabRate  = 100; // Miliseconds. 500 = half a second
    var count     = 0;

    function showResults() {
        console.log('Finishing');
        encoder.finish();
        var binary_gif = encoder.stream().getData();
        var data_url = 'data:image/gif;base64,'+encode64(binary_gif);
        document.write('<img src="' +data_url + '"/>\n');
    }

    var encoder = new GIFEncoder();
    encoder.setRepeat(0);  //0  -> loop forever, 1+ -> loop n times then stop
    encoder.setDelay(500); //go to next frame every n milliseconds
    encoder.start();

    var grabber = setInterval(function(){
      console.log('Grabbing '+count);
      count++;

      if (count>grabLimit) {
        clearInterval(grabber);
        showResults();
      }

      var imdata = context.getImageData(0,0,canvas.width,canvas.height);
      encoder.addFrame(context);

    }, grabRate);

}, 1000);

它使用了这篇博文JavaScript to (Animated) GIF中引用的一些有用的代码,指针和JS文件。我直接使用了一些JS文件,但是如果要使用它们,你应该在本地复制这些文件。

我的输出是这个GIF: alt text

所以它的东西,但不是你需要的......

答案 1 :(得分:12)

编辑:最后使用该代码,结果如下:

alt text

Imagick生成了一个大图像,因此我继续使用gimp进行优化。

客户端代码是Michael代码的修改版本:

var canvas = document.getElementById("mycanvas");
var shots  = [];
var grabLimit = 30;  // Number of screenshots to take
var grabRate  = 100; // Miliseconds. 500 = half a second

var count     = 0;

function postResults() {
   console.log("START---------");
   for (var i = 0; i < shots.length; i++) {
      document.write(shots[i]+"<br />");
   }    
   console.log("END-----------");
}

var grabber = setInterval(function(){
  count++;

  if (count>grabLimit) {
    clearInterval(grabber);
    postResults();
  }

  var img     = canvas.toDataURL("image/png");
  shots.push(img.replace("data:image/png;base64,",""));
}, grabRate);

它会在屏幕上写下一堆base64字符串。复制它们并将它们保存到文本文件中,然后将其上传到您的Web服务器。然后运行另一个脚本(见下文),它会将图像写入您的Web服务器。由此产生的图像将很大并且可能不连贯,因此打开GIMP并优化差异和GIF。保存时,强制它对所有帧使用相同的延迟,以便动画流畅。


使用PHP可能不会太难。

  1. 使用JS获取每个帧的dataURL(base64编码的字符串)并将其发送到服务器。
  2. 解码base64字符串并将它们转换为Imagick对象。
  3. 将这些Imagick对象作为帧添加到新的Imagick对象。
  4. 将Imagick对象作为GIF保存到文件系统。
  5. 由于迈克尔已经发布了一个不错的JS解决方案,如果你想自动化它,我会添加服务器端代码:

    <?php
    $imageData = array_map('rtrim', file('data.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)); //base 64 strings separated by newlines
    $delay = 100;
    $filename = 'coolmoviebro.gif';
    $gif = new Imagick();
    
    for($i = 0; $i < count($imageData); $i++) {
       $tempImg = new Imagick();
       $tempImg->readimageblob(base64_decode($imageData[$i]));
       $gif->addImage($tempImg);
    }
    
    $gif->setFormat('gif');
    $gif->setImageDelay($delay);
    $gif->writeImages($filename, true);
    
    ?>
    

    我一年或两年没写过多少PHP,所以一定要仔细检查一切等等。

答案 2 :(得分:2)

我看了一下代码,似乎应该可以通过一点点黑客攻击。

通过查看Palette.Cycles中的循环对象列表,您应该能够使用cycle.high,cycle.low和cycle.rate字段计算每个循环的循环长度。也就是说,你需要为cycle.reverse的六个可能值中的每一个使用不同的算法。

一旦你知道列表中每个循环的长度(以毫秒为单位,如果我正确地读取代码),你可以找到所有循环长度的最小公倍数,这将告诉你总长度动画。但实际上,你需要先按照样本周期(例如,每秒10帧100毫秒)对它们进行底层划分,以获得较低的公倍数。

然后在main.js中设置animate函数以获取tickCount参数并将其传递给palette.cycle,而不是基于实时使用任何东西。每次迭代时,按样本周期增加滴答计数。

从那里,你应该能够修改Bitmap类的render方法,添加必要的逻辑来将画布转换为文件。似乎有些库可以为您管理最后一点。我建议使用刻度计数作为文件名保存文件(使用足够的前导零以保持它们的顺序。)将所有图像拼接成动画GIF可能可以使用正确的软件作为批处理作业执行。 / p>

当然,我还没有尝试过。例如,您可能希望进行检查,以确保您不会偶然发现具有史诗周期长度的动画,并在硬盘上创建数百万张图像。

顺便说一下,你还可以通过更多的工作,找出下次更新的确切时间并采取不规则的样本,但你必须弄清楚如何存储延迟信息,以便你可以使用它组装完成的GIF。

答案 3 :(得分:1)

可悲的是,根据art creator,由于图片的不同部分具有不同的周期,因此无法将其转换为GIF动画。

答案 4 :(得分:1)

Try PhantomJS

此脚本可保存100帧。

var webPage = require('webpage');
var fs = require('fs');
var page = webPage.create();

var NB_FRAME = 100;
var current = 0;

page.open('http://www.effectgames.com/demos/canvascycle/?sound=0',
function(status) {
  if (status === "success") {
     var current = 0;
     var grabber = setInterval(function () {
      var frame = page.evaluate(function() {
       return document.getElementById('mycanvas').toDataURL("image/png").split(",")[1];
      });
      fs.write("./frame-" + current + ".png",atob(frame), 'wb');
  if (++current === NB_FRAME) {
     window.clearInterval(grabber);
     phantom.exit(0);
  }
   }, 1000);
}
});

运行它:

 phantomjs SaveCanvasFrame.js

然后使用ImageMagick

convert *.png animated.gif

我们走了: animated