Working with Image Thumbnails

Overview

Concrete CMS version 7 contains a completely new way of handling image thumbnails. Thumbnail types are defined in the Dashboard, and when images of sufficient size are uploaded into the File manager, thumbnails of those dimensions will automatically be created. You can learn more about how these work with responsive themes in the Supporting Responsive Images in your Concrete Theme.

These thumbnails aren't just useful for responsive themes, however. With a little bit of custom development, you can use custom thumbnails to power image galleries and more. You get the best of both worlds: thumbnails are auto-generated to your exact specifications, but also support the built-in Concrete Image Editor for specific overrides.

Using Custom Thumbnails in Gallery Blocks

It's a common problem: you have an image gallery, and you'd like to list custom thumbnails in the page, with a detail image that gets displayed when you click on the thumbnail. Your thumbnails all should be 100 pixels wide by 100 pixels tall. Let's say you have an array of \Concrete\Core\File\File objects (the $images array below), and these are the images you want to display in your block. In Concrete version 6 and earlier, you might have looped through them and used the image helper:

<?php
$width = 100;
$height = 100;
$im = Loader::helper('image');
foreach($images as $file) {
    print '<div class="thumbnail">';
    $im->outputThumbnail($file, $width, $height, $file->getTitle(), false, true);
    print '</div>';
}

Let's break down what's happening here. For each File object in the array, we generate a custom thumbnail at 100 pixels by 100 pixels. We set the alt tag for our image to the title of the File object. The fifth argument controls whether the method prints out immediately or returns its contents, and finally, the last argument controls whether the image should be absolutely constrained to the passed width and height. Since we've set this to true, we will always get 100 by 100 images back – even if the aspect ratio of the image isn't a square. The thumbnailer will simply chop off content until it gets to 100 by 100.

There are a couple problems with this approach.

Memory Hog

Since this happens in real time on page load, this can be a memory hog. If you've got lots of images in your gallery, your page might take a really long time to load. This shouldn't always be the case, as once these images are generated they do get stored in the application/files/cache directory, but any time the cache is cleared these images will have to be rebuilt. Sometimes this can be a lot for an underpowered server.

No Control

Worse than potential memory issues – there's very little control over this approach. You'll get your thumbnails, and the image service can provide some basic JPEG compression controls, but other than that you have no control over how your thumbnails look. If you upload an image and the thumbnailer cuts someone's head off, you can't really do much about it, other than upload an image at a different aspect ratio and cross your fingers.

A Better Way

Fortunately, Concrete version 7 provies a much better way to solve this problem. First, in the Dashboard, create a custom thumbnail type for your gallery, and set it to a fixed 100 pixels by 100 pixels:

Next, go through the File Manager and rescan every image you have. This will regenerate thumbnails for your images, including the new thumbnail type that you added. You'll only have to do this once; new files that are uploaded will automatically have a thumbnail for this new type.

Now, within the template of your block, instead of using the basic image thumbnailer like we did before, we're going to use these special thumbnails, with code like this:

$type = \Concrete\Core\File\Image\Thumbnail\Type\Type::getByHandle('gallery');
foreach($images as $file) {
    if (is_object($file)) {
        $src = $file->getThumbnailURL($type->getBaseVersion());
        echo '<div class="thumbnail">';
        echo "<img src=\"$src\" alt=\"{$file->getTitle()}\" width=\"{$type->getWidth()}\" height=\"{$type->getHeight()}\">";
        echo '</div>';
    }    
}

First, we retrieve an object for the gallery thumbnail type we added. Next, for each File object in the images array, we grab the thumbnail URL for that thumbnail type's base version. What's a base version? Well, every thumbnail type has a base version (which is the version that is created exactly from the dimensions you specified) as well as a doubled version, which is used for Retina displays. We're going to grab the base version, but you could just as easily grab the doubled version instead, and perhaps size the image down using responsive CSS.

That's It!

Your code is cleaner, and more importantly, it doesn't suffer from any of the drawbacks listed above. Your images are computed at upload or rescan time, which means your pages load faster. Additionally, if you don't like one of the automatically created images, just edit the File's thumbnail through the File Manager Image Editor. You can get the image just right. Using this technique making an image gallery in Concrete has never been easier.