代码之家  ›  专栏  ›  技术社区  ›  Matthew Groves

抓取HTML5画布的每一帧

  •  20
  • Matthew Groves  · 技术社区  · 14 年前

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

    我想把这些(或全部)做成桌面背景。

    我可以使用动画的GIF版本,但我不知道如何从画布“动画”中得到它。是否有任何可用的东西可以沿着这些线做一些事情(特别是对于那个链接,一般来说)。

    5 回复  |  直到 9 年前
        1
  •  24
  •   donohoe    14 年前

    我有一个解决方案,但它取决于您是否熟悉Firefox中的javascript控制台(安装Firebug插件),Chrome或Safari。

    如果您不是,请谷歌搜索它,或尝试右键单击页面上的任意位置,选择“ inspect element ”,然后查找“ console ”..

    代码的作用:

    它允许您每隔1/10秒对 canvas 元素进行10次屏幕抓取。这两个值都很容易修改,因为您可以调整以找到您想要的迭代次数。对于给出的示例,canvas元素id是“ mycanvas ”。

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

    运行代码

    将以下代码粘贴到javascript控制台中

    var canvas=document.getElementByID(“myCanvas”);
    无功放炮=[]
    var grabblimit=10;//要拍摄的屏幕截图数
    var grabrate=100;//毫秒。500=半秒
    
    var计数=0;
    
    函数showResults()。{
    //console.log(快照);
    对于(var i=0;i<shots.length;i++){
    document.write('<img src=“'+shots[i]+'“/>\n');
    }
    }
    
    var grabber=设置间隔(函数()。{
    计数+;
    
    如果(计数>抓取限制){
    清除间隔(抓取器);
    显示结果();
    }
    
    var img=canvas.todataurl(“image/png”);
    射击。推(img);
    };
    < /代码> 
    
    

    然后按ctrl enter.执行。

    跑步需要几秒钟,所以请耐心等待。

    之后,您应该拥有所有必要的帧(可能更多),以便通过ImageMagick创建动画GIF,this websitemakeagif.com,or other a p p.

    旁注

    如果出于某种原因,您需要输出为JPG格式的GIF而不是PNG格式,请根据需要进行更新,如下所示:

    var img=canvas.todataurl(“image/png”);
    < /代码> 
    
    

    其中一个:

    var img=canvas.todataurl(“image/gif”);
    var img=canvas.todataurl(“image/jpg”);
    < /代码> 
    
    

    支持输出为gifjpg可能不在所有浏览器中(应该是大多数浏览器)。

    (大)更新1

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

    第二,这个新代码不能解决问题。有点像,但有一个主要缺点。它创建一个动画gif(yipee!)但是它的颜色是各种深浅的绿色(booo!。不知道怎么做/为什么,但也许有人可以从这里拿走它,看看我错过了什么。

    所以我们开始…同样的规则也适用-复制并粘贴到浏览器的javascript控制台中(它在火狐中落后,但谷歌Chrome速度相当快…10秒左右)。

    var jsf=[“/demos/b64.js”,“lzwencoder.js”,“neuquant.js”,“gifencoder.js”];
    var head=document.getElementsByTagname(“head”)[0];
    
    对于(var i=0;i<jsf.length;i++){
    var newjs=document.createElement('script');
    newjs.type='text/javascript';
    newjs.src='http://github.com/antimatre15/jsgif/raw/master/'+jsf[i];
    head.appendchild(newjs);
    }
    
    //这篇文章很有帮助!
    //http://antimatre15.com/wp/2010/07/javascript-to-animated-gif/
    
    var w=setTimeout(function()//给外部JS 1秒的加载时间
    
    console.log(“开始”);
    
    var canvas=document.getElementByID(“myCanvas”);
    var context=canvas.getContext('2d');
    无功放炮=[]
    var grabblimit=10;//要拍摄的屏幕截图数
    var grabrate=100;//毫秒。500=半秒
    var计数=0;
    
    函数showResults()。{
    console.log(“finishing”);
    编码器.finish();
    var binary_gif=encoder.stream().getdata();
    var data_url='data:image/gif;base64,'+encode64(二进制_gif);
    document.write(“<img src=”'+data_url+'”/>\n');
    }
    
    var编码器=new gifencoder();
    encoder.setrepeat(0);//0->永远循环,1+->循环n次,然后停止
    encoder.setdelay(500);//每N毫秒转到下一帧
    编码器.start();
    
    var grabber=设置间隔(函数()。{
    console.log('抓取'+计数);
    计数+;
    
    如果(计数>抓取限制){
    清除间隔(抓取器);
    显示结果();
    }
    
    var imdata=context.getImageData(0,0,canvas.width,canvas.height);
    encoder.addframe(上下文);
    
    };
    
    },1000);
    < /代码> 
    
    

    它使用了一些有用的代码、指针和JS文件,这些代码、指针和JS文件在这个博客帖子中被引用javascript to(animated)gif。我直接使用一些JS文件,但是如果要经常使用它,您应该在本地复制这些文件。

    我的输出是这个gif:

    所以这是有意义的,但不是你需要的……

    使用JavaScript控制台的amiliar
    在firefox中(安装Firebug plugin)铬或狩猎。

    如果你没有,用谷歌搜索,或者尝试右键点击页面上的任何地方,选择“检查元素“寻找”慰问“……”

    代码的作用:

    它可以让你抓取10个屏幕CANVAS每十分之一秒一个元素。这两个值都很容易修改,因为您可以调整以找到您想要的迭代次数。对于您给出的示例,canvas元素id是'画布'.

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

    运行代码

    将以下代码粘贴到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进入执行它。

    跑步需要几秒钟,所以请耐心等待。

    在那之后,你应该有所有必要的帧(可能更多)来通过这个网站imagemagick创建一个动画gif。MakeAGif.com或其他应用程序。

    边注

    如果出于某种原因,您需要输出为JPG格式的GIF而不是PNG格式,请根据需要进行更新,如下所示:

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

    其中之一:

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

    支持输出为GIFJPG可能不在所有浏览器中(应该是大多数浏览器)。

    (大)更新1

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

    第二,这个新代码不能解决问题。有点像,但有一个主要缺点。它创建一个动画gif(伊比!)但是它有各种不同的绿色(酒鬼!)不知道怎么做/为什么,但也许有人可以从这里拿走它,看看我错过了什么。

    所以我们开始…同样的规则也适用-复制并粘贴到浏览器的javascript控制台中(它在火狐中落后,但谷歌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);
    

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

    我的输出是这个gif: alt text

    所以这是有意义的,但不是你需要的…

        2
  •  12
  •   Cristian Sanchez    14 年前

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

    imagick生成了一个大图像,所以我继续使用gimp进行优化。

    客户端代码是迈克尔代码的修改版本:

    var canvas=document.getElementByID(“myCanvas”);
    无功放炮=[]
    var grabblimit=30;//要拍摄的屏幕截图数
    var grabrate=100;//毫秒。500=半秒
    
    var计数=0;
    
    函数postResults()。{
    console.log(“开始-------”);
    对于(var i=0;i<shots.length;i++){
    document.write(快照[i]+“<br/>”);
    }
    console.log(“结束-------”);
    }
    
    var grabber=设置间隔(函数()。{
    计数+;
    
    如果(计数>抓取限制){
    清除间隔(抓取器);
    后结果();
    }
    
    var img=canvas.todataurl(“image/png”);
    shots.push(img.replace(“数据:image/png;base64,”,“);
    };
    < /代码> 
    
    

    它将向屏幕写入一组base64字符串。将它们复制并保存到文本文件中,然后将其上载到Web服务器。然后运行另一个脚本(见下文),它将把图像写入您的Web服务器。生成的图像会很大,可能会有起伏,因此打开gimp并针对差异和gif进行优化。保存时,强制它对所有帧使用相同的延迟,以便动画平滑。


    使用PHP可能不太难。

    1. 用JS抓取每个帧的dataurl(base64编码字符串),并将其发送到服务器。
    2. 解码base64字符串并将其转换为imagick对象。
    3. 将这些imagick对象作为帧添加到新的imagick对象中。
    4. 将imagick对象以gif格式保存到文件系统。

    由于Michael已经发布了一个很好的JS解决方案,如果您希望自动化它,我将添加服务器端代码:

    <?PHP
    $imagedata=array_map('rtrim',file('data.txt',file_ignore_new_lines file_skip_empty_lines));//以换行符分隔的64个基字符串
    $延迟=100;
    $filename='coolmoviebro.gif';
    $gif=新imagick();
    
    对于($i=0;$i<count($imagedata);$i++){
    $tempimg=new imagick();
    $tempimg->readImageBlob(base64_解码($imagedata[$i]);
    $gif->添加图像($tempimg);
    }
    
    $gif->设置格式(“gif”);
    $gif->设置图像延迟($delay);
    $gif->写入图像($filename,true);
    
    ?gt;
    < /代码> 
    
    

    我已经一两年没有写太多PHP了,所以一定要仔细检查所有东西,以此类推。

    使用,结果如下:

    alt text

    imagick生成了一个大图像,所以我继续使用gimp进行优化。

    客户端代码是迈克尔代码的修改版本:

    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。

    由于Michael已经发布了一个很好的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了,所以一定要仔细检查所有东西等等。

        3
  •  2
  •   Isabelle Wedin    14 年前

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

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

    一旦知道列表中每个循环的长度(以毫秒为单位,如果我正确地读取代码),就可以找到所有循环长度中最不常见的倍数,这将告诉您动画的总长度。但在实践中,为了得到一个较低的公倍数,您需要先将它们除以采样周期(例如,每秒10帧100毫秒)。

    然后在main.js中装配animate函数,获取一个tickCount参数并将其传递到palete.cycle中,而不是使用任何基于实时的东西。在每次迭代中按采样周期增加勾号计数。

    从那里,您应该能够修改位图类的呈现方法,添加必要的逻辑来将画布撕裂到文件中。似乎有一些库可以为您管理最后一个位。我建议使用勾号作为文件名保存文件(有足够的前导零来保持它们的顺序)。使用正确的软件将所有图像拼接到一个动画GIF中可能会作为批处理作业执行。

    当然,我还没试过。例如,您可能需要进行检查,以确保不会偶然发现具有史诗般循环长度的动画,并在硬盘上创建数百万个图像。

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

        4
  •  1
  •   syockit    14 年前

    可悲的是,根据 art creator ,由于图片的不同部分具有不同的循环,因此不太可能将其转换为GIF动画。

        5
  •  1
  •   youyoup    9 年前

    Try phantomjs

    此脚本可保存100帧。

    var webpage=require('webpage');
    var fs=需要(“fs”);
    var page=webpage.create();
    
    var nb_帧=100;
    无功电流=0;
    
    page.open('http://www.effectgames.com/demos/canvascycle/?声音=0’,
    功能(状态){
    if(status==“成功”)。{
    无功电流=0;
    var grabber=设置间隔(函数()。{
    var frame=page.evaluate(function()。{
    返回document.getElementByID(“myCanvas”).todataURL(“image/png”).split(“,”)[1];
    (});
    fs.write(“./frame-”+current+“.png”,atob(frame),'wb');
    如果(++当前==nb_帧){
    窗口。清除间隔(抓取器);
    幻影出口(0);
    }
    },1000);
    }
    (});
    < /代码> 
    
    <> >:

    phantomjs savecanvasframe.js
    < /代码> 
    
    

    然后使用imagemagick

    转换*.png animated.gif
    < /代码> 
    
    我们走:
    

    此脚本保存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