1.11.2017
How to export frames from animated SVG (or convert animated SVG to GIF, APNG)
(2.2020) Note: this method of exporting frames from SVG is for SMIL animations and is obsolete and not working in the actual version of chrome. New CSS animation recommended - see updated article here.
I was surprised, that after few hours of searching i couldn't find any simple solution how to export frames from SVG animation. There also none open software or library that can interpret and play SVG format - only browsers have that capability.
So that's an opportunity for some invention. With javascript, its possible to start/play/pause animation and you can render it onto 2d canvas. It's little tricky to keep animation state when rendering, but its possible.
Here is relatively simple code with comments: ( you need no external libraries - but modern browser recommended - tested on latest Chrome )
/* uniformly named URL object */
var DOMURL = window.URL || window.webkitURL || window;
/* our snapshotting class */
function svg_snapshot(svg_ref, fps, seconds) {
/* DOM object element */
this.svg_ref = svg_ref;
/* svg xml root */
this.svg_root = svg_ref.contentDocument.documentElement;
/* frames per second */
this.fps = fps;
/* total animation duration in seconds */
this.seconds = seconds;
this.svg_root.pauseAnimations();
this.make_step = function(step, time) {
if (time > this.seconds * 1000) {
// animation ended
return false;
}
/* pause for snapshot */
this.svg_root.pauseAnimations();
/* save actual svg state as XML */
var svg_xml = this.svg_root.outerHTML;
/* disable animation elements with simple replacing */
svg_xml = svg_xml.replace(new RegExp('<animate', 'g'), '<not_anim');
/* save as blob */
var svg_data = new Blob([svg_xml], {type: 'image/svg+xml'});
/* create data url (creates browsers interal blob: data link) */
var data_url = DOMURL.createObjectURL(svg_data);
/* create bitmap */
var img = new Image();
/* save class reference */
var self = this;
/* mount load process */
img.onload = function() {
self.make_step_next(step, time, this);
};
/* set image url */
img.src = data_url;
};
this.make_step_next = function(step, time, img) {
/* create canvas */
var canvas = document.createElement("canvas");
canvas.setAttribute("width", this.svg_ref.clientWidth);
canvas.setAttribute("height", this.svg_ref.clientHeight);
canvas.style.border = "1px solid black";
/* get canvas 2d contextr */
var ctx = canvas.getContext('2d');
/* drav loaded image onto it */
ctx.drawImage(img, 0, 0);
/* here we can get dataURL (base64 encoded url with image content) */
var dataURL = canvas.toDataURL('image/png');
/*
and here you can do whatever you want - send image
by ajax (that base64 encoded url which you can decode
on serverside) or draw somewhere on page
*/
var finalImg = document.createElement("IMG");
finalImg.src = dataURL;
finalImg.style.border = "1px solid black";
document.body.appendChild(finalImg);
/*
let animation continue - before image is loaded, the
animation is paused - by this is achieved perfect
timing in this serial process
*/
this.svg_root.unpauseAnimations();
var self = this;
var interval = 1000 / this.fps; // one frame interval
setTimeout(function() {
self.make_step(step + 1, time + interval);
}, interval);
};
}
/* usage - parameters: SVG DOM ref, frames per second, duration in seconds */
var item_ref = new svg_snapshot(document.getElementById('id_of_some_svg'), 30, 1);
/* start snapshotting */
item_ref.make_step(0, 0);
That's the principle. With those frames you could build them into animation in different format ( for example using convert ) or use them directly - to increase SVG performance or use it on some platform, where SVG isn't supported.
And here some live demonstration:
© 2024 Dzejkob games | info@dzejkobgames.eu | YouTube channel | Itch.io