Convert animated SVG to movie
I have an animated SVG and would like to turn it into a movie (a series of pictures would also do). The animation plays in webkit browsers (Safari, Chrome) and in Batik's squiggle). I tried capturing it with a screen capturer. but the movie ends up pretty jerky.
Is there a good tool for this?
Here's an example animation:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%">
<rect id="BB" x="0" y="0" height="100%" width="100%" fill="white"/>
<g id="firstone" stroke="black">
<g id="g3" fill="none" stroke-width="2">
<animateTransform attributeName="transform" type="rotate" dur="5s" from="360 100 100" to="0 100 100" repeatCount="indefinite"/>
<g id="g2">
<ellipse id="g1" cx="100" cy="100" rx="75" ry="75">
</ellipse>
<g id="sec">
<line x1="100" y1="100" x2="45" y2="45" style="stroke: rgb(99, 99, 99); stroke-width: 6;"/>
</g>
</g>
</g>
<g id="pit">
<line x1="100" y1="175" x2="100" y2="200" style="stroke: red; stroke-width: 6;"/>
</g>
</g>
</svg>
Solution 1:
Have you tried using squiggle to export a series of frames? I found squiggle a pain to get your line just where I wanted it to be to properly set up a series of frames. However, once you have that, you can use imagemagick - apparently my favorite answer this week ;-) to transform it however you like.
Assuming each you save the frames off as frame01.svg, frame02.svg, etc. Then this:
convert -delay 5 -loop 0 frame??.svg animated.gif
will make a single animate gif from your frames that loops forever, 5 ms between frames.
convert will convert svg to , but imagemagick doesn't process the animateTransform tag, so any output is static.
Update: I found squiggle so painful to work with (at least trying to stop the animation at just the right spot to grab an image, I was embarrassed to have even suggested it!
Here's a bash script using imagemagick to convert your svg into an animated gif: Before running this script I split your example svg into 2 parts: bg.svg contains the elipse and the 'pit' element and hand.svg contains just the 'sec' element
`#!/bin/bash`
rm *.png
rm anim.gif
convert bg.svg -crop 200x200+0+0 +repage bg.png
convert hand.svg -crop 200x200+0+0 +repage -transparent white hand.png
for ((i=1; i<=359; i=i+3))
do
convert hand.png -gravity center -rotate $i tmp.png
n=`printf "%03d" $i`
composite -gravity center tmp.png bg.png hand${n}.png
rm tmp.png
done
convert -delay 1 -loop 0 hand*.png anim.gif
~
I'm sure someone more clever than me could figure out how to merge the convert and combine all in one step without also rotating the bg.png, but this is what you get for free ;-)
Also, wanted to keep this simple, just in case it needs to be reimplemented as a windows bat file.
The i=i+5 is a trade-off between how smooth the animation looks vs. file size.
Note: Even with -delay 1 (1 ms between frames), firefox would not move the hand in a complete circle in 5 seconds. It was closer to 10 secs.
And here's what the script produced
Solution 2:
I found a way to create the series of images with the help of canvg. To run the following page, you have to use a modified script of canvg.js in that the draw function is accessable.
Changes in script canvg.js (v1.0):
In line 2321 change from:
var draw = function() {
to:
svg.draw = function() {
In line 2361 and 2390 change from:
draw();
to:
svg.draw();
My generation script:
<html>
<head>
<script type="text/javascript" src="rgbcolor.js"></script>
<script type="text/javascript" src="canvg.js"></script>
<script type="text/javascript">
loadSVG = function() {
canvg('canvas', '<animated SVG>', { ignoreMouse: true, ignoreAnimation: true });
}
function RenderNext(delta) {
var c = document.getElementById("canvas");
var svg = c.svg;
for (var i=0; i<svg.Animations.length; i++) {
svg.Animations[i].update(delta);
}
svg.draw();
}
function CreateImage(imgStr) {
var oImg=document.createElement("img");
oImg.setAttribute('src', imgStr);
return oImg;
}
function start() {
var c = document.getElementById("canvas");
var result = document.getElementById("resultDiv");
var maxDur = 5; // seconds
var framerate = 5; // imgages per second
for (var i = 0; i < framerate * maxDur; i++) {
RenderNext(1000 / framerate);
var oImg = CreateImage(c.toDataURL('image/png'));
result.appendChild(oImg);
}
}
</script>
</head>
<body onload="loadSVG()">
<canvas id="canvas" width="30px" height="30px"></canvas>
<p>
<input type="button" id="start" value="Start" onclick="start()" />
</p>
<div id="resultDiv">
</div>
</body>
</html>
Solution 3:
If you're using FireFox you might give SVG Render Plug in a try: http://adasek.cz/svgrender/
Solution 4:
to render animated svg to animated gif
- convertio online converter
- a code snippet using d3.js and gif.js, you also need the files: sp-500.csv, gif.js, gif.worker.js
- a whole study using different tools
- GreenSock GSAP - SVG Timeline Animations to GIF
- cloudfour.com - rasterizing svg animations
- chrisgannon - SVG2GIF
Solution 5:
There is a node package called timecut
which uses Chromium to record an SVG into an MP4 video file. https://github.com/tungs/timecut
Installation
$ cd project
$ npm install timecut
Usage
$ cd project
$ ./node_modules/timecut/cli.js Animation.svg
This creates a file named video.mp4
.
timecut
has quite a number of options, like frame rate, pixel format, etc.