March 23, 2010

Optimizing Gradients

Gradient backgrounds are a common visual element on modern websites. And while you can use browser specific CSS extensions to directly create gradient backgrounds with pure CSS the much more common method is to use an image. Traditionally, when a web designer wants to create a gradient to a webpage, they use a program like Photoshop or The Gimp to create a small image containing the gradient they want. They then use CSS to set this image as the background for a specific element and then use repeat-x or repeat-y to spread the gradient image along the entire length of the element. This provides us with the chance for a new performance optimization technique!

Consider the image above that a Sven, a long time Zoompf user, sent in. This image is 38 pixels wide and 91 pixels tall. As you can see there is a gradient that goes from dark gray at the top of the image to white at the bottom. This image is used on the website to provide a background gradient for section titles. The website’s CSS uses the repeat-x directive to fill the section title along the X-axis with the gradient. Which raises the question “Why is the image 39 pixels wide?” After all, the change in colors is along the Y-axis (from the top of the image to the bottom). The width of the image is meaningless. It adds nothing to the image. If you were to open this image in a program like Photoshop you would see that every pixel has the same color as the pixel to it’s left or right. It cannot be any other way. Otherwise when the image is repeated one after another along the X-axis you would see spots or seams where the colors were different. Since CSS is used to repeat this image in the X-axis direction, there is no reason for the image to be larger than 1 pixel wide! Converting the 38×91 pixel image to a 1×91 reduces the size of the file by over 65%!

Let’s try a real example. Consider this gradient from Yahoo. This image is actually a sprite of several different gradients! It is 5 pixels wide and 3302 pixels tall and is 3466 bytes. Again, we can confirm that the extra 4 pixels in width provide no value. All the pixels in this image have the same color value as the pixels to the right or left. Using Photoshop, we cropped the image to be 1×3302 pixels with a size of 1920 bytes. This is a savings of 45% with absolutely no loss to image quality or user experience!

We performed this optimization on a sample of 300 or so gradient images. On average we reduced file size by 30-70%. PNG images tended to see an improvement of 10-30%.

Browser Performance Impact

Are there any negative effects to using gradient images that are only 1 pixel in length along the axis they repeat? This is what Sven wanted to know when he emailed the image. Consider an image that’s 32 x 300 images. It is repeated along the X-axis using CSS and is used as a background for a <DIV> that is 96 pixels wide. To “draw” an image on the screen, the fundamental operation the browser is doing is copying the bytes of the image into the buffer of bytes that display the screen. That means to draw the gradient background the browser has to copy the bytes of the 32 x 300 pixel image into the video memory 3 times (because 3 times 32 is 96). Consider if we had a 1 x 100 pixel image. The browser has to copy the bytes of the 1 x 300 pixel image into the video memory 96 times (because 1 times 96 is 96). So, it would seem that using a 1 x 100 pixel image is 32 times slower than using a 32 x 100 pixel image. Remember we aren’t talking about browser repaint or reflow events (where the browser has to recalculate where all the text and images goes and then redraw). We are talking purely about how quickly the computer can draw an image.

It sounds like we might have a performance problem.

Only we don’t. Computers can move data around very quickly. We are talking nanoseconds (10^-9). Meanwhile, transferring data over Internet connections is typically measured in millisecond or microseconds (10 ^ -3 or 10 ^ -6). So even though smaller images may make the browser do more work, even 32 times more work, the difference is so infinitesimal that they are not noticeable to the user. The time saving you will get by reducing the amount of data you have to send over the slow network however is impactful and beneficial.

Conclusions

The fact that gradients using images rely on CSS to repeat the image allows us to reduce the width or height of the gradient image without any visual difference. Performance is improved because we have reduced the size of the image. This technique can be applied to all images that are used as gradients. If a gradient image repeats along the X-axis it should only be 1 pixel wide. If a gradient image repeats along the Y-axis it should only be 1 pixel tall. As we saw the the example gradient from Yahoo, even gradient images that are already quite small in terms of dimensions can drastically reduce their size even further by reducing the width or height to 1 pixel.

Want to see what performance problems your website has? Oversized Gradient Image is just one of the 300+ web performance issues Zoompf detects when scanning your web applications. Get your instant free web performance assessment at Zoompf.com today!

February 4, 2010

Choosing PNG8 Candidate Images

Have you heard about PNG8 yet? No? Well, PNG8 is a PNG image that is used an indexed palette of 256 colors instead of a true color PNG which can support several million different colors. There has already been a number of excellent articles and blog posts written about PNG8. These articles have discussed things about PNG8 such as its benefits, how to create PNG8, and using them across different browsers.

But this article isn’t about any of that.

This article is about how to choose PNG images that are good candidates for converting to PNG8. Historically this has not been an easy or a straight forward decision.

We already know that PNG images can be optimized. Crunching PNGs (using pngcrush, or optipng, etc) to reduce their size is a lossless operation. This process removes unnecessary data chucks like comments and recompresses the DEFLATE streams using tweaked settings. When optimizing images by crunching them none of the image data changes. The number of colors in the image does not change and their color values and hues are exactly the same.

But converting a true color PNG to a PNG8 image is a lossly operation. You lose data. PNG8 images can have at most 256 distinct colors while true color PNGs can have several million. Because of this not all PNG images should be converted to PNG8. Some images look absolutely horrible when converted. Working with our clients we have created two guidelines to evaluate whether a PNG image can be converted to PNG8 without any noticeable loss in quality. This is a easier and scalable solution than converting all of the PNG images on your website and then manually verifying the resulting PNG8 images are acceptable.

Guideline #1: Number of Colors

To understand the impact of limiting a PNG image to only 256 distinct colors we must understand how many colors PNG images typically have. Converting to PNG8 can quite significantly reduce the number of colors in the image. A PNG8 version of a true color PNG image with 1,000 distinct colors has 25% as many colors of the original image. A PNG8 version of a true color PNG image with 10,000 colors has only 2.5% as many colors of the original image! So the number of distinct colors in the image (and thus the number of distinct colors you are destroying when converting to PNG8) has a huge impact on how acceptable the resulting PNG8 will be. In plain terms the PNG8 version of a 10,000 color PNG image will look worse than the PNG8 version of a 1,000 color PNG image.

While true color PNGs can have several million distinct colors they rarely do. (If you have a PNG image that has even a few tens of thousands of colors it should probably be saved as a JPEG instead). Examining a sample set of PNG images we found that PNGs tend to have several thousand distinct colors. We also have found that images containing only a few thousand colors will easily convert to a PNG8 image without any noticeable loss in quality. Consider the Zoompf logo:

The Zoompf logo is a true color PNG image consisting of 1999 distinct colors. That sounds like a lot. Let’s convert this to a PNG8 image using pngquant. Here is the original logo and the PNG8 version of the logo side by side for comparison. The original logo is on the top and new PNG8 version is on the bottom.

Wow, They look virtually identical even though the PNG8 version’s file size is over 50% smaller and uses 87% less colors than the original. Only if you zoom in very close do you start to see some differences. The greens are slightly lighter and the gray in the swoosh lines are a little different.

We have found that images will less than 2500-3000 distinct colors tend to provide the best trade off in terms of maximum reduction in file size without any noticeable difference to quality. This is purely subjective. There are some true color PNG images with 6,000 colors or more that look just fine when converted to PNG8. You should experiment and see what works best for you.

Guideline #2: Image Dimensions

Another factor is the dimensions of the image. Small images, even if they have more than 7,500 distinct colors, convert to PNG8 with not visible loss of quality. This is because your brain has trouble detecting some many similar colors in such a small area. Consider this true color PNG image of a cat.

This picture consists of 8,853 distinct colors. That’s an enormous amount when you realize this image has only 9900 pixels total! Almost every pixel is a completely unique color. That’s tons of distinct colors given the area they are displayed in. Again we use pngquant to convert this cat image into a PNG8 image and compare it to the original. The original image is on the top and PNG8 version is on the bottom.

Again, they look virtually identical even though the PNG8 version’s file size is over 50% smaller and uses 97.2% less colors than the original. As if the logo, only if you zoom in very close you can start to see the differences between the original image and the PNG8 version.

We have found that images less than 100 pixels by 100 pixels, or an image whose area is less than 10,000 pixels can easily be converted into a PNG8 without any noticeable difference in quality. This is a purely subjective guideline. Some larger true color PNG images look just fine when converted to PNG8.

Using the Guidelines

These guidelines can be used separately. A PNG image does not have to be both small and not using many colors to be a good candidate for converting to PNG8. As as example, Graphviz, a program that generates node-and-edge style graphs, regularly produces images that are thousands of pixels wide by thousands of pixels tall. This would violate our image area guideline. However these images usually contain a few hundred colors. This satisfies our color count guideline. Sure enough, converting the output of Graphviz to PNG8 saves a lot of space with no perceivable loss of quality.

PNG8 and CSS Sprites

A lot of times people want to combine PNG8′s advantage of a very small file size with CSS Sprite’s’ advantage of reducing the number of HTTP requests. At first glance this makes a lot of sense. Individual CSS background images inside of the sprite are often small images, fitting our image dimensions guideline. Also CSS background images are often icon-style images used on buttons, toolbars, etc. This means each individual image tends to have only several dozen distinct colors fitting our image colors guideline.

Unfortunately this is looking at the trees instead of the forest. That’s because a CSS Sprite saved as a PNG8 image has to use only 256 distinct colors for all the sub-images inside the sprite. So while each sub-image that makes up the CSS Sprite might look fine as an individual PNG8 image (each with its own 256 color palette) all the sub-images together in a single PNG8 CSS Sprite using a single common 256 color palette could not. This is especially true with gradients and othe graphics that use different shades for color transitions. In fact, Stoyan pointed out a recent article talked about how converting a CSS Sprite to PNG8 caused a very noticeable loss in quality. The solution was the hand edit the PNG8′s 256 color palette to preserve as many shades of the gradient as possible to improve quality.

Zoompf Color Counter

Since so much savings can occur from converting from PNG24 to PNG8 where appropriate, developers are left with the challenge of trying to quickly find candidate images. While Zoompf’s free web performance scanning service will detect candidate images developers will also want to test images that are not yet uploaded or test images on a website that is not yet in production. To help developers, Zoompf has released the Zoompf Color Counter.

Screen shot of Zoompf's Color Counter program

Zoompf Color Counter is a Windows program that will analyze an image and tell the user how many distinct colors it has. Simply open an image inside Zoompf Color Counter or drag and drop an image on top of Zoompf Color Counter to learn the number of distinct colors. Download Zoompf Color.

Summary

There are a lot of blog posts and articles on the Internet about how converting true color PNG images into PNG8 images is an excellent optimization technique. However knowing how to choose true color PNG images that are good candidates to convert to PNG8 can be difficult and time consuming. In this post we provide 2 guidelines to help:

  1. Images with less than 2500 to 3000 distinct colors can usually be converted to PNG8 without any noticeable differences
  2. Image less than 100 pixels by 100 pixels (or an image whose area is less than 10,000 pixels) can usually be converted to PNG8 without any noticeable differences.

In addition we have release Zoompf Color Counter to help developers find candidate images. Remember that converting to PNG8 is a lossly process. How much loss is tolerable will vary from person to person. You should use our guidelines but also experiment to see if you will tolerate more. Finally, be careful converting your CSS Sprites image into PNG8, especially if you use images with gradients.

Want to see what performance problems your website has? Finding Candidate PNG8 Images based on color count or image dimensions are just two of the 300+ performance issues Zoompf detects when checking your web applications. You can sign up for a free mini web performance assessment at Zoompf.com today!

January 5, 2010

Top PNG Optimizers Don't Use zlib

Oleg Kikin has an interesting chart comparing the performance multiple different PNG optimizing tools. The tools tested are:

Go take a look at the PNG comparison chart. I can wait.

So what do these results mean? Well I believe it shows how far image optimization has come in the last 2 years. Tools that just manipulate the parameters for the stock DEFLATE compressor code that is included in the zlib compression library and remove extra PNG chunks no longer produce the smallest optimized image. PNGOut and AdvanceCOMP produce the smallest PNGs because they use custom DEFLATE compressors that achieve better compression than zlib’s implementation. PNGOut’s deflate compressor was written from scratch and AdvanceCOMP uses the custom DEFLATE compressor written for 7Zip. We’ve talked about 7Zip and DEFLATE before in the Rezipping Web Resources for Fun and Profit post. I used 7Zip for my rezipping work because it’s optimized DEFLATE compressor compresses data better than the DEFLATE compressor in zlib. This in turn produces smaller ZIP files but the logic applies to image formats that use DEFLATE.

Unfortunately I cannot find any information about the command line options Oleg used with each tool.

It is interesting to note the difference between Smush.it and PNGCrush. According to Smush.it’s information page it is using PNGcrush under the covers. Any difference in the output of Smush.it and PNGCrush is entirely from the command line options that we know nothing about. It would be possible to reverse engineer what Smush.it is doing by using the service and comparing the output. I image they are using the -m option instead of the -brute option to reduce the number of rounds of PNGCrush and improve the response speed of the Smush.it web service.

What we really need is a web service that accepts images and tries several different optimization tools. Smush.it has hinted at this for a while now in their FAQ but improvements to the tool seem to have stalled since Yahoo took it over (to say nothing of the un-sexy-fying of the Smush.it UI). Hopefully something like this will appear.

Want to see what performance problems you have? Unoptimized PNG images are just one of the 200+ performance issues Zoompf detects while assessing your web applications. You can sign up for a free mini web performance assessment at Zoompf.com today!