Last active
October 6, 2023 05:11
-
-
Save KL13NT/1b96c8888b384272a426ebcdf825b9ae to your computer and use it in GitHub Desktop.
A script to transform Animated Webp files into Webm files. Tested on Windows only. Depends on ffmpeg and libwebp. Make sure to add them to your PATH.
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
/** | |
* This script transforms animated webp files which are not widely supported yet | |
* to simple animated webm. Please state the source of your share this. | |
* | |
* # How this works | |
* This script depends on ffmpeg and libwebp provided by Google. Make sure | |
* they're in your PATH. | |
* | |
* The way this works is based off this answer https://askubuntu.com/a/1141049. | |
* It starts by extracting the input webp frames to a ./frames directory and, | |
* using webpmux, determines whether it's actually animated or not. If it is | |
* animated then it proceeds to use ffmpeg to create a webm based on the | |
* extracted frames. Cleanup is done after the script finishes successfully. | |
* | |
* It also takes a switch that determines whether you want to permanently delete | |
* the original animated webp file. | |
* | |
* libwebp: https://developers.google.com/speed/webp/docs/precompiled | |
* ffmpeg: https://ffmpeg.org/ | |
*/ | |
const child = require('child_process') | |
const fs = require('fs') | |
const path = require('path') | |
const util = require('util') | |
const exec = util.promisify(child.exec) | |
const terminateWithError = (error = '[fatal] error') => { | |
console.log(error) | |
process.exit(1) | |
} | |
const params = process.argv.slice(2) | |
if (!params[0]) terminateWithError('[fatal] need file name or absolute path') | |
const deleteOriginal = params[1] === 'true' | |
const filename = path.isAbsolute(params[0]) | |
? path.basename(params[0]) | |
: params[0] | |
if (deleteOriginal) console.log('[info] will delete original when successful') | |
const nameWithoutExt = filename.replace('.webp', '') | |
const frames = path.resolve(process.cwd(), 'frames') | |
if (fs.existsSync(frames)) fs.rmdirSync(frames, { recursive: true }) | |
fs.mkdirSync(frames) | |
process.chdir('frames') | |
console.log('[info]', process.cwd()) | |
console.log('[info]', `anim_dump ../${filename}`) | |
exec(`anim_dump ../${filename}`) | |
.then(() => { | |
process.chdir('..') | |
console.log('[info]', process.cwd()) | |
const command = `webpmux -info ./${filename}` | |
console.log('[info]', command) | |
return exec(command) | |
}) | |
.then(({ stdout, stderr }) => { | |
if (stderr) return Promise.reject(stderr) | |
const isAnimation = stdout.match(/Features present: animation/) !== null | |
if (!isAnimation) return Promise.reject('This is not an animated webp file') | |
const firstLine = stdout.match(/1:.+[\r]?\n/g) | |
if (!firstLine) return | |
const frameLength = firstLine[0].split(/\s+/g)[6] | |
const framerate = Math.round(1000 / frameLength) // frames/second | |
const dump = path.resolve(frames, 'dump_%04d.png') | |
const command = `ffmpeg -framerate ${framerate} -i "${dump}" "${nameWithoutExt}.webm" -y` | |
console.log('[info]', command) | |
return exec(command) | |
}) | |
.then(({ stdout, stderr }) => { | |
if (/error/gm.test(stderr)) return Promise.reject(stderr) | |
// cleanup | |
fs.rmdirSync(frames, { recursive: true }) | |
if (deleteOriginal) fs.rmSync(path.resolve(process.cwd(), filename)) | |
console.log('[info] Success!\n') | |
}) | |
.catch(err => { | |
terminateWithError(`[fatal] ${err}`) | |
fs.rmdirSync(frames, { recursive: true }) | |
}) |
@enzomtpYT I never did that but you can probably just switch up the extensions in the script and have it work just as well
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am currently searching the reversed thing