The nightmare that is Lottie to GIF conversion

Future edit:

I was informed that rlottie exists (which is used by Telegram and Discord): https://github.com/Samsung/rlottie

It comes with a built-in GIF converter called lottie2gif, but that does not support transparency.

I ended up making a (shitty) tool called LFE based on that that, which does the job of extracting each frame as PNGs with transparency. You can then replace the puppeteer-lottie-cli steps to equivalents with lfe.

I've run benchmarks of converting 30 files (alongside some other processing), and it ended up getting me over 3x speedups.

Before:

real    6m10.508s
user    2m3.647s
sys     0m19.909s

After:

real    1m59.302s
user    1m56.607s
sys     0m5.522s

(2020-12-04)


This is a blog post intended to explore the current options out there regarding Lottie->GIF/APNG conversions and go into what I personally ended up doing.

Wait, what is a “Lottie” again?

So, this is a little convoluted, but bear with me.

“Bodymovin” is a project created by Hernan Torrisi in 2015 that allows people to export After Effects projects as special JSON files, and originally, to use them on web.

Lottie seems like it was originally a project by airbnb introduced around early 2017* to bring facemovin to more platforms , but it seems like at some point facemovin became “Lottie-Web”, though it seems like it's still maintained by Hernan Torrisi.

Lottie is used by a number of large companies. Discord and Telegram recently started using Lottie for their animated stickers. (Though it's worth noting that Telegram actually uses a fork)

I personally dislike it. Sure, it may be smaller than an APNG, but it also makes my CPU a lot sadder than one, especially when there's several on the screen at once.

The options out there right now

python-lottie

When I first tested python-lottie, it crashed when trying to convert images:

...

They corrected this bug since then, but it still is a little buggy for converting to GIFs:

It needs work on the real world lottie files I tested (like the one above), but it is still quite promising. If you're reading this far into the future, you might want to try that before you deal with the messy conversion I talk about doing in this blog post.

puppeteer-lottie(-cli)

puppeteer-lottie-cli seemed a lot more promising as it ran a headless browser (and a lot less desirable as it's much heavier as a result), but outputs were... buggy, especially on parts with transparency:

Lottiefiles.com converter

The lottiefiles.com converter kept popping up here and there and people seemed to be rather happy about it, but it provided no API.

However, this got me wondering... how does that tick behind the scenes?

The deep dive

So, the first thing I ended up doing was searching “Lottiefiles github” to see if their website source code was public, and while it wasn't...

One of their forks gave me a really good pointer: https://github.com/LottieFiles/puppeteer-lottie

I suddenly realized that puppeteer-lottie had the potential to give me what I need, and started taking a look at the changes of this fork of puppeteer-lottie.

Not much was added, just a way to grab specific frames (and a fix for that).

I got the idea of just extracting frames and going off of those, and then stumbled upon this issue asking for APNG support. What's more interesting, however, was the fact that the issue body included a way of extracting each frame separately, which isn't something I realized I could do before.

I quickly did that, and took on the task of converting it into a GIF myself.

Not a lot interesting happened there, but after some fiddling with tools, I ended up with a pretty good way of converting Lotties to GIFs.

how.png

The way I currently convert lotties to GIFs is first extracting them into each separate frame (with a fixed size):

puppeteer-lottie -i "infilename.json" -o "frame-%d.png" --width 500

Then looking at the framerate inside the lottie file (“fr” field in the json), and converting it to an intermediary GIF with ffmpeg...

ffmpeg -y -framerate "frameratefromjson" -i "frame-%d.png" -filter_complex "[0:v] fps=50,split [a][b];[a] palettegen [p];[b][p] paletteuse" "intermediary.gif"

And finally, using imagemagick to do a -dispose Background pass for it to render properly everywhere..

convert -dispose Background "intermediary.gif" "final.gif"

This does sadly get rid of transparency, but it also gets rid of all the glitches:

And so, that's it! The best way of converting Lotties to GIFs at the moment, at least in my opinion.

Notes

*: I'm not entirely sure about when exactly Lottie popped up, and the official blog post does not include a date, but the file upload date is 01/2017. The second blog post has a cover image upload date of 08/2017, and refers to Lottie's release as “6 months ago”.