Lose The Wait: Optimizing GIF Images
Our Lose the Wait series is all about improving the performance of your web applications. As we have mentioned, a great way to lose the wait is to lose the weight, as in the weight of your page content. In our last post, we talked about using HTTP compression to reduce the size of the data that needs to be sent to the client, as well as the challenges that are involved. Now let’s shift our attention from text content to images.
Images make of the majority of content on the web. According to the HTTP Archive, the total size of an average web page and its supporting content is 968kB. Of that, 601kB, or 62% of the total amount, is image content. Understand images and how to optimize them are skills for any frontend performance advocate. To do this, we start by exploring the GIF image format and how to optimize it.
GIF is a lossless image format created by CompuServe in the late 1987. This makes GIF the oldest image format in common use on the web today. GIF is a palette based image format, allowing an image to contain up to 256 distinct colors defined from a possible 16,000,0000 colors (2^24). GIF images also support binary transparency. This means a pixel of the image can be completely transparency, showing the background behind the image, or completely opaque, showing the color value for that pixel. GIFs feature the ability to contain multiple graphic images inside of a single file
Due to their age, simple nature, and a widespread support, GIFs are widely present on the Internet. According to the HTTP Archive, 33% of all images on the web use the GIF format. Due to their prevalence, understanding how to structure optimize GIF images is an important part of understanding.
The Structure of a GIF Image
To understand how to optimize GIF images, we need to first explore the structure of the image format to identify which areas can be streamlined or optimized.
GIF are composed of a six byte header, identifying the file format and version. A six byte Logic Screen Descriptor follows, specifying the dimensions of the image, number of colors used, and other flags. The next data structure in a GIF file is the Global Color Table. This defines the color values for each of the up to 256 distinct colors which can referenced by the graphics data.
Now we get to how the content of an image is saved inside the GIF format. This happens in the Graphic Image Data sections. If the GIF is an animated GIF it will contain multiple Graphic Image Data sections for the different frames of animation. If it is a static, non-animated GIF, there is only one Graphic Image Data section. Each Graphic Image Data section is composed of a few other pieces of data. Obviously, it contains the graphics data that represent the image or a frame of animation. It can also optionally contain a local color palette that is specific to that piece of image data. This means that frame 1 of an animation can be composed of colors from a palette of 256 colors, and frame 2 can be composed of a different palette of colors. Local color palette data override the palette in the Global Color Table. In fact, the Global Color Table is actually optional, and each Graphic Image Data section can define it own palette. When you are dealing with a static image this is not really necessary, as it doesn’t matter whether the palette information is stored in the Global Image Data of the single Graphic Image Data section. As we will see later, this can be used to optimize animation.
The graphics data inside of a Graphic Image data section is a bitmap of pixel where each pixel value is a reference to the color palette which defines the actual red, green and blue values which represents the color. This pixel data can be sorted and stored in different ways to enable features like interlacing. All of this pixel data is compressed using the Lempel-Ziv-Welch (LZW) lossless data compression algorithm.
GIFs also have a number of other, optional data sections that can be present. Comments are common section, as are so-called "Application Extension" sections. These sections can be used to a variety of application specific information. The commonly implemented Netscape 2.0 Application Extension which enabled the looping of GIF animations. Adobe products store XMP image metadata inside of The Application Extensions. Embedded thumbnails can be stored in Application Extensions. There are also lesser used GIF features which use additional data sections. For example, the Graphic Image Data section can contain other data sections such as a Plain Text Data section, which allows for text to be rendered on top of an image similar to a closed captioning or subtitling system for video files.
GIF Optimization opportunities
Now that I’ve told you way more than you ever wanted to know about the internals of a GIF image, we can think about optimizing. There are several aspects of the GIF image format that create opportunities to reduce file size while retaining image quality:
- The LZW compression algorithm has its roots in the 1970s. While impressive for its time, its performance and compression ratios have been eclipsed by more modern lossless compression algorithms. Using an image format with a better compression.
- Palettes can contain more color definitions than actually used by the image
- The size of palette entries can be inefficient when the image contains less than 128 colors.
- GIF comments, metadata, and (most) Application Extension sections don’t contribution to the rendering of the graphic data. This data can be removed.
Funny enough, the GIF specification even suggests avoiding Application Extensions saying:
[Not using Application Extensions] is recommended in favor of using Application Extensions, which become overhead for all other applications that do not process them.
“Overhead” is just a fancy way of saying wasted bytes!
GIF vs. PNG
PNG images are also a lossless image format that very closely mirrors GIF images. The PNG format was defined 10 years after the GIF format allowing PNG images address many of the shortcomings of GIF images, such as:
- PNG’s DEFLATE algorithm achieves better compression than GIF’s LZW algorithm
- PNG images supports a precompression filter step, which rearranges graphic data before compression to maximize redundancy and thus improve the efficiency of DEFLATE compression. GIF does not have this feature.
- The size of PNG palette entries can be smaller than the corresponding GIF palette entries on images with less than 256 colors.
- PNG’s ancillary data sections support compression allowing their overall size to be reduced.
Additionally, programs that convert from a GIF image to a PNG image, such as gif2png, focus only on converting graphical data. Comments, metadata, embedded thumbnails, Application Extensions, and other non-graphical information present in a GIF are not transferred over into the resulting PNG. In other words, converting from a GIF to a PNG sheds all this "excess baggage" in addition to better compressing the graphical data. All of these factors mean that converting a GIF image to a PNG almost always results in a smaller image.
Bigger as PNG?
PNG images can sometimes be larger than the source GIF image. There are a few reasons for this, some of which can be fixed. Ensure the PNG you convert has an 8bit color depth. PNG supports millions of distinct colors in an image, whereas GIF only supports 256 distinct colors. Since you are converting from a source with a maximum of 256 colors, there is no need to support a larger color depth. If you do, it can needlessly result in a larger file.
It is still possible for GIF images to be smaller than PNG images. This usually only occurs for extremely small images, where the actual graphical data is quite small. For these images, the overhead of various headers and sections inside of the GIF or PNG image contribute to the overall size more so than the graphics data. In this case, very simple GIFs can be smaller than PNGs. In my experience, these extremely small GIF images are used by websites as spacer images or as the response for web services beacons. You shouldn’t be using spacer GIFs at all, and you should be returning HTTP 204 No Content responses instead of using tiny images. In short, if you find any GIFs on your website that are smaller as GIFs than PNGs, you are probably doing something else that is wrong.
The Savings of Converting to PNG
To determine the average savings of converting to PNG, I extract the 2547 GIF images that were recently downloaded by Zoompf’s scanner by users of our free performance scanning service. I then converted these from a GIF to a PNG using Optipng, which conveniently converts to a PNG image and then attempts to losslessly optimize the PNG image in a single step. The median size of the GIF images was 6900 bytes. The median size of the result PNG images was 5546 bytes. This means the median savings of converting all GIFs to PNGs is 21.07%. That’s a pretty awesome result and this aligns nicely with Stoyan’s analysis from 2009. You can download my test results here.
So far we have been talking about static GIFs, but what about animated GIFs? Luckily, the use of annoying, eye bleeding under construction GIFs has past us by (a fact for which I, and all of you, should thank whatever God or gods you pray to, every single day). However animated GIFs are still with us, thanks to the ever present status thumper!
While converting to PNG images provides a simple, easy way to bulk optimize GIFs, what can be done for animated GIFs? PNG does not support animation, so that is not an option.
Before you can optimize a GIF you need to know whether it’s animated or not. Ideally we want an easy way to do this from the command line so we can sort and optimize our GIF images and animations in bulk automatically as part of a script. Luckily the identify command of ImageMagick can help us out. The following:
identify [file] | head -n 1 | grep "] GIF"
This will run identify on the command, and look for the text which indicates this GIF image contains multiple Graphic Image Data sections and thus is part of an animation. Now that we can sort the wheat from the chaff, we can start optimizing animated GIFs.
The list of optimizations that can be applies to animated GIFs is, in many ways, a superset of the optimizations for a static GIF. While you can’t gain the advantage of PNG’s DEFLATE compression algorithm you can:
- Remove metadata, or unused palette entries from a GIF and write a better optimized GIF.
- Combine or generalize local palette information in individual Graphic Image Data sections into the Global Color Table.
- Reuse existing animation frames.
- Minimize what is changing between animation frames, reducing the size different Graphic Image Data sections.
Gifsicle is a great command line tool which can, among other things, perform several of these optimizations automatically. Its free, open source, and easy to use. Because its a command line tool, this Gifsicle can be scripted for bulk optimization operations or bundled into build scripts. To optimize a GIF, this is all:
gifsicle -O2 orig-animation.gif -o new-animation.gif
While Gifsicle can automatically optimize GIFs, it can only do some of the optimizations discussed above with varying degrees of success. For example, Gifsicle does a great job detecting and combining duplicate local palette information into the Global Color Table. It does a good job removing GIF comment sections, but does a poor job detecting and removing Application Extensions, embedded thumbnails, and XMP metadata. It does a reasonable job trying to optimize differences between animation frames. Better optimization can be achieved by manually reviewing the animation to detect frames which can be reused as well as reduce the total changes applied to an image between animation frames.
I don’t want to sound like I’m criticizing Gifsicle. Detecting and applying the optimizations discussed above is not easy to do, let alone automate. Gifsicle is an awesome tool and everyone should use it. I just want to be clear that optimizing Animated GIFs is not as easy or straight forward as stripping meta data from a static GIF. Manual examination or optimization may be required to get the results you expect.
There are numerous aspects of the GIF image format which allow for lossless optimizations to reduce file size while maintaining image quality. Converting to PNG is a nice, universal way to do this. Animated GIFs however, cannot be converted. Instead you can use Gifsicle to automate some optimization and use hand optimization techniques.
Want to see what performance problems your website has? Unoptimzied GIF Image and Unoptimized Animated GIF Image are just 2 of the nearly 400 performance issues Zoompf detects when testing your web applications. You can get a free performance scan of you website now and take a look at our Zoompf WPO product at Zoompf.com today!