With thanks to: Kornel Lesiński, Estelle Weyl, Jeremy Wagner, Tim Kadlec, Nolan O’Brien, Pat Meenan, Kristofer Baxter, Henri Helvetica, Houssein Djirdeh, Una Kravets, Elle Osmani and Ilya Grigorik for their help and reviews.
We should all be automating our image compression.
Image optimization should be automated. It’s easy to forget, best practices change, and content that doesn’t go through a build pipeline can easily slip. To automate: Use imagemin or libvips for your build process. Many alternatives exist.
Most CDNs (e.g. Akamai) and third-party solutions like Cloudinary, imgix, Fastly’s Image Optimizer, Instart Logic’s SmartVision or ImageOptim API offer comprehensive automated image optimization solutions.
The amount of time you’ll spend reading blog posts and tweaking your configuration is greater than the monthly fee for a service (Cloudinary has a free tier). If you don’t want to outsource this work for cost or latency concerns, the open-source options above are solid. Projects like Imageflow or Thumbor enable self-hosted alternatives.
Everyone should be compressing their images efficiently.
At minimum: use ImageOptim. It can significantly reduce the size of images while preserving visual quality. Windows and Linux alternatives are also available.
More specifically: run your JPEGs through MozJPEG (q=80 or lower is fine for web content) and consider Progressive JPEG support, PNGs through pngquant and SVGs through SVGO. Explicitly strip out metadata (--strip for pngquant) to avoid bloat. Instead of crazy huge animated GIFs, deliver H.264 videos (or WebM for Chrome, Firefox and Opera)! If you can’t at least use Giflossy. If you can spare the extra CPU cycles, need higher-than-web-average quality and are okay with slow encode times: try Guetzli.
Some browsers advertise support for image formats via the Accept request header. This can be used to conditionally serve formats: e.g. lossy WebP for Blink-based browsers like Chrome and fallbacks like JPEG/PNG for other browsers.
There’s always more you can do. Tools exists to generate and serve srcset breakpoints. Resource selection can be automated in Blink-based browsers with client-hints and you can ship fewer bytes to users who opted into ‘data savings’ in-browser by heeding the Save-Data hint.
The smaller in file-size you can make your images, the better a network experience you can offer your users – especially on mobile. In this write-up, we’ll look at ways to reduce image size through modern compression techniques with minimal impact to quality.
Images are still the number one cause of bloat on the web.
Images take up massive amounts of internet bandwidth because they often have large file sizes. According to the HTTP Archive, 60% of the data transferred to fetch a web page is images composed of JPEGs, PNGs and GIFs. As of July 2017, images accounted for 1.7MB of the content loaded for the 3.0MB average site.
Per Tammy Everts, adding images to a page or making existing images larger have been proven to increase conversion rates. It’s unlikely that images will go away and so investing in an efficient compression strategy to minimize bloat becomes important.
Per Soasta/Google research from 2016, images were the 2nd highest predictor of conversions with the best pages having 38% fewer images.
Image optimization consists of different measures that can reduce the file size of your images. It ultimately depends on what visual fidelity your images require.
Image optimization: Choose the right format, compress carefully and prioritize critical images over those that can be lazy-loaded.
Common image optimizations include compression, responsively serving them down based on screen size using /, and resizing them to reduce image decode costs.
Per the HTTP Archive, per-image savings at the 95th percentile (looking at the Cumulative Distribution Function) are 30KB!
There’s plenty of room for us to collectively optimize images better.
ImageOptim is free, reduces image size through modern compression techniques and by stripping unnecessary EXIF meta-data.
If you’re a designer, there’s also an ImageOptim plugin for Sketch that will optimize your assets on export. I’ve found it a huge time saver.
Perform a site audit through WebPageTest.org and it will highlight opportunities to better optimize your images (see ‘Compress Images’).
The ‘Compress Images’ section of a WebPageTest report lists images that can be compressed more efficiently and the estimated file-size savings of doing so.
Lighthouse audits for performance best practices. It includes audits for image optimisation and can make suggestions for images that could be compressed further or point out images that are off-screen and could be lazy-loaded.
As of Chrome 60, Lighthouse now powers the Audits panel in the Chrome DevTools:
Lighthouse can audit for Web Performance, Best Practices and Progressive Web App features.
You may also be familiar of other performance auditing tools like PageSpeed Insights or Website Speed Test by Cloudinary which includes a detailed image analysis audit.
As Ilya Grigorik notes in his excellent image optimization guide, the ‘right format’ for an image is a combination of desired visual results and functional requirements. Are you working with Raster or Vector images?
Raster graphics represent images by encoding the values of each pixel within a rectangular grid of pixels. They are not resolution or zoom independent. WebP or widely supported formats like JPEG or PNG handle these graphics well where photorealism is a necessity. Guetzli, MozJPEG and other ideas we’ve discussed apply well to raster graphics.
Vector graphics use points, lines and polygons to represent images and formats using simple geometric shapes (e.g. logos) offering a high-resolution and zoom like SVG handle this use case better.
The wrong format can cost you. The logical flow for choosing the right format can be fraught with peril so experiment with the savings other formats can afford with care.
Jeremy Wagner has covered trade-offs worth considering when evaluating formats in his image optimization talks.
The JPEG may well be the world’s most widely used image format. As noted earlier, 45% of the images seen on sites crawled by HTTP Archive are JPEGs. Your phone, your digital SLR, that old webcam – everything pretty much supports this codec. It’s also very old, dating all the way back to 1992 when it was first released. In that time, there’s been an immense body of research done attempting to improve what it offers.
JPEG is a lossy compression algorithm that discards information in order to save space and many of the efforts that came after it attempted to preserve visual fidelity while keeping file sizes as small as possible.
What image quality is acceptable for your use-case?
Formats like JPEG are best suited for photographs or images with a number of color regions. Most optimisation tools will allow you to set what level of compression you’re happy with; higher compression reduces file size but can introduce artifacts, halos or blocky degrading.
JPEG: Perceivable JPEG compression artifacts can increase as we shift from best quality to lowest. Note that image quality scores in one tool can be very different to quality scores in another.
When choosing what quality setting to opt for, consider what quality bucket your images fall into:
Best quality – when quality matters more than bandwidth. This may be because the image has high prominence in your design or is displayed at full resolution.
Good quality – when you care about shipping smaller file-sizes, but don’t want to negatively impact image quality too much. Users still care about some level of image quality.
Low quality – when you care enough about bandwidth that image degradation is okay. These images are suitable for spotty/poor network conditions.
Lowest quality – bandwidth savings are paramount. Users want a decent experience but will accept a pretty degraded experience for the benefit of pages loading more quickly.
Next, let’s talk about JPEG’s compression modes as these can have a large impact on perceived performance.
The JPEG image format has a number of different compression modes. Three popular modes are baseline (sequential), Progressive JPEG (PJPEG) and lossless.
How do baseline (or sequential) JPEGs and Progressive JPEGs differ?
Baseline JPEGs (the default for most image editing and optimisation tools) are encoded and decoded in a relatively simple manner: top to bottom. When baseline JPEGs load on slow or spotty connections, users see the top of the image with more of it revealed as the image loads. Lossless JPEGs are similar but have a smaller compression ratio.
Baseline JPEGs load top to bottom while Progressive JPEGs load from blurry to sharp.
Progressive JPEGs divide the image into a number of scans. The first scan shows the image in a blurry or low-quality setting and following scans improve image quality. Think of this as ‘progressively’ refining it. Each ‘scan’ of an image adds an increasing level of detail. When combined this creates a full-quality image.
Baseline JPEGs load images from top to bottom. PJPEGs load from low-resolution (blurry) to high-resolution. Pat Meenan wrote an interactive tool to test out and learn about Progressive JPEG scans too.
Lossless JPEG optimization can be achieved by removing EXIF data added by digital cameras or editors, optimizing an image’s Huffman tables, or rescanning the image. Tools like jpegtran achieve lossless compression by rearranging the compressed data without image degradation. jpegrescan, jpegoptim and mozjpeg (which we’ll cover shortly) also support lossless JPEG compression.
The ability for PJPEGs to offer low-resolution ‘previews’ of an image as it loads improves perceived performance – users can feel like the image is loading faster compared to adaptive images.
On slower 3G connections, this allows users to see (roughly) what’s in an image when only part of the file has been received and make a call on whether to wait for it to fully load. This can be more pleasant than the top-to-bottom display of images offered by baseline JPEGs.
In 2015, Facebook switched to PJPEG (for their iOS app) and saw a 10% reduction in data usage. They were able to show a good quality image 15% faster than previously, optimising perceived loading time, as shown in the figure above.
PJPEGs can improve compression, consuming 2-10% less bandwidth compared to baseline/simple JPEGs for images over 10KB. Their higher compression ratio is thanks to each scan in the JPEG being able to have its own dedicated optional Huffman table. Modern JPEG encoders (e.g. libjpeg-turbo, MozJPEG, etc.) take advantage of PJPEG’s flexibility to pack data better.
Twitter.com ships Progressive JPEGs with a baseline of quality of 85%. They measured user perceived latency (time to first scan and overall load time) and found overall, PJPEGs were competitive at addressing their requirements for low file-sizes, acceptable transcode and decode times.
Facebook ships Progressive JPEGs for their iOS app. They found it reduced data usage by 10% and enabled them to show a good quality image 15% faster.
Yelp switched to Progressive JPEGs and found it was in part responsible for ~4.5% of their image size reduction savings. They also saved an extra 13.8% using MozJPEG.
Many other image-heavy sites, like Pinterest and even entertainment platforms such as Leon Casino, also use Progressive JPEGs in production to keep visuals sharp without slowing down the user experience.
Pinterest’s JPEGs are all progressively encoded. This optimizes the user experience by loading them each scan-by-scan.
PJPEGs can be slower to decode than baseline JPEGs – sometimes taking 3× as long. On desktop machines with powerful CPUs this can be less of a concern, but is on underpowered mobile devices with limited resources. Displaying incomplete layers takes work as you’re basically decoding the image multiple times. These multiple passes can eat CPU cycles.
Progressive JPEGs are also not always smaller. For very small images (like thumbnails), progressive JPEGs can be larger than their baseline counterparts. However for such small thumbnails, progressive rendering might not really offer as much value.
This means that when deciding whether or not to ship PJPEGs, you’ll need to experiment and find the right balance of file-size, network latency and use of CPU cycles.
Note: PJPEGs (and all JPEGs) can sometimes be hardware decodable on mobile devices. It doesn’t improve on RAM impact, but it can negate some of the CPU concerns. Not all Android devices have hardware-acceleration support, but high end devices do, and so do all iOS devices.
Some users may consider progressive loading to be a disadvantage as it can become hard to tell when an image has completed loading. As this can vary heavily per audience, evaluate what makes sense for your own users.
Tools and libraries like ImageMagick, libjpeg, jpegtran, jpeg-recompress and imagemin support exporting Progressive JPEGs. If you have an existing image optimization pipeline, there’s a good likelihood that adding progressive loading support could be straight-forward:
Most image editing tools save images as Baseline JPEG files by default.
Most image editing tools save images as Baseline JPEG files by default. You can save any image you create in Photoshop as a Progressive JPEG by going to File -> Export -> Save for Web (legacy) and then clicking on the Progressive option. Sketch also supports exporting Progressive JPEGs – export as JPG and check the ‘Progressive’ checkbox while saving your images.
Our eyes are more forgiving to loss of color detail in an image (chroma) than they are luminance (or luma for short – a measure of brightness). Chroma subsampling is a form of compression that reduces the precision of color in a signal in favor of luma. This reduces file size, in some cases by up to 15-17%, without adversely affecting image quality and is an option available for JPEG images. Subsampling can also reduce image memory usage.
As contrast is responsible for forming shapes that we see in an image, luma, which defines it, is pretty important. Older or filtered black and white photos may not contain color, but thanks to luma, they can be just as detailed as their color counterparts. Chroma (color) has less of an impact on visual perception.
JPEG supports a number of different subsampling types: none, horizontal and horizontal and vertical. This diagram is from JPEGs for the horseshoe crabs by Frédéric Kayser.
There are a number of common samples discussed when talking about subsampling. Generally, 4:4:4, 4:2:2 and 4:2:0. But what do these represent? Let’s say a subsample takes the format A:B:C. A is the number of pixels in a row and for JPEGs this is usually 4. B represents the amount of color in the first row and C the color in the second.
4:4:4 has no compression, so color and luma are transported completely.
4:2:2 has half sampling horizontally and full sampling vertically.
4:2:0 samples colors out of half the first row’s pixels and ignores the second row.
By reducing pixels in our chroma components, it’s possible to reduce the size of color components significantly, ultimately reducing byte size.
Chrome subsampling configurations for a JPEG at quality 80.
Chroma subsampling is worth considering for most types of image. It does have some notable exceptions: as subsampling relies on limitations in our eyes, it is not great for compressing images where color detail may be as important as luminance (e.g. medical images).
Images containing typefaces can also suffer as poor subsampling of text can decrease its legibility. Sharper edges are harder to compress with JPEG as it was designed to better handle photographic scenes with softer transitions.
Understanding JPEG recommends sticking with a subsampling of 4:4:4 (1×1) when working with images containing text.
Trivia: The exact method of Chroma subsampling wasn’t specified in the JPEG specification, so different decoders handle it differently. MozJPEG and libjpeg-turbo use the same scaling method. Older versions of libjpeg use a different method that adds ringing artifacts in colors.
For a further read on Chroma Subsampling, see Why aren’t your images using Chroma subsampling?.
Here’s the current state of image formats on the web:
tl;dr – there’s a lot of fragmentation. We often need to conditionally serve different formats to different browsers to take advantage of anything modern.
Different modern image formats (and optimizers) used to demonstrate what is possible at a target file-size of 26KB. We can compare quality using SSIM (structural similarity) or Butteraugli, which we’ll cover in more detail later.
JPEG 2000 (2000) – an improvement to JPEG switching from a discrete cosine based transform to a wavelet-based method. Browser support: Safari desktop + iOS
JPEG XR (2009) – alternative to JPEG and JPEG 2000 supporting HDR and wide gamut color spaces. Produces smaller files than JPEG at slightly slower encode/decode speeds. Browser support: Edge, IE.
WebP (2010) – block-prediction based format by Google with support for lossy and lossless compression. Offers byte savings associated with JPEG and transparency support byte-heavy PNGs are often used for. Lacks chroma subsampling configuration and progressive loading. Decode times are also slower than JPEG decoding. Browser support: Chrome, Opera. Experimented with by Safari and Firefox.
FLIF (2015) – lossless image format claiming to outperform PNG, lossless WebP, lossless BPG and lossless JPEG 2000 based on compression ratio. Browser support: none. Note that there is a JS in-browser decoder.
HEIF and BPG. From a compression perspective, they’re the same but have a different wrapper:
BPG (2015) – intended to be more compression-efficient replacement for JPEG, based on HEVC (High Efficiency Video Coding). Appears to offer better file size compared to MozJPEG and WebP. Unlikely to get broad traction due to licensing issues. Browser support: none. Note that there is a JS in-browser decoder.
HEIF (2015) – format for images and image sequences for storing HEVC-encoded images with constrained inter-prediction applied. Apple announced at WWDC they would explore switching to HEIF over JPEG for iOS, citing up to 2× savings on file-size. Browser support: None at the time of writing. Eventually, Safari desktop and iOS 11
If you’re more visual, you might appreciate one of these visual comparison tools for some of the above.
So, browser support is fragmented and if you wish to take advantage of any of the above you’ll likely need to conditionally serve fallbacks for each of your target browsers. At Google, we’ve seen some promise with WebP so we’ll dive into it in more depth shortly.
You can also serve image formats (e.g. WebP, JPEG 2000) with a .jpg extension (or any other) as the browser can render an image it can decide the media type. This allows for server-side content-type negotiation to decide which image to send without needing to change the HTML at all. Services like Instart Logic use this approach when delivering images to their customers.
Next, let’s talk about an option for when you can’t conditionally serve different image formats: optimising JPEG encoders.
Modern JPEG encoders attempt to produce smaller, higher fidelity JPEG files while maintaining compatibility with existing browsers and image processing apps. They avoid the need to introduce new image formats or changes in the ecosystem in order for compression gains to be possible. Two such encoders are MozJPEG and Guetzli.
tl;dr Which optimising JPEG Encoder should you use?
General web assets: MozJPEG
Quality is your key concern and you don’t mind long encode times: use Guetzli
If you need configurability:
JPEGRecompress (which uses MozJPEG under the hood)
JPEGMini. It’s similar to Guetzli – chooses best quality automatically. It’s not as technically sophisticated as Guetzli, but it’s faster, and aims at quality range more suitable for the web.
ImageOptim API (with free online interface here) – it’s unique in its handling of color. You can choose color quality separately from overall quality. It automatically chooses chroma subsampling level to preserve high-res colors in screenshots, but avoid waste bytes on smooth colors in natural photos.
Mozilla offers a modernized JPEG encoder in the form of MozJPEG. It claims to shave up to 10% off JPEG files. Files compressed with MozJPEG work cross-browser and some of its features include progressive scan optimization, trellis quantization (discarding details that compress the least) and a few decent quantization table presets that help create smoother High-DPI images (although this is possible with ImageMagick if you’re willing to wade through XML configurations).
MozJPEG is supported in both ImageOptim and there’s a relatively reliable configurable imagemin plugin for it. Here’s a sample implementation with Gulp:
MozJPEG: A comparison of file-sizes and visual similarity scores at different qualities.
I used jpeg-compress from the jpeg-archive project to calculate the SSIM (The Structural Similarity) scores for a source image. SSIM is a method for measuring the similarity between two images, where the SSIM score is a quality measure of one image given the other is considered ‘perfect’.
In my experience, MozJPEG is a good option for compressing images for the web at a high visual quality while delivering reductions on file size. For small to medium sized images, I found MozJPEG (at quality=80-85) led to 30-40% savings on file size while maintaining acceptable SSIM, offering a 5-6% improvement on jpeg-turbo. It does come with a slower encoding cost than baseline JPEG, but you may not find this a show stopper.
Guetzli is a promising, if slow, perceptual JPEG encoder from Google that tries to find the smallest JPEG that is perceptually indistinguishable from the original to the human eye. It performs a sequence of experiments that produces a proposal for the final JPEG, accounting for the psychovisual error of each proposal. Out of these, it selects the highest-scoring proposal as the final output.
To measure the differences between images, Guetzli uses Butteraugli, a model for measuring image difference based on human perception (discussed below). Guetzli can take into account a few properties of vision that other JPEG encoders do not. For example, there is a relationship between the amount of green light seen and sensitivity to blue, so changes in blue in the vicinity of green can be encoded a little less precisely.
Guetzli claims to achieve a 20-30% reduction in data-size for images for a given Butteraugli score compared to other compressors. A large caveat to using Guetzli is that it is extremely, extremely slow and is currently only suitable for static content. From the README, we can note Guetzli requires a large amount of memory – it can take 1 minute + 200MB RAM per megapixel. There’s a good thread on real-world experience with Guetzli in this GitHub thread. It can be ideal for when you’re optimizing images as part of a build process for a static site but less so when performed on demand.
Tools like ImageOptim support Guetzli optimization (in the latest versions).
It took almost seven minutes (and high CPU usage) to encode 3 x 3MP images using Guetzli with varied savings. For archiving higher-resolution photos, I could see this offering some value.
Guetzli: A comparison of file sizes and visual similarity scores at different qualities.
While compressing an image with Guetzli is very (very) time-consuming and will make your fans spin, for larger images, it is worth it. I have seen a number of examples where it saved anywhere up to 40% on file size while maintaining visual fidelity. This made it perfect for archiving photos. On small to medium sized images, I have still seen some savings (in the 10-15KB range) but they were not quite as well pronounced. Guetzli can introduce more liquify-esque distortion on smaller images while compressing.
You may also be interested in Eric Portis research comparing Guetzli to Cloudinary’s auto-compression for a different data point on effectiveness.
Comparing different JPEG encoders is complex – one needs to compare both the quality and fidelity of the compressed image as well as the final size. As image compression expert Kornel Lesiński notes, benchmarking one but not both of these aspects could lead to invalid conclusions.
How does Guetzli compare to MozJPEG? – Kornel’s take:
Guetzli is tuned for higher-quality images (butteraugli is said to be best for q=90+, MozJPEG’s sweet spot is around q=75)
Guetzli is much slower to compress (both produce standard JPEGs, so decoding is fast as usual)
MozJPEG doesn’t automagically pick quality setting, but you can find optimal quality using an external tool, e.g. jpeg-archive
A number of methods exist for determining if compressed images are visually similar or perceivably similar to their sources. Image quality studies often use methods like SSIM (structural similarity). Guetzli however optimizes for Butteraugli.
Butteraugli is a project by Google that estimates the point when a person may notice visual image degradation (the psychovisual similarity) of two images. It gives a score for the images that is reliable in the domain of barely noticeable differences. Butteraugli not only gives a scalar score, but also computes a spatial map of the level of differences. While SSIM looks at the aggregate of errors from an image, Butteraugli looks at the worst part.
Above is an example that used Butteraugli to find the minimal JPEG quality threshold before visual degradation was bad enough for a user to notice something wasn’t clear. It resulted in a 65% reduction in total file size.
In practice, you would define a target goal for visual quality and then run through a number of different image optimisation strategies, looking at your Butteraugli scores, before choosing something that fits the best balance of file- size and level.
All in all, it took me about 30m to setup Butteraugli locally after installing Bazel and getting a build of the C++ sources to correctly compile on my Mac. Using it is then relatively straight-forward: specify the two images to compare (a source and compressed version) and it will give you a score to work from.
How does Butteraugli differ to other ways of comparing visual similarity?
This comment from a Guetzli project member suggests Guetzli scores best on Butteraugli, worst on SSIM and MozJPEG scores about as well on both. This is in line with the research I’ve put into my own image optimisation strategy. I run Butteraugli and a Node module like img-ssim over images comparing the source to their SSIM scores before/after Guetzli and MozJPEG.
Combining encoders?
For larger images, I found combining Guetzli with lossless compression in MozJPEG (jpegtran, not cjpeg to avoid throwing away the work done by Guetzli) can lead to a further 10-15% decrease in filesize (55% overall) with only very minor decreases in SSIM. This is something I would caution requires experimentation and analysis but has also been tried by others in the field like Ariya Hidayat with promising results.
MozJPEG is a beginner-friendly encoder for web assets that is relatively fast and produces good-quality images. As Guetzli is resource-intensive and works best on larger, higher-quality images, it’s an option I would reserve for intermediate to advanced users.
WebP is a recent image format from Google aiming to offer lower file-sizes for lossless and lossy compression at an acceptable visual quality. It includes support for alpha-channel transparency and animation.
In the last year, WebP gained a few percent over compression-wise in lossy and lossless modes and speed-wise the algorithm got twice as fast with a 10% improvement in decompression. WebP is not a tool for all purposes, but it has some standing and a growing user base in the image compression community. Let’s examine why.
WebP: A comparison of file sizes and visual similarity scores at different qualities.
WebP lossy files, using a VP8 or VP9 video key frame encoding variant, are on average cited by the WebP team as being 25-34% smaller than JPEG files.
In the low-quality range (0-50), WebP has a large advantage over JPEG because it can blur away ugly blockiness artifacts. A medium quality setting (-m 4 -q 75) is the default balancing speed/file-size. In the higher-range (80-99), the advantages of WebP shrink. WebP is recommended where speed matters more than quality.
Lossless Compression
WebP lossless files are 26% smaller than PNG files. The lossless load-time decrease compared to PNG is 3%. That said, you generally don’t want to deliver your users lossless on the web. There’s a difference between lossless and sharp edges (e.g. non-JPEG). Lossless WebP may be more suitable for archival content.
Transparency
WebP has a lossless 8-bit transparency channel with only 22% more bytes than PNG. It also supports lossy RGB transparency, which is a feature unique to WebP.
Metadata
The WebP file format supports EXIF photo metadata and XMP digital document metadata. It also contains an ICC Color Profile.
WebP offers better compression at the cost of being more CPU intensive. Back in 2013, the compression speed of WebP was ~10× slower than JPEG but is now negligible (some images may be 2× slower). For static images that are processed as part of your build, this shouldn’t be a large issue. Dynamically generated images will likely cause a perceivable CPU overhead and will be something you will need to evaluate.
Many large companies are using WebP in production to reduce costs and decrease web page load times.
Google reported 30-35% savings using WebP over other lossy compression schemes, serving 43 billion image requests a day, 26% of that being lossless compression. That’s a lot of requests and significant savings. Savings would undoubtedly be larger if browser support were better and more widespread. Google also uses it in production sites like Google Play and YouTube.
Netflix, Amazon, Quora, Yahoo, Walmart, Ebay, The Guardian, Fortune, and USA Today, all compress and serve images with WebP for browsers which support it. VoxMedia shaved 1-3s off load times for The Verge by switching over to WebP for their Chrome users. 500px saw an average 25% reduction in image file size with similar or better image quality when switching to serving it to their Chrome users.
There are quite a few more companies on board than this sample list indicates.
WebP usage at Google: 43 billion WebP image requests a day are served across YouTube, Google Play, Chrome Data Saver and G+.
WebP’s lossy encoding is designed to compete with JPEG for still images. There are three key phases to WebP’s lossy encoding:
Macro-blocking – splitting an image into 16×16 (macro) blocks of luma pixels and two 8×8 blocks of chroma pixels. This may sound familiar to the idea of JPEGs doing color space conversion, chroma channel downsampling and image subdivision.
Prediction – every 4×4 subblock of a macroblock has a prediction model applied that effectively does filtering. This defines two sets of pixels around a block – A (the row directly above it) and L (the column to the left of it). Using these two the encoder fills a test block with 4×4 pixels and determines which creates values closest to the original block. Colt McAnlis talks about this in more depth in How WebP lossy mode works.
A Discrete Cosine Transform (DCT) is applied with a few steps similar to JPEG encoding. A key difference is use of an Arithmetic Compressor vs JPEG’s Huffman.
If you want to dive deeper, Google Developer’s article WebP Compression Techniques goes into this topic in depth.
Not all browsers support WebP, however according to CanIUse.com, global user support is at about 74%. Chrome and Opera natively support it. Safari, Edge, and Firefox have experimented with it but not landed it yet in official releases. This often leaves the task of getting the WebP image to the user up to the web developer. More on this later.
Here are the major browsers and support information for each:
Chrome: Chrome began full support at version 23.
Chrome for Android: Since Chrome 50
Android: Since Android 4.2
Opera: Since 12.1
Opera Mini: All versions
Firefox: Some beta support
Edge: Some beta support
Internet Explorer: No support
Safari: Some beta support
WebP is not without its downsides. It lacks full-resolution color space options and does not support progressive decoding. That said, tooling for WebP is decent and browser-support, while limited to Chrome and Opera at the time of writing, may well cover enough of your users for it to be worth considering with a fallback.
Several commercial and open source image editing and processing packages support WebP. One particularly useful application is XnConvert: a free, cross-platform, batch image processing converter.
XnConvert
XnConvert enables batch image processing, compatible with over 500 image formats. You can combine over 80 separate actions to transform or edit your images in multiple ways.
XnConvert supports batch image optimisation, allowing straight-forward conversion from source files to WebP and other formats. In addition to compression, XnConvert can also help with metadata stripping, cropping, color depth customisation and other transforms.
Some of the options listed on the xnview website include:
Metadata: Editing
Transforms: Rotate, Crop, Resize
Adjustments: Brightness, Contrast, Saturation
Filters: Blur, Emboss, Sharpen
Effects: Masking, Watermark, Vignetting
The results of your operations can be exported to about 70 different file formats, including WebP. XnConvert is free for Linux, Mac, and Windows. XnConvert is highly recommended, especially for small businesses.
Node modules
Imagemin is a popular image minification module that also has an add-on for converting images to WebP (imagemin-webp). This supports both lossy and lossless modes.
To install imagemin and imagemin-webp run:
> npm install --save imagemin imagemin-webp
We can then require() in both modules and run them over any images (e.g. JPEGs) in a project directory. Below we’re using lossy encoding with a WebP encoder quality of 60:
Similar to JPEGs, it’s possible to notice compression artefacts in our output. Evaluate what quality setting makes sense for your own images. Imagemin-webp can also be used to encode lossless quality WebP images (supporting 24-bit color and full transparency) by passing lossless: true to options:
A WebP plugin for Gulp by Sindre Sorhus built on imagemin-webp and a WebP loader for WebPack are also available. The Gulp plugin accepts any options the imagemin add-on does:
XNConvert supports batch image compression, but if you would prefer to avoid using an app or a build system, bash and image optimization binaries keep things fairly simple.
You can bulk convert your images to WebP using cwebp:
Photoshop WebP Plugin — Free. Image import and export. From Google.
Android: You can convert existing BMP, JPG, PNG or static GIF images to WebP format using Android Studio. For more information, see Create WebP Images Using Android Studio.
While you can drag and drop WebP images to Blink-based browsers (Chrome, Opera, Brave) to preview them, you can also preview them directly from your OS using an add-on for either Mac or Windows.
Facebook experimented with WebP a few years ago and found that users who tried to right-click on photos and save them to disk noticed they wouldn’t be displayed outside their browser due to them being in WebP. There were three key problems here:
"Save as" but unable to view WebP files locally. This was fixed by Chrome registering itself as a ".webp" handler.
"Save as" then attaching the image to an email and sharing with someone without Chrome. Facebook solved this by introducing a prominent "download" button in their UI and returning a JPEG when users requested the download.
Right click > copy URL -> share URL on the web. This was solved by content-type negotiation.
These issues might matter less to your users, but is an interesting note on social shareability in passing. Thankfully today, utilities exist for viewing and working with WebP on different operating systems.
On Mac, try the Quick Look plugin for WebP (qlImageSize). It works pretty well:
On Windows, you can also download the WebP codec package allowing WebP images to be previewed in the File Explorer and Windows Photo Viewer.
Browsers without WebP support can end up not displaying an image at all, which isn’t ideal. To avoid this there are a few strategies we can use for conditionally serving WebP based on browser support.
The Chrome DevTools Network panel highlighting WebP files being conditionally served to Blink-based browsers under the ‘Type’ column.While the Play store delivers WebP to Blink, it falls back to JPEGs for browsers like Firefox.
Here are some of the options for getting WebP images from your server to your user:
Using .htaccess to Serve WebP Copies
Here’s how to use a .htaccess file to serve WebP files to supported browsers when a matching .webp version of a JPEG/PNG file exists on the server.
Vincent Orback recommended this approach:
Browsers can signal WebP support explicitly via an Accept header. If you control your backend, you can return a WebP version of an image if it exists on disk rather than formats like JPEG or PNG. This isn’t always possible however (e.g. for static hosts like GitHub pages or S3) so be sure to check before considering this option.
Here is a sample .htaccess file for the Apache web server:
RewriteEngine On
# Check if browser support WebP images
RewriteCond %{HTTP_ACCEPT} image/webp
# Check if WebP replacement image exists
RewriteCond %{DOCUMENT_ROOT}/$1.webp -f
# Serve WebP image instead
RewriteRule (.+)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1]
Header append Vary Accept env=REDIRECT_accept
AddType image/webp .webp
If there are issues with the .webp images appearing on the page, make sure that the image/webp MIME type is enabled on your server.
Apache: add the following code to your .htaccess file:
AddType image/webp .webp
Nginx: add the following code to your mime.types file:
image/webp webp;
Using the Tag
The browser itself is capable of choosing which image format to display through the use of the tag. The tag utilizes multiple elements, with one tag, which is the actual DOM element which contains the image. The browser cycles through the sources and retrieves the first match. If the tag isn’t supported in the user’s browser, a
is rendered and the tag is used.
Here is some sample HTML:
Automatic CDN conversion to WebP
Some CDNs support automated conversion to WebP and can use client hints to serve up WebP images whenever possible. Check with your CDN to see if WebP support is included in their service. You may have an easy solution just waiting for you.
WordPress WebP support
Jetpack — Jetpack, a popular WordPress plugin, includes a CDN image service called Photon. With Photon you get seamless WebP image support. The Photon CDN is included in Jetpack's free level, so this is a good value and a hands-off implementation. The drawback is that Photon resizes your image, puts a query string in your URL and there is an extra DNS lookup required for each image.
Cache Enabler and Optimizer — If you are using WordPress, there is at least one halfway-open source option. The open source plugin Cache Enabler has a menu checkbox option for caching WebP images to be served if available and the current user’s browser supports them. This makes serving WebP images easy. There is a drawback: Cache Enabler requires the use of a sister program called Optimizer, which has an annual fee. This seems out of character for a genuinely open source solution.
Short Pixel — Another option for use with Cache Enabler, also at a cost, is Short Pixel. Short Pixel functions much like Optimizer, described above. You can optimize up to 100 images a month for free.
Ultimately, choosing an image optimization strategy will come down to the types of images you’re serving down to your users and what you decide is a reasonable set of evaluation criteria. It might be using SSIM or Butteraugli or, if it’s a small enough set of images, going off of human perception for what makes the most sense.
Here are my closing recommendations:
If you can’t invest in conditionally serving formats based on browser support:
Guetzli + MozJPEG’s jpegtran are good optimizers for JPEG quality > 90.
For the web q=90 is wastefully high. You can get away with q=80, and on 2× displays even with q=50. Since Guetzli doesn’t go that low, for the web you can MozJPEG.
Kornel Lesiński recently improved mozjpeg’s cjpeg command to add tiny sRGB profile to help Chrome display natural color on wide-gamut displays
PNG pngquant + advpng has a pretty good speed/compression ratio
If you can conditionally serve (using , the Accept header or Picturefill):
Serve WebP down to browsers that support it
Create WebP images from original 100% quality images. Otherwise you’ll be giving browsers that do support it worse-looking images with JPEG distortions and WebP distortions! If you compress uncompressed source images using WebP it’ll have the less visible WebP distortions and can compress better too.
The default settings the WebP team use of -m 4 -q 75 are usually good for most cases where they optimize for speed/ratio.
WebP also has a special mode for lossless (-m 6 -q 100) which can reduce a file to its smallest size by exploring all parameter combinations. It’s an order of magnitude slower but is worth it for static assets.
As a fallback, serve Guetzli/MozJPEG compressed sources to other browsers
JPEG XT defines extensions to the 1992 JPEG specification. For extensions to have pixel-perfect rendering on-top of old JPEG, the specification had to clarify the old 1992 spec and libjpeg-turbo was chosen as its reference implementation (based on popularity).
PIK is a new image codec worth keeping an eye on. It’s compatible with JPEG, has a more efficient color-space and utilizes similar benefits found in Guetzli. It decodes at 2/3 the speed of JPEG and offers 54% more file savings than libjpeg does. It is both faster to decode and compress than Guetzli-ified JPEGs. A study on psychovisual similarity of modern image codes showed PIK was less than half the size of alternatives. Unfortunately, it’s still early days for the codec and encoding is unusably slow at this time (August, 2017).
ImageMagick is often recommended for image optimization. This write-up considers it a fine tool, but its output generally requires more optimization and other tools can offer better output. We recommend trying libvips instead, however it is lower-level and requires more technical skill to use. ImageMagick has also histortically had noted security vulnerabilities you may want to be aware of.
Blink (the rendering engine used by Chrome) decodes images off the main thread. Moving the decode work to the compositor thread frees-up the main thread to work on other tasks. We call this deferred decoding. With deferred decoding, the decode work remains on the critical path for presenting a frame to the display, so it can still cause animation jank. The img.decode() API should help with the jank problem.
The content of this book is licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 2.0 Generic (CC BY-NC-ND 2.0) license, and code samples are licensed under the Apache 2.0 License. Copyright Google, 2018.