Improve HTML5 Canvas frame by frame JPG animation

2019-03-22 18:01发布

问题:

I'm trying to build on top of this great script here which was answered by Phrogz.

The problem is that the animation won't play until all the images have cached in the browser. Therefore, on first load it won't play. Only on a reload.

The point of me trying to do this is I'm trying to provide an alternate solution to getting an animation to autoplay since that feature doesn't work in iOS browsers.

Here is the code I'm using:

         function draw() { 
            var imgNumber = 1;
            var lastImgNumber = 121;

            var ctx = canvas.getContext('2d');
            var img = new Image;
            img.onload = function(){
            ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );
            ctx.drawImage( img, 0, 0 );
            };
            var timer = setInterval( function(){
              if (imgNumber>lastImgNumber){
                clearInterval( timer );
              }
             else{
                img.src = "jpg_80/t5_"+( imgNumber++ )+".jpg";
              }
            }, 1000/24 ); //Draw at 24 frames per second
          }

I've tried adding this before the closing body tag:

                 window.onload = draw; 

However, I believe that the code would have to be changed within the draw() function. Somewhere in the setInterval function?

回答1:

This is a modified version of your draw function which preloads all images before putting them on a canvas.

It assumes you have a canvas with id 'anim' (as there is no reference of the canvas in the source you provided)

<canvas id='anim' width='660' height='500'></canvas>

JavaScript: (tested on an iPad)

function draw() {
    var ctx = document.getElementById('anim').getContext("2d");
    var start = 1, stop = 121,cur=start,imgArr=[];

    var loadLoop = function() {
        var img = document.createElement("img");
        img.onload = function() {
            imgArr.push(this);
            cur++;

            if(cur > stop) {
                // all images preloaded
                animate();
            }
            else {
                loadLoop();
            }
        }

        img.src = "jpg_80/t5_"+(cur)+".jpg";
    }

    loadLoop();

    function animate() {
        var timer = setInterval(function() {
            ctx.drawImage(imgArr.shift(), 0, 0 );
            if(imgArr.length == 0) {
                // no more frames
                clearInterval(timer);
            }
        },1000/24);
    }
}


回答2:

You can create 121 <img> elements and add an .onload function to each of them. In that handler you increment a number, and when it reaches 121, you start the animation.

But what you are trying to do sounds like you want to create a video clip. When that's your intention, the <video> tag might be a better solution. A 121 frame video clip encoded with a modern codec will be much smaller than 121 separate JPEGs, because video compression algorithms use redundancies between frames to improve compression.