Dejavu
Haven’t I read this already? I swear it was called “Losslessly crunch animations” before.
Yes, you did. I wrote a whole blog post comparing optimisation & conversion tools to each other, and determining that GIMP’s “Optimise (for GIF)” filter was the best option when it was available… and I was wrong.
So let’s start over, and hopefully not discover yet another tool which is magically better than everything else after I’ve already written a blog post about it, shall we?
GIF2APNG
GIF2APNG is a GIF-to-APNG converter. As of writing, GIMP doesn’t support exporting APNG animations (though plugins may exist to enable this), and moreover, GIF2APNG performs a number of optimisations which can shrink the output size considerably. Before getting into how to use the tool, I want to explain the APNG format since it’s less understood than other formats like GIF.
In reality, APNG is a standard PNG file such that the first frame of the animation is set as the main image data, and all the other frames are put into the metadata section of the PNG. Because of this, image viewers which don’t support APNG can display the image file as normal and ignore the unknown metadata. Unlike GIF, APNG supports 24-bit colour, non-binary transparency, and indexed colour mode is optional (GIF only supports 256 colours per frame due to indexing).
Here’s an example of using gif2apng:
gif2apng -z2 -i1 image.gif image.apng
- -z: Sets the compression algorithm used to compress the metadata frames (so that similar frames are deduplicated), where 0 is ZLIB, 1 is 7ZIP (default), and 2 is ZOPFLI. ZOPFLI nearly always yields the best compression, however, it may be worth experimenting with different algorithms on a per-image basis.
- -i: Sets the number of compression iterations (default 15). I recommend setting it to -i1 and then incrementing the value until you reach the point just before the output size starts increasing again (in some cases, the file size never changes regardless of the value).
- -kp: Keeps the original GIF file’s palette. If you’ve already optimised the GIF before feeding it into gif2apng, setting this option will avoid applying further optimisations to it (which in some rare cases can lead to a slightly larger file size).
I’d describe GIF2APNG as an inconsistent optimisation method. Typically, GIF optimisation tools will handily beat it in file size, but occasionally (I think more complex animations benefit most), GIF2APNG will produce an image file vastly smaller than what GIF-oriented tools can. Therefore, I’d recommend always trying this tool just in case.
Gifski
Gifski is a GIF optimisation tool from the same creator as the ‘pngquant’ tool (as covered in the Optimising pixel art post). There’s not much else to say, so here’s an example:
gifski --quality 100 --repeat 0 image.gif -o gifski.gif
- --quality/-Q: Sets the quality target for the output relative to the input. If gifski can’t meet the target without changing the image frames, like if more than 256 colours are present and dithering is therefore needed, the input will be returned instead.
- --repeat: Sets the number of times the animation will repeat, with ‘-1’ being none, ‘0’ being forever, and any positive integer is the number of times the animation loops.
- --output/-o: The output path for the image.
I have noticed that Gifski will delete completely empty frames, even if intentional, so look out for that if your animation has any. If you do experience this problem, consider using one of the other tools.
Gifski is intended for optimising large GIFs, with features like temporally-consistent dithering and others improvements focused on squeezing as much quality out of the GIF format as possible, but because of this (as I learned recently), Gifski is not the most effective GIF optimisation tool for simpler GIFs which are only a few kilobytes in size.
GIMP GIF filter
GIMP has a filter for optimising animations for the GIF format under Filters⇒Animation⇒Optimise (for GIF), and using this filter will cause a new file tab to be opened which contains the optimised image frames.
Instead of each frame being a distinct image which fully replaces the previous frame, ‘combine’ mode creates a sort of ghosting effect where any pixels which don’t overlap with pixels in the next frame are retained, which can drastically reduce the amount of data that each frame needs to store. However, GIMP’s automatic generation of combined frames isn’t perfect and can introduce visual artefacts.
For instance, you can’t replace a pixel with transparency in combine mode, you’d need to add a regular replacing frame (which GIMP’s filter doesn’t know how to do), so once a pixel is set it can only be replaced by another opaque pixel:
You can check whether any visual oddities like this have appeared before exporting by looking at Filters⇒Animation⇒Playback....
Attempting to feed the filter-optimised GIFs into GIF2APNG or Gifski will nearly always create larger image files. The reason Gifski’s output is larger, despite the fact that it also uses the optimisation, is because Gifski uses local colour palettes, where frames are given their own colour palette, for every frame which leads to OVER-ahem-overhead for small GIFs such as these.
Gifsicle
Gifsicle is another GIF optimisation tool similar to Gifski, however, this tool has proven to be the most effective at shrinking GIFs to their absolute minimum sizes, even beating out GIMP’s GIF filter.
It’s also the reason I had to rewrite this entire blog post once I realised its effectiveness.
Gifsicle is a much more feature-dense tool than the others, even having the ability to modify individual frames if needed, but for our purposes, we’ll only need the following to optimise a GIF:
gifsicle --optimize=3 --optimize=keep-empty image.gif -o gifsicle.gif
- --optimize/-O: Sets the optimisation level to use. -O1 is the least optimised and -O3 is the most. -Okeep-empty preserves empty transparent frames (which is the problem I noted Gifski as having earlier).
- As mentioned in the man gifsicle pages, -O3 may produce larger images than the other “lower” optimisation levels on rare occasions, so it may be worth trying all of them to avoid this.
- --output/-o: The output path for the image.
EXIF data
Using a tool like Exiftool, you can additionally shave off some bytes from the image. Here’s the command to remove all non-essential EXIF metadata:
exiftool -all= image.ext
- -all=: Sets all EXIF metadata to emptiness; “”.
Exiftool will not remove animation-frame metadata from APNG files, so don’t worry about accidentally removing the ‘A’ from APNG. It’s also worth noting that GIMP (when exporting minimally) and Gifsicle already create image files without any non-essential EXIF metadata.
Demonstrations
Exact commands used:
gif2apng -z2 -i1 image.gif image.apng
gifski --quality 100 --repeat 0 image.gif -o gifski.gif.
gifsicle --optimize=3 --optimize=keep-empty image.gif -o gifsicle.gif
exiftool -all= image.ext
The ‘WHAT!?’ tag header image:
- Gifsicle: 604 bytes.
- Exiftool: No change.
- Filter-optimised GIMP GIF: 660 bytes.
- Exiftool: No change.
- GIF2APNG: 994 bytes.
- Exiftool: 958 bytes.
- Gifski: 1104 bytes.
- Exiftool: 1093 bytes.
- Normal GIMP GIF: 1876 bytes.
- Exiftool: No change.
The ‘Bad Idea’ tag header image:
- Gifsicle: 1021 bytes.
- Exiftool: No change.
- Gifski: 1603 bytes.
- Exiftool: 1592 bytes.
- GIF2APNG: 2627 bytes.
- Exiftool: 2591 bytes.
- Normal GIMP GIF: 3623 bytes.
- Exiftool: No change.
- Filter-optimised GIMP GIF: N/A (underline doesn’t disappear as it should).
And finally, the ‘Scripting’ tag header image:
- GIF2APNG: 6205 bytes.
- Exiftool: 6169 bytes.
- Gifsicle: 10611 bytes.
- Exiftool: No change.
- Gifski: 18359 bytes.
- Exiftool: 18348 bytes.
- Normal GIMP GIF: 24080 bytes.
- Exiftool: No change.
- Filter-optimised GIMP GIF: N/A (underscore persists when it shouldn’t).
As the results show, Gifsicle is the most effective way to optimise GIFs, however, APNG can end up being the most compact format in certain circumstances.