Having Images Optimized for Size

Good website performance is among the top factors contributing to a positive user experience. Especially with low-bandwidth connections, images often have a strong impact on page loading times, and thus represent the most effective leverage point to improve website responsiveness.

Why transfer high-res images to a mobile device incapable of displaying them in their full beauty? Instead of letting the browser scale them down, such images could already be optimized before they are delivered, minimizing the amount of data to be transferred. Scrivito takes care of exactly this – to the benefit of the visitor’s user experience.

Providing scaled down image versions

Screens vary in size, uploaded images don’t. Without any adaptiveness, if an editor uploads an oversized image, it gets delivered as is, regardless of the visitor’s screen dimensions, wasting a lot of time and bandwidth. To improve this, Scrivito creates a pool containing several scaled down versions of an image immediately after it has been uploaded, plus the one of the original size if it’s not covered by any of the standard sizes. From this pool, images nearest in dimensions to the display resolution on the client’s side are automatically selected and served – without having to bother about making images responsive from within the app. It simply works out of the box!

In addition to adaptively serving images from the pool, the Scrivito backend transparently generates precisely matching image versions supplementing the standard sizes.

Note that Scrivito never upscales images. Even if, for example, a 240 pixels wide image has been uploaded and placed in full width on a page which then gets displayed on a 2400 pixels wide high-res device, the 240 pixels image version is still delivered unchanged, leaving it to the browser to make it fit.

How is the best fitting image version determined? 

Scrivito includes two helper components for rendering images, Scrivito.ImageTag and Scrivito.BackgroundImageTag. Both were designed to reference an image that has been uploaded to the CMS.

To have the generated markup include the image version that fits best, the SDK requests from the backend the URL to use for the image in question. The request includes the device’s screen dimensions, enabling the backend to determine the best matching image version and return its URL. The SDK then uses this URL to render the tag attribute referencing the image, resulting in something like this:

<img src="https://cdn0.scrvt.com/cms-tenant-id/608e1943afa34329/f9f1d48cd587cae9/608d1943afa3/v/c77740150e89/my-image.png" class="…" alt="…">

Since fetching and analyzing image metadata is time-consuming, the Scrivito backend caches the URLs and the dimensions associated with them, speeding up the SDK’s rendering of markup for downscaled images.

Width and height validation

Users may upload images with any dimensions. However, the maximum width or height of image versions the backend computes is limited – currently to 4096 pixels. This also applies to image versions the backend delivers. Here’s an example use case:

Let’s assume that a user uploads an image, which is 6000 pixels wide (and 4096 or less pixels high). This triggers the creation of a number of downscaled image versions of which the largest is 4096 pixels wide. Let’s further assume that afterwards some requests for this image are made:

Facts and figures

  • After uploading an image, scaled-down versions of it are automatically generated and delivered based on the screen dimensions of the visitor’s device.
  • The maximum width and height of an image scaled down by Scrivito never exceeds 4096 pixels.
  • 4096 pixels is at the same time the maximum width and height of any image delivered, unless you are using the API to fetch the originally uploaded version of an image.
  • Scrivito never upscales images.
  • When downscaling images, Scrivito always preserves their aspect ratio.
Original width Requested width Delivered width Note
6000 6500 4096 Maximum
6000 5000 4096 Maximum
6000 4000 4096 Maximum, best match

The request for the 4000 pixels wide version causes it to be computed in the background for delivering it instead of the precomputed maximum the next time this width is asked for.

Scrivito always uses the greater of the two side lengths for determining the scaling factors it needs to apply to an image. In that sense, width and height are interchangeable in the examples above.

Optimizing images programmatically

Next to automatically creating scaled-down image versions for improving website performance, Scrivito provides an API for transforming images programmatically from within your app. The Binary#optimizeFor method not only lets you scale images down to any size you require but also crop them in case you wish to highlight some detail in your thumbnails, for example. For not going beyond the scope of this article, we’ll limit ourselves here to explaining the basic principle behind Binary#optimizeFor and when to use this approach.

Scaling and cropping

Both built-in image rendering helper components, Scrivito.ImageTag and Scrivito.BackgroundImageTag, are best efforts to make images fit into the space provided for them on a page and thereby reduce the amount of data to be downloaded.

Binary#optimizeFor, on the other hand, is intended for cases in which you need full control over the dimensions of images, such as a company logo that must never be scaled down, or fixed-size images to be fed into a third party library, e.g. a slider.

In general, optimizeFor lets you scale down or crop any Binary holding an image. With image objects, the binary data is usually stored in an attribute named blob (but any attribute of the binary type will do). So, for example, the following retrieves the binary of an image object for processing it further:

image = Scrivito.getClass("Image").all().first();
binary = image.get('blob')

Examining image metadata

In very rare cases it might be desirable to ensure that an image to be transformed using optimizeFor has at least the width, height, or aspect ratio you are aiming at. This can be achieved by checking its metadata, like so:

metadata = binary.raw().metadata();
width = metadata.get('width');
height = metadata.get('heigth');
if (width < 720 || (width / height) < 1.0) {
  /* Discard image, display message, ... */

Be aware that fetching image metadata is time consuming, so do this only if it cannot be avoided.

To scale down or crop a binary, apply optimizeFor to it, like so:

binary = binary.optimizeFor({ width: 720, fit: 'resize' });
binary = binary.optimizeFor({ height: 120, fit: 'crop' });

Note that calls to optimizeFor do not trigger any image processing. The resulting image is computed only after accessing its data, e.g. by querying its URL:

imageUrl = binary.url();

In summary …

When using the Scrivito.ImageTag and Scrivito.BackgroundImageTag components built into Scrivito, images are automatically scaled down for devices with smaller screen dimensions. This reduces image file size and thus bandwidth utilization, resulting in better website performance.

For changing the dimensions of images from within an app, the Binary.optimizeFor method is available for downscaling and cropping images in a controlled manner. To learn how to use this method in a component, take a look at the “ThumbnailGalleryWidget” included in the Scrivito Example App.