Using Cloudinary to convert an animated GIF to a video

I like animated GIFs, like most people these days I think, but they are really heavy, hurting the performance of web pages, and consuming data plans faster than should be needed. So we need to convert them to videos, which are much lighter, for the same visual result. Let's use Cloudinary.

You need a Cloudinary account to try all of this, but no fear, its free plan is really confortable for personnal use or just testing: signup for Cloudinary.

The animations in this post are animated GIFs provided by Giphy and (obviously) converted by Cloudinary.

So, what's the issue with animated GIFs? §︎

Animated GIFs are really popular, thanks to nice cinemagraphs, or funny reaction images. But all these animated GIFs tend to be really really heavy.

This means:

  • once the animated GIF starts downloading and rendering, it will increase the load on the browser CPU and memory and make it less responsive
  • the user will consume her data-plan faster

What's the solution? §︎

Current state of the art for dealing with heavy animations is to replace animated GIFs with videos, which are much lighter. Twitter has been doing for years, for example. Giphy even provides MP4 alternatives to their animated GIFs.

Videos decoding can even be done by the device GPU, which means the CPU will not suffer like with animated GIFs, and the rendering will be smooth.

What about the easy autoplay of animated GIFs? §︎

Inline videos without a sound track, or muted, can be set to autoplay since:

Ok, so which video format? §︎

We only need one video format, MP4 encoded as H.264/AAC, because (almost) all browsers now support it:

Browser support for feature “mpeg4“
Can I Use mpeg4?

But adding WebM encoded as VP9/Opus can save a few more bytes, which is what we try to do here. And WebM support is pretty good:

Browser support for feature “webm“
Can I Use webm?

If you encode and host video files yourself, you could choose to use only MP4, to ease video creation and lower storage capacity requirements.

But if you don't have these concerns, for example because you use a CDN where storage is cheap and costs depend more on bandwidth, you should use both formats.

How can Cloudinary help? §︎

Cloudinary has been providing animated GIFs to video conversion for a while, as this blog post from 2014 shows: Reduce size of animated GIFs, automatically convert to WebM and MP4.

Here is the simple process it described:

First upload the animated GIF to Cloudinary, so that it is available at this URL:

https://res.cloudinary.com/demo/image/upload/kitten_fighting.gif

Then, change the file extension at the end of the URL to ask Cloudinary to convert it into WebM or MP4 video:

https://res.cloudinary.com/demo/image/upload/kitten_fighting.webm
https://res.cloudinary.com/demo/image/upload/kitten_fighting.mp4

Easy! Magical!

But I want my publication process to be even easier, not requiring any upload (manual or automated) of my digital assets.

That's why I find Cloudinary's Fetch API awesome!

You can also use Cloudinary's Auto-Upload, which provides a lot more features, but I like to keep things simple, and my master pristine images are hosted on my site anyway. Actually, my Jekyll-Cloudinary plugin uses the Fetch API to provide simple and efficient responsive images to Jekyll users.

So, how can we use the Fetch API to convert animated GIFs to videos?

Let's say the pristine animated GIF is located at https://example.com/anim.gif.

The simple Fetch API URL to serve this image though Cloudinary, but untouched, would be this:

https://res.cloudinary.com/<cloud_name>/image/fetch/https://example.com/anim.gif

<cloud_name> should be replaced by your own cloud_name.

If we try to replace .gif with .mp4 at the end of this URL, like in the 4 years old Cloudinary post, it won't work, because Cloudinary will try to fetch a video located at https://example.com/anim.mp4, which doesn't exist.

The solution is to use the explicit format conversion parameter (f_) you can set in your Fetch URL, before the pristine image URL:

https://res.cloudinary.com/<cloud_name>/image/fetch/f_mp4/https://example.com/anim.gif

So, we can replace this:

<img src="https://example.com/anim.gif" alt="an animation">

With this:

<video autoplay loop muted playsinline>
<source src="https://res.cloudinary.com/<cloud_name>/image/fetch/f_webm/https://example.com/anim.gif" type="video/webm">
<source src="https://res.cloudinary.com/<cloud_name>/image/fetch/f_mp4/https://example.com/anim.gif" type="video/mp4">
<p>Your browser doesn't support HTML5 video, <a href="https://example.com/anim.gif">download the animated GIF</a>.</p>
</video>

Don't use the animated GIF has a fallback §︎

Be careful if you put the source animated GIF has a <img> fallback for the <video> for browsers that don't support HTML5 videos, because it will always be downloaded!

If you need to publish animated GIFs anyway, at least make sure they are not too heavy (500KB should really be a maximum IMHO). You can use tools like Lossy GIF to optimize these animated GIFs.

Be careful! §︎

The transformation on Cloudinary can take some time if the animated GIF is really heavy, so you might have to consider uploading it and perform the transformation asynchronously, without using the Fetch API.

I didn't find any of this explained in Cloudinary documentation, maybe because it mixes images and videos.

One more thing… §︎

If you want to dive deeper in this topic, you can discover how — in the near future — animated GIFs converted to videos could be better loaded in <img> tags, with Colin Bendell's post in the 2017 edition of Performance (Advent) Calendar: Evolution of <img>: Gif without the GIF.

Apple has been the first to implement support of soundless videos has src attribute of img elements in Safari.

Chomium intended to implement it, but it was closed as WontFix.

Additional resources §︎