Created
April 5, 2016 07:49
-
-
Save jbmoelker/816b5307f6913334d4217f2fe719eb5b to your computer and use it in GitHub Desktop.
[POC] Animated SVG to GIF
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/** | |
* Script converts an animated SVG (`fileIn`) into an animated GIF (`fileOut`) | |
* with the given `duration`, `fps`, `width` and `height. | |
* This is just a proof-of-concept. Script needs an API etc etc. | |
*/ | |
// config which should come from cli args | |
const fileIn = 'animation.svg'; | |
const fileOut = 'animation.gif'; | |
const duration = 2000; // ms | |
const fps = 60; | |
const width = 320; // px | |
const height = 320; // px | |
// dependencies | |
const fs = require('fs'); | |
const GifEncoder = require('gifencoder'); | |
const phantom = require('phantom'); | |
const pngFileStream = require('png-file-stream'); | |
const Promise = require('bluebird'); | |
const mkdirp = Promise.promisify(require('mkdirp')); | |
const rmdir = Promise.promisify(require('rimraf')); | |
// internal vars | |
let instance; | |
const encoder = new GifEncoder(width, height); | |
let page; | |
const tempDir = 'frames/'; | |
/** | |
* create page with source svg | |
* render each frame to a png | |
* stitch all pngs together into a gif | |
*/ | |
phantom.create() | |
.then(_instance => { | |
instance = _instance; | |
return instance.createPage(); | |
}) | |
.then(_page => { | |
page = _page; | |
page.viewportSize = { width, height }; | |
return page.open(`file://${__dirname}/${fileIn}`); | |
}) | |
.then(() => mkdirp(tempDir)) | |
.then(() => renderFrames()) | |
.then(() => page.close()) | |
.then(() => instance.exit()) | |
.then(() => renderGif()) | |
.then(() => rmdir(tempDir)) | |
.catch(err => console.error(err)); | |
/** | |
* Render each frame to a png in temp dir. | |
* @returns {Promise} | |
*/ | |
function renderFrames() { | |
return new Promise((resolve, reject) => { | |
let frameIndex = 0; | |
const interval = setInterval(() => { | |
page.render(`${tempDir}${frameIndex}.png`).catch(reject); | |
frameIndex ++; | |
if (frameIndex > duration/fps) { | |
clearInterval(interval); | |
resolve(); | |
} | |
}, 1000/fps); | |
}); | |
} | |
/** | |
* Stich png frames from temp dir together and write to gif | |
*/ | |
function renderGif() { | |
return new Promise((resolve, reject) => { | |
pngFileStream(`${tempDir}?.png`) | |
.pipe(encoder.createWriteStream({ repeat: -1, delay: 1000/fps, quality: 10 })) | |
.pipe(fs.createWriteStream(fileOut)) | |
.on('error', err => reject(err)) | |
.on('finish', () => resolve()); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment