How to save canvas animation as gif or webm?

15,786

Solution 1

In modern browsers you can use a conjunction of the MediaRecorder API and the HTMLCanvasElement.captureStream method.

The MediaRecorder API will be able to encode a MediaStream in a video or audio media file on the fly, resulting in far less memory needed than when you grab still images.

const ctx = canvas.getContext('2d');
var x = 0;
anim();
startRecording();

function startRecording() {
  const chunks = []; // here we will store our recorded media chunks (Blobs)
  const stream = canvas.captureStream(); // grab our canvas MediaStream
  const rec = new MediaRecorder(stream); // init the recorder
  // every time the recorder has new data, we will store it in our array
  rec.ondataavailable = e => chunks.push(e.data);
  // only when the recorder stops, we construct a complete Blob from all the chunks
  rec.onstop = e => exportVid(new Blob(chunks, {type: 'video/webm'}));
  
  rec.start();
  setTimeout(()=>rec.stop(), 3000); // stop recording in 3s
}

function exportVid(blob) {
  const vid = document.createElement('video');
  vid.src = URL.createObjectURL(blob);
  vid.controls = true;
  document.body.appendChild(vid);
  const a = document.createElement('a');
  a.download = 'myvid.webm';
  a.href = vid.src;
  a.textContent = 'download the video';
  document.body.appendChild(a);
}

function anim(){
  x = (x + 1) % canvas.width;
  ctx.fillStyle = 'white';
  ctx.fillRect(0,0,canvas.width,canvas.height);
  ctx.fillStyle = 'black';
  ctx.fillRect(x - 20, 0, 40, 40);
  requestAnimationFrame(anim);
}
<canvas id="canvas"></canvas>

Solution 2

You can also use https://github.com/spite/ccapture.js/ to capture to gif or video.

Share:
15,786

Related videos on Youtube

Hashir Salam
Author by

Hashir Salam

I am a computer science graduate with extensive technology knowledge and skills to achieve targets. I specialize in MEAN stack (MongoDB, Express.js, Angular, Node.js) and Microsoft SharePoint / Office 365. I use Ionic for hybrid mobile development (IOS / Android). I have worked in Flask and Django framework (Python). If you have any question, don't hesitate to send me a message! Thanks!

Updated on October 24, 2020

Comments

  • Hashir Salam
    Hashir Salam over 3 years

    i have written this function to capture each frame for the GIF but the output is very laggy and crashes when the data increases. Any suggestions ?

    Code :

        function createGifFromPng(list, framerate, fileName, gifScale) {
                gifshot.createGIF({
                    'images': list,
                    'gifWidth': wWidth * gifScale,
                    'gifHeight': wHeight * gifScale,
                    'interval': 1 / framerate,
                }, function(obj) {
                    if (!obj.error) {
                        var image = obj.image;
                        var a = document.createElement('a');
                        document.body.append(a);
                        a.download = fileName;
                        a.href = image;
                        a.click();
                        a.remove();
                    }
                });
            }
    /////////////////////////////////////////////////////////////////////////
    
    function getGifFromCanvas(renderer, sprite, fileName, gifScale, framesCount, framerate) {
                var listImgs = [];
                var saving = false;
                var interval = setInterval(function() {
                    renderer.extract.canvas(sprite).toBlob(function(b) {
                        if (listImgs.length >= framesCount) {
                            clearInterval(interval);
                            if (!saving) {
                            createGifFromPng(listImgs, framerate, fileName,gifScale);
                                saving = true;
                            }
                        }
                        else {
                            listImgs.push(URL.createObjectURL(b));
                        }
                    }, 'image/gif');
                }, 1000 / framerate);
            }
    
  • TheJim01
    TheJim01 almost 6 years
    I think part of the point was that performance goes down as the number of Blobs increases, so storing them until you can execute this code might not be viable.
  • Kaiido
    Kaiido almost 6 years
    @TheJim01 I probably should have explained that MediaRecorder encodes the video on the fly, so it will not save still images, and the chunks we store there are really chunks of the final media file i.e already encoded as webm, or said differently, not still images. You keep only the data of the final video in memory.
  • Umesh Patadiya
    Umesh Patadiya over 5 years
    Hi, I'm trying to use this code but I got error like: canvas.captureStream is not a function
  • Kaiido
    Kaiido over 5 years
    @UmeshPatadiya from which browser? Microsoft ones still don't support this method.
  • Umesh Patadiya
    Umesh Patadiya over 5 years
    I'm using chrome on windows. My project is in angular 6.
  • Kaiido
    Kaiido over 5 years
    @UmeshPatadiya ... I don't know angular, do they wrap everything in their own object in a TypeScript fashion? In this case, you'd probably have to extend whatever object you have so that it implements the native element's methods. And you could first check console.log(canvas instanceof HTMLCanvasElement) to be sure you are dealing with a canvas.
  • Umesh Patadiya
    Umesh Patadiya over 5 years
    @Kaiido I'm getting false in above log, one more thing is I'm using fabricJS canvas.
  • Kaiido
    Kaiido over 5 years
    Then what is canvas if it is not an HTMLCanvasElement? Do you set it to canvas = new fabric.Canvas()? In that case, this is not a canvas you have here, but a fabricjs object. You'd need to call its getElement method to retrieve the real canvas element.
  • Umesh Patadiya
    Umesh Patadiya over 5 years
    Thanks @Kaiido It's working now. I added getElement(). now let me know once thing. Is it possible to record with the sound?
  • Kaiido
    Kaiido over 5 years
  • Ryan
    Ryan over 4 years
    Does this approach support saving transparency / alpha into the webm (like I'm hoping for here stackoverflow.com/q/58190652/470749)?
  • Kevin Wheeler
    Kevin Wheeler over 3 years
    The recording I'm getting is so blurry / poor quality. Is there any way to fix that?
  • Crashalot
    Crashalot over 3 years
    hi again @Kaiido. do you know if this architecture would hurt video quality? html5 canvas editor where users animate text, upload multiple video formats (.mp4, .mov, .avi, .wmv), and upload audio tracks; canvas exports webm; server uses ffmpeg to convert webm to multiple formats (.mp4, .mov, .avi, .wmv)?