I’ve seen a number of questions regarding how to save an HTML5 canvas animation as an animated GIF. So, lets have at it…
Limitations: CCapture.js only works on browsers that have a `canvas implementation. More limitations listed on the the ccapture.s Github page.
[TLDR: Here’s the source code for the demo.]
Credit to Jaume Sanchez Elias for producing CCapture.js which I use here to handle the animation-to-GIF part of the task. Also to @Anton at konvajs.org for building, enhancing and supporting the Konva canvas library which powers the canvas part of this demo. I edited the jumping bunnies performance demo from the Konva website where it shows the visual performance Konva animations can provide.
The mods I made to the jumping bunnies demo are:
- Switch out the bunnies for Euro 21 country flags
- Gave the flags a rotation feature whereas bunnies did not rotate
- Multiple flag images required loading a bunch of html images before we unleash the jumping effect
- Added the code to fire up the ccapture.js engine and trigger its frame capture and save.
So – the demo launches two hundred 50px x 50px image shapes onto the canvas and bounces them around. We use ccapture.js to capture 2 seconds worth of this mahem. Ccapture.js cleverly manipulates the requestAnimationFrame() process, grabbing a snapshot of the canvas each time this is called – well its a bit more sophisticated than that but in essence this is what it does.
I was looking to get a fairly small GIF file so I reduced the ccapture frame rate to 20fps – if it was good enough for Buster Keaton then it’s good enough for bouncy footballs. This kept the file size good – around 3,500kb for 3 seconds at 400px square output.
The production of the GIF takes some time which is reasonable given what it has to do. My demo does not include a progress bar because there is currently no easy means of being notified of frame generation progress. The reason for this is that ccapture.js code utilises gif.js to handle the complexities of making the GIF. This involves much for-next looping through the pixels of each frame so as to spot unchanged pixels for optimisation, etc.
Whilst gif.js DOES emit events each time a frame is completed, ccapture.js does not have an obvious way to pass those events on to my code, or to let my code listen to those events on the encoder.
I think this could be done with some small modifications to the code in ccapture.js – look for ‘function CCGIFEncoder’ in the source and then search for ‘progress’ to see the code location where ccapture sees the gif.js events and outputs its progress when settings.verbose is set. The modification would be to expose the CCGIFEncoder object to our code object then do something like this in our code:
let gifEncoder = capturer.CCGIFEncoder;
gifEncoder.encoder.on( 'progress', function(progress){
console.log(progress);
// do something useful with progress to show percent complete?
}
I’ll leave that to you – meanwhile in the demo, open the console and you can see the reports of the number of frames to be produced and the current frame that was just completed. When it’s done you will see a GIF has been downloaded to your browser – enjoy.
I posted the demo as a CodePen project – it needed to be a project because normal codepens are all-in-one and I needed to upload the image files and ccapture.js. The project is available here.
Thanks for reading.
VW June 21
Since this is using the GIF format there must be some way to download a gif with a transparent alpha color, but I have seen no reference to how that is done. Any idea?
Thanks.
LikeLike