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!

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 originally uploaded image version: Binary#original()
  • Scrivito never upscales images.
  • When downscaling images, Scrivito always preserves their aspect ratio.
  • Scrivito applies the orientation of the original image to the scaled-down versions.
  • Scaled-down versions are always in the sRGB color space. Color conversion (e.g. from CMYK) is based on the ICC profile, if present. There’s an API for accessing the not converted image version: Binary#original()
Original width Requested width Delivered width Note
6000 6500 4096 Maximum
6000 5000 4096 Maximum
6000 4000 4096 Maximum, best match

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.

Requesting pre-scaled images programmatically

Scrivito not only creates and automatically delivers scaled-down image versions for improving website performance. Additionally, it provides an API, the Binary#optimizeFor method, for finding the image version that best satisfies the demands in two use cases:

  • The image version should best fit into an area of specific dimensions.
  • The image version should be suitable for being cropped to specific dimensions.

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 better control over the dimensions of images, such as a company logo that must never be scaled down, or images to which CSS will be applied, e.g. to change their aspect ratio or crop them.

Generally speaking, optimizeFor returns the image version whose dimensions are either closest to the ones you specify, or large enough to subsequently crop the image.

How it works

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:

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

To specify the target dimensions of the binary, apply optimizeFor to it, like so:

Copy
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 or downloading but record the desired dimensions for a specific operation. Only after accessing the binary’s data, e.g. by querying its URL, Scrivito selects the image version to use.

Copy
imageUrl = binary.url();

The resulting pre-scaled image is determined at best effort and should thus be used only in combination with suitable CSS to ensure that the image is displayed as intended.  

Examining image metadata

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

Copy
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.

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 requesting an image version that best meets specific requirements, the Binary.optimizeFor method is available. To learn how to use this method in a component, take a look at the “ThumbnailGalleryWidget” included in the Scrivito Example App.