How to save canvas animation as gif or webm?
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.
Related videos on Youtube
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, 2020Comments
-
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 almost 6 yearsI 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 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 over 5 yearsHi, I'm trying to use this code but I got error like: canvas.captureStream is not a function
-
Kaiido over 5 years@UmeshPatadiya from which browser? Microsoft ones still don't support this method.
-
Umesh Patadiya over 5 yearsI'm using chrome on windows. My project is in angular 6.
-
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 over 5 years@Kaiido I'm getting false in above log, one more thing is I'm using fabricJS canvas.
-
Kaiido over 5 yearsThen what is
canvas
if it is not an HTMLCanvasElement? Do you set it tocanvas = new fabric.Canvas()
? In that case, this is not a canvas you have here, but a fabricjs object. You'd need to call itsgetElement
method to retrieve the real canvas element. -
Umesh Patadiya over 5 yearsThanks @Kaiido It's working now. I added getElement(). now let me know once thing. Is it possible to record with the sound?
-
Kaiido over 5 years@UmeshPatadiya stackoverflow.com/questions/39302814/…
-
Ryan over 4 yearsDoes this approach support saving transparency / alpha into the webm (like I'm hoping for here stackoverflow.com/q/58190652/470749)?
-
Kevin Wheeler over 3 yearsThe recording I'm getting is so blurry / poor quality. Is there any way to fix that?
-
Crashalot over 3 yearshi 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)?