Image Compression

The image compressor tries to find the optimal representation for each input image by performing several optimization experiments for it. For example, in order to achieve substantial size improvements for a JPEG encoded photo some lossy compression techniques may be applied. A transparent PNG may be converted to a ZorroSVG whereas graphic images may benefit from WebP-lossless encoding or quantization. The experiments are traffic-aware, so that frequently requested images are taken care of with higher priority.

The Image Compression only optimizes cacheable image responses. Responses with e.g. Cache-Control: private or other headers which prevent caching, are passed unmodified to client. With every image request one experiment for that image will be carried out. The optimization is always running offline. The first client always gets the original image and triggers the first experiment. If the result of an experiment is better (i.e. smaller) than any previous result, it will be used as the new reference image which is to be beaten by the following experiments. Usually the final optimization will not be reached in the first request.

In contrast to image scaling, image compression does not change image dimensions. Moreover, rewriting of URLs in HTML documents and CSS style sheets is less elaborate and therefore much faster compared to image scaling. This reduces the overall footprint for HTML and CSS processing which shortens the critical path.

Automatic Image Quality Assessment

Usually it is impossible to find a quality setting that is optimal in terms of balancing file size vs. visual quality for all images. Different images show different patterns of degradation when quality is decreased. While some JPEG images still look good with quality="30", others may show disturbing artifacts at quality="90".

Automatic image quality assessment (AIQA) is able to target the optimal compression level within a configurable “visual dissimilarity”. In other words: It reduces the image in byte size as much as possible without visually changing it. AIQA even allows to apply lossy compression – which usually achieves the highest byte savings – to input images in lossless formats (PNG/WebP) without risking to degrade quality.

FIT uses DSSIM to measure how dissimilar the compressed version of the image is compared to the original.

For now, AIQA (controlled by the value of the d attribute) is only applied to JPEG compression.


To use image compression, add the image-compression entry to the conf/config.xml:

    <image-compression />

image-compression and image-scaling cannot be used together. Enabling image-scaling automatically disables image compression.

Image compression can be controlled with these options:

    <image-compression preset="balanced" quality="80" d="0.002" />

If lossy compression is applied to an image in JPEG or WebP format, the quality parameter determines the size in terms of bytes the image will be. A higher quality results in a larger, better looking image.

The quality attribute of image-compression (default: 80) sets the quality for JPEG and WebP images.

Lossy compression leads to smaller images which look more or less similar to the original. Therefore, a lower quality generates images having a reduced similarity to the original image and vice versa. As it is virtually impossible to find a quality setting that results in both consistently good visual quality and reduction in size for lots of different images, the d attribute (default: 0.002) allows you to specify an acceptable dissimilarity to the original image.

A valid d attribute causes the image compressor to automatically determine a corresponding JPEG quality for each image, overriding a given quality attribute (Automatic Quality Assessment). A smaller dissimilarity d increases the output quality and therefore results in larger, better looking JPEG images. Accordingly, a higher dissimilarity d produces smaller images with possibly stronger visual degradation. A nonpositive d forces the JPEG output quality to fall back to the value of the quality attribute.

Note: d currently only applies to images that are output in JPEG format.

For ease of use, the built-in presets quality, performance and balanced (default) already define appropriate values for d and quality (see table below). Thus, usually there’s no need to specify these attributes explicitly, just set the desired preset:

    <image-compression preset="performance" />
Preset d quality
performance 0.004 70
balanced 0.002 80
quality 0.001 90


    <!-- d=0.002 (JPEG) and quality=80 (WebP) from preset "balanced" -->
    <image-compression />

    <!-- d=0.004 (JPEG) and quality=70 (WebP) from preset "performance" -->
    <image-compression preset="performance" />

    <!-- d=0.002 (JPEG) from preset "balanced", quality=85 (WebP) -->
    <image-compression quality="85" />

    <!-- d=0.003 (JPEG), quality=70 (WebP) from preset "performance" -->
    <image-compression d="0.003" preset="performance" />

    <!-- d disabled, quality=80 for both WebP and JPEG from preset "balanced" -->
    <image-compression d="0" />

    <!-- d disabled, quality=75 for both WebP and JPEG -->
    <image-compression d="0" quality="75" />

HTML Attribute ai-compress

With the HTML attribute ai-compress="false" you can disable image compression on a per image basis:

<img alt="will be compressed (default)" src="image.jpg" />
<img alt="will NOT be compressed"       src="image.png" ai-compress="false" />

Caching and URLs

By default, the Image Compression uses the HTTP Caching. Here the If-Modified-Since and If-None-Match headers are passed from the client to the source. Pragma, Cache-Control, Expires, ETag and Last-Modified headers as well as 304 Not Modified HTTP status codes from the source are passed to the client.

If a valid fit:// resource is requested, the FIT Server will add a Last-Modified header to the response. If the client request header contains an appropriate If-Modified-Since FIT will respond with 304 Not Modified.

If Interval Caching is enabled, FIT will add Cache-Control: max-age=<interval>, s-maxage=<interval> to the response.

FIT always adds the Cache-Control: No-Transform directive to image responses.

Whether an image will be publicly cacheable depends on whether all suitable compression experiments have been run for that image. Until all experiments have run FIT will add Cache-Control: private. The image that “wins” the final experiment will eventually be sent with Cache-Control: public.

When processing HTML or CSS content, image URLs (e.g. the value of the src attribute on an img element) are changed have the URL Mark m=ic. Depending on the client’s capabilities further marks are added to the URL that indicate WebP and Zorro support. The HTML document is delivered with Vary: User-Agent, but the Image responses don’t need to vary.

If an Image URL is not rewritten, e.g. if an image is loaded via JavaScript, the request will run the Flow. Then, the parse action will detect the image and run Image Compression, too. WebP and Zorro will be considered accordingly. However, the response will be marked Cache-Control: private.

System configuration and limits

In the system-wide configuration fit.ini you can set the FIT_MAX_IMAGE_AREA to define the maximum size of an ingoing (=outgoing) image in megapixels. With FIT_MAX_IMAGE_PROCESSES you can limit the number of concurrently running image optimization processes to prevent excessive CPU usage.