Skip to content

Instantly share code, notes, and snippets.

@weisjohn
Last active May 8, 2023 20:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save weisjohn/8066013 to your computer and use it in GitHub Desktop.
Save weisjohn/8066013 to your computer and use it in GitHub Desktop.
how to turn a keyframe animation into an animated png using phantomjs, imagemagick, and apngasm

jumping through hoops

A wonderfully warm winter day. Everything was perfect. Lofty visions of CSS3 animations dazzled my eyes. Nay, what's this? A browser from years ago appears. What's that you say? It doesn't support keyframes? Ghast. Make an animated gif! Oh, wait, we need transparency? Make an animated png!

This is the final outcome (sans history) of half a day spent to ensure experience parity on a super old (Opera 9.8) browser that we absolutely have to support.

It took hours, and it wasn't probably worth it, but I learned so much, and in the end it works pretty well.

technique

The original animation (part of a larger web-app) is in spin.html, but it all comes together in apng.sh:

  • simple python webserver
  • point phantomjs at the page with the animation
  • render out about 6 frames as pngs
  • use imagemagick to convert the pngs to have transparent backgrounds
  • package them up with apngasm into an apng
  • open up a sample page (for quick debug/tweak cycles)

Oh, and as luck would have it, the latest Chrome doesn't have apng support, so you'll have to view it in Firefox or install the APNG plugin. Oh, and Github doesn't allow animated PNGs, so you'll have to click on the image.

completion

It's still a little choppy, but it'll get the job done.

yes

#!/bin/bash
python -c $'import SimpleHTTPServer;\nmap = SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map;\nmap[""] = "text/plain";\nfor key, value in map.items():\n\tmap[key] = value + ";charset=UTF-8";\nSimpleHTTPServer.test();' "8896" &
server=$!
rm -rf animation.png render_*
# install from http://phantomjs.org/
phantomjs index.js
# rm $(ls render_* | head -n 3)
rm $(ls render_* | tail -n 1)
for file in `ls render_*`; do
echo "converting $file"
# black needs to be transparent
convert $file -fuzz 80% -transparent white $file
done
# install from http://apngasm.sourceforge.net/
apngasm animation.png render_*.png
open http://localhost:8896/preview.apng.html
sleep 5
kill $server
var page = require('webpage').create();
var count = 0, frames = 8, delay = 94;
function format(num) {
return num > 9 ? num : "0" + num;
}
function render() {
// skip the first frame
if (count > 1) page.render('render_' + format(count) + '.png');
if (count < frames) {
count++;
setTimeout(render, delay);
} else {
phantom.exit();
}
}
page.open('http://localhost:8896/spin.html', function() {
page.viewportSize = { width: 124, height: 124 };
setTimeout(render, delay);
});
<html>
<head>
<title></title>
<style type="text/css">
* { background: orange; }
</style>
</head>
<body>
<img src="animation.png">
</body>
</html>
<html>
<head>
<title>Olympus Dev Environment</title>
<style type="text/css">
* { background: white; }
.spin {
-webkit-animation: spinner 750ms infinite linear;
animation: spinner 750ms infinite linear;
width: 80.0px;
height: 80.0px;
left: 15px;
top: 15px;
z-index: 10000000;
padding: 0 !important;
margin: 0 !important;
border: 8.0px solid black;
border-right-color: white;
border-radius: 80.0px;
box-sizing: border-box;
display: inline-block;
position: relative;
overflow: hidden;
text-indent: -9999px;
}
@-webkit-keyframes spinner{
0% {
-webkit-transform:rotate(0deg);
transform:rotate(0deg)
}
100%{
-webkit-transform:rotate(360deg);
transform:rotate(360deg)}}
@keyframes spinner {
0%{
-webkit-transform:rotate(0deg);
transform:rotate(0deg)
}
100% {
-webkit-transform:rotate(360deg);
transform:rotate(360deg)}
}
}
</style>
</head>
<body>
<div class="spin"></div>
<!-- <div class="inner"> -->
<!-- <div id="AdScene"></div> -->
<!-- </div> -->
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment