How does Google's Page Speed lossless image compression work?

When you run Google's PageSpeed plugin for Firebug/Firefox on a website it will suggest cases where an image can be losslessly compressed, and provide a link to download this smaller image.

For example:

  • Losslessly compressing http://farm3.static.flickr.com/2667/4096993475_80359a672b_s.jpg could save 33.5KiB (85% reduction).
  • Losslessly compressing http://farm2.static.flickr.com/1149/5137875594_28d0e287fb_s.jpg could save 18.5KiB (77% reduction).
  • Losslessly compressing http://cdn.uservoice.com/images/widgets/en/feedback_tab_white.png could save 262B (11% reduction).
  • Losslessly compressing http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/base/images/ui-bg_flat_75_ffffff_40x100.png could save 91B (51% reduction).
  • Losslessly compressing http://www.gravatar.com/avatar/0b1bccebcd4c3c38cb5be805df5e4d42?s=45&d=mm could save 61B (5% reduction).

This applies across both JPG and PNG filetypes (I haven't tested GIF or others.)

Note too the Flickr thumbnails (all those images are 75x75 pixels.) They're some pretty big savings. If this is really so great, why aren't Yahoo applying this server-side to their entire library and reducing their storage and bandwidth loads?

Even Stackoverflow.com stands for some very minor savings:

  • Losslessly compressing http://sstatic.net/stackoverflow/img/sprites.png?v=3 could save 1.7KiB (10% reduction).
  • Losslessly compressing http://sstatic.net/stackoverflow/img/tag-chrome.png could save 11B (1% reduction).

I've seen PageSpeed suggest pretty decent savings on PNG files that I created using Photoshop's 'Save for Web' feature.

So my question is, what changes are they making to the images to reduce them by so much? I'm guessing there are different answers for different filetypes. Is this really lossless for JPGs? And how can they beat Photoshop? Should I be a little suspicious of this?


Solution 1:

If you're really interested in the technical details, check out the source code:

  • png_optimizer.cc
  • jpeg_optimizer.cc
  • webp_optimizer.cc

For PNG files, they use OptiPNG with some trial-and-error approach

// we use these four combinations because different images seem to benefit from
// different parameters and this combination of 4 seems to work best for a large
// set of PNGs from the web.
const PngCompressParams kPngCompressionParams[] = {
  PngCompressParams(PNG_ALL_FILTERS, Z_DEFAULT_STRATEGY),
  PngCompressParams(PNG_ALL_FILTERS, Z_FILTERED),
  PngCompressParams(PNG_FILTER_NONE, Z_DEFAULT_STRATEGY),
  PngCompressParams(PNG_FILTER_NONE, Z_FILTERED)
};

When all four combinations are applied, the smallest result is kept. Simple as that.

(N.B.: The optipng command line tool does that too if you provide -o 2 through -o 7)


For JPEG files, they use jpeglib with the following options:

 JpegCompressionOptions()
     : progressive(false), retain_color_profile(false),
       retain_exif_data(false), lossy(false) {}

Similarly, WEBP is compressed using libwebp with these options:

  WebpConfiguration()
      : lossless(true), quality(100), method(3), target_size(0),
        alpha_compression(0), alpha_filtering(1), alpha_quality(100) {}

There is also image_converter.cc which is used to losslessly convert to the smallest format.

Solution 2:

I use jpegoptim to optimize JPG files and optipng to optimize PNG files.

If you're on bash, the command to losslessly optimize all JPGs in a directory (recursively) is:

find /path/to/jpgs/ -type f -name "*.jpg" -exec jpegoptim --strip-all {} \;

You can add -m[%] to jpegoptim to lossy compress JPG images, for example:

 find /path/to/jpgs/ -type f -name "*.jpg" -exec jpegoptim -m70 --strip-all {} \;

To optimize all PNGs in a directory:

find /path/to/pngs/ -type f -name "*.png" -exec optipng -o2 {} \;

-o2 is the default optimization level, you can change this from o2 to o7. Notice that higher optimization level means longer processing time.

Solution 3:

Take a look at http://code.google.com/speed/page-speed/docs/payload.html#CompressImages which describes some of the techniques/tools.

Solution 4:

It's a matter of trading encoder's CPU time for compression efficiency. Compression is a search for shorter representations, and if you search harder, you'll find shorter ones.

There is also a matter of using image format capabilities to the fullest, e.g. PNG8+a instead of PNG24+a, optimized Huffman tables in JPEG, etc.

Photoshop doesn't really try hard to do that when saving images for the web, so it's not surprising that any tool beats it.

See

  • ImageOptim (lossless) and
  • ImageAlpha (lossy) for smaller PNG files (high-level description how it works) and
  • JPEGmini/MozJPEG (lossy) for better JPEG compressor.