Warning: not Python
A friend recently built out a site which amongst other things, in some cases features large pages of animated GIFs. There is perhaps nothing more wasteful of an Internet connection than such a page, especialy when the “animation” is actually continuous tone real colour videos converted from some other format.
[Whoops, removed utterly wrong explanation of GIF compression. GIFs aren’t run-length encoded, they use LZW coding, so the description and example that previously appeared here were completely incorrect]
This is pretty much how photos and real-world videos rich in varied tones compress, and so using GIF to encode files like these is a horrible choice.
So why is it popular, then? Well, compatibility of course. GIF has been around since at least the 90s, if not earlier, and has been supported by all browsers for over a decade.
Unless you’ve been living under a rock, you might know that in recent years modern web browsers grew a <video> tag. Great, portable standardized containers for video!
Except it doesn’t work like that at all, because politics and money, of course. As can be seen from Video Formats and Browser Support, there is no single video codec that satisfies all popular browsers.
So unless we encode our videos at least twice (doubling at least storage costs), we can’t portably support the HTML <video> element. Even if a single encoding was supported by all modern browsers, that still leaves those less fortunate people stuck with ancient browsers out in the cold.
Still, each time I click one of these GIF-heavy pages and waiting 30 seconds for all 50MiB of it to load, I’m left wondering if there is a better way. And so comes a little head scratching, and an even littler proof of concept…
My little proof of concept doesn’t quite work well for all GIFs yet, though not surprising, since I only spent an hour or so on it. The general idea is:
* Figure out the maximum size of any GIF frame (since GIF frames may be variable)
* Politely ask ImageMagick to render each GIF frame in a tiled composition as a single new JPEG image (example source - 8.4MiB, result - 377KiB)
* Instantiate a class that uses the information stored in the JSON file to modify the DIV’s background-image-position CSS property at timed intervals, such that all but the image for the current frame is clipped by the DIV’s dimensions
* Success! 8.4MiB GIF is now a 377KiB “animated JPEG”. You can try out a final rendering here (and full page here). Note that many of the GIFs don’t quite render properly yet, and their timing is way off, but I’m certain the output size is representative.
Note also the browser’s CPU usage. It seems at least comparable to the same page full of GIFs, which I was quite surprised by. With Firefox, when the page is running in a background tab, CPU time is minimal.
No doubt there are issues with doing this in some browsers - for example, at the very least, the produced JPEGs are huge when they are decompressed. For our example GIF, this requires at least 40MiB RAM in the browser to decompress (and possibly 56MiB if the browser stores alpha information too)
In any case, I think there is room to improve on this technique and maybe produce something suitable for a live web site.
The original web page that caused me to think about this had 50MiB of GIF files. Recompressed, they come out as just 6.4MiB of JPEGs.