Most mobile carriers force all HTTP traffic to go through their proxies that—among other things—recompress images on the fly. This means that visitors of your website or mobile app may be getting images in much lower quality than you're serving.
I've decided to have a closer look at what exactly these proxies do to images and whether it can be improved. I've set up a test page that downloads a set of sample images and re-uploads them back to my server for analysis. I've served 27 different images and got 231 unique files back.
It turns out that these proxies are not as bad as I expected, but quality of images they produce is rather low and cannot be relied upon. With few simple tweaks it's possible to deliver images with even better compression and quality. Here's what I've found:
All proxies recompress all JPEG images. Unfortunately, even very low quality JPEGs are recompressed to have even lower quality. If you're already using JPEGs at minimum acceptable quality (e.g. "compressive images" trick for high-dpi displays) you need to stop proxies from ruining them.
PNG images are very rarely recompressed. If you're not using lossy PNG yet—you really should!
Static GIF images are getting noticeably posterized/discolored/dithered. Fortunately, apart from nostalgia, there's no reason to use GIF for images any more.
The standard HTTP header Cache-Control: no-transform
which tells proxies not to modify responses was respected by all proxies I've encountered. This is amazing! It wins an award in the "Best Supported Obscure Header" category.
ByteMobile proxy seems to be ISPs' favorite. Sprint, Vodaphone.de, O2 (Telefonica), T-Mobile PL served bit-identical images that appear to be generated by this software. It also modifies HTML (and ignores MIME types and breaks XML) to inject a script that allows users to reload images in original quality… with a keyboard shortcut. The good news is that this proxy has a JPEG encoder tuned to perform relatively well on low quality images.
Centertel PL and openmobile.ne.jp use different software, but achieve similar results.
There was only one proxy that recompressed PNG images (it identifies itself as "bwo-c1s11 hpm/3.0"). It did OK job with opaque PNG files, but messed up transparency and made some PNGs larger.
These two proxies are not run by ISPs, but are integrated with Opera's and Google's browsers. They convert images to WebP and compress them very aggressively. They achieve smallest file sizes, but often also give lowest quality.
Google's lossy WebP format is not so good for high-quality images (e.g. can't store color at full resolution), but it's strength is in low-quality range thanks to block prediction that can approximate edges and deblocking filter that blurs away some compression artifacts.
However, recompressing proxies are at a disadvantage, because they don't have access to original high-quality images. They can only make bad quality worse, and lossy recompression of lossy format magnifies compression artifacts.
For example, a 26KB JPEG image saved at "30%" quality was losslessly optimized to 24KB by openmobile.ne.jp. Google Proxy converted this image to a larger 24.7KB WebP that smudged away some details. Opera's WebP settings blur even more:
20KB recompressed WebP | 20KB JPEG saved from source |
You're better off optimizing images yourself from source files than relying on proxies to (re)compress for you.
No proxy converts BMP or TIFF. These formats provide very weak or no compression, so it would be nice to protect users from such rare, but massive files. Similarly proxies miss out on converting uncompresed ICO files to PNG (tip: you can use PNG for favicon.ico
—it works in all browsers including recent IE).
Only openmobile.ne.jp and Centertel PL support ICC color profiles. All other proxies misinterpreted colors as sRGB. Browser support for color profiles isn't great either, so it's best to use sRGB from the start.
GIFs are converted to poorly chosen, posterized palettes with unused colors. Sadly no proxy converts them to PNG8, which would give bigger savings.
Animated GIFs are left unharmed, but you shouldn't use them on mobile anyway. It may seem odd, but due to very inefficient compression and lack of hardware acceleration, GIFs are slower to download and may use more battery than high-end video codecs!
Proxies cannot modify HTTPS traffic, so this is one way to bypass them. For insecure traffic, you can add an HTTP header.
In nginx:
location ~* \.(png|jpg|jpeg|gif)$ {
add_header "Cache-Control" "public, no-transform";
}
Apache:
<IfModule mod_headers.c>
<FilesMatch "\.(png|jpg|jpeg|gif)$">
Header append Cache-Control "public, no-transform"
</FilesMatch>
</IfModule>
Please opt out of recompression only if you're heavily compressing and optimizing images yourself already. Keep in mind that there are still areas with 2G networks capped to 10KB/s. Recompressed ugly images are better than pretty images that won't load before users lose patience and navigate away.
It's also worth mentioning an unfortunate side-effect of HTTP proxies: they break WebSocket connections and there's no easy "opt-out" for that. Instead you have to use WebSockets over HTTPS or switch to HTTP-compatible Server-Sent Events.
Make PNGs 70% smaller by converting them with a lossy PNG encoder. Check out ImageAlpha or TinyPNG.
Lower quality of JPEGs. "Quality" setting in JPEG is very misleading—it controls how much data is removed, but some images can tolerate much more compression than others. Tune it per image instead of using arbitrary high setting for all of them. Try JPEGMini/Adept and ImageOptim.
Serve well-optimized images over HTTPS or with Cache-Control: no-transform
header to prevent further degradation.
Never use GIF, TIFF, BMP or other legacy formats.
Merry compressing!
Icons by George Agpoon and Jaime Carrion from The Noun Project.