Using phpThumb() to generate responsive and modern images
Websites need to be fast, not just for great usability and user experience but to deliver great performance for both our clients and users. Images are the biggest culprits for bloating page size and slowing down loading times. However, with MODX we can use a few simple tricks to generate performant images on the fly.
You'll need the pThumb Extra installed to follow along, pThumb is a port of the older PHpThumbOf Extra that provides some added performance and caching benefits.
The first thing we'll need is an image we can manipulate, I've found this one from Unsplash:
This image is 2mb! Far too big to be of any use to us, it'll be slow to load (even though we're lazy loading it here), mobile users or users on slow internet connections will have to wait longer while this image loads and it'll hurt our SEO score.
What can we do?
Here is where the power of pThumb comes in, with a simple change to the
img tag, we can drop the size of that image right off the bat. To use pThumb we just need to pass the URL of the image we are manipulating, you can use pThumb as an output modifier or as a snippet. For this article, I'll just be passing the URL into the snippet.
Let's start by resizing this image, the max width of my container is only 768px, so I don't need to be loading an image that's 4513px wide!
<img src="[[!pthumb? &input=`luca-bravo-zAjdgNXsMeg-unsplash.jpg` &options=`w=712&q=100`]]">
We've gone from 2MB to 297kb in one simple step, that's a massive reduction in image size however, the image quality has been compromised. There are a number of things we can do to improve image quality while reducing the size of the image, but first, let's take a look under the hood.
phpThumb() uses the GD library to create thumbnails from images (JPEG, PNG, GIF, BMP, etc) on the fly. The output size is configurable and the source may be the entire image or only a portion of the original image - source https://phpthumb.sourceforge.net/
It comes with a handful of useful functions that we can utilize to scale, crop, and transform images for various use cases. To use phpThumb() with MODX we can download the PHPThumbOf or pThumb extra using the MODX Package manager. pThumb is a fork of phpThumbOf 1.4.0. pThumb is a lightweight, efficient, and actively maintained replacement for phpThumbOf. It offers most of the functionality of its predecessor while adding new features, fixing bugs, and offering some potentially dramatic speed improvements on sites that use phpThumbOf heavily.
Improving our image
Our image quality has been affected by the reduction in size, however, using the latest best practices we can generate different image sizes that target different screen widths and pixel ratios, plus utilize PhpThumb's ability to generate different file formats. The first thing we're going to do with convert the image to webp, WebP is a modern image format that provides superior lossless and lossy compression for images on the web.
<img src="[[++placeholder_img]]" data-src="[[!pthumb? &input=`luca-bravo-zAjdgNXsMeg-unsplash.jpg` &options=`w=712&q=100&f=webp`]]" alt="Resized image using pthumb" class="lazy">
Converting the image to webp has brought our image size from 297kb to 56.3kb! This time with no degradation in image quality compared to the smaller JPEG image. This gives us some breathing room to improve our image quality by generating a large file that we can send to browsers that can handle it.
Utilizing the <picture> tag
The picture tag allows us to define different source images that can target different screen widths and device pixel ratios based on media queries. Using pThumb we can generate out the different assets required for each media query:
<picture> <source data-srcset="[[!pthumb? &input=`luca-bravo-zAjdgNXsMeg-unsplash.jpg` &options=`w=519&q=100&f=webp`]] 1x, [[!pthumb? &input=`luca-bravo-zAjdgNXsMeg-unsplash.jpg` &options=`w=1038&q=100&f=webp`]] 2x" media="(max-width: 575.99px)" type="image/webp" /> <source data-srcset="[[!pthumb? &input=`luca-bravo-zAjdgNXsMeg-unsplash.jpg` &options=`w=712&q=100&f=webp`]] 1x, [[!pthumb? &input=`luca-bravo-zAjdgNXsMeg-unsplash.jpg` &options=`w=1424&q=100&f=webp`]] 2x" media="(min-width: 576px)" type="image/webp" /> <!-- Fallback image --> <img src="[[++placeholder_img]]" data-src="[[!pthumb? &input=`luca-bravo-zAjdgNXsMeg-unsplash.jpg` &options=`w=712`]]" alt="Resized image using pthumb" class="lazy"> </picture>
There is a fine line to walk when utilizing this method, if you're generating 5 images on the fly on a PDO Resources call with a limit of 12 resources you'll be creating 60 images on the first-page load! This is not necessarily a problem if you've got a long cache on these images and a good server, as once the images are generated they won't need to be regenerated for a long time.
When using the picture tag, the browser is responsible for selecting the image file to fetch and display, so even though you have 5 files, only the file that the browser chooses will be requested. You can see this in action by opening the network tab in your browser's console and resizing the screen, when the browser drops below 576px it requests the most suitable image and updates the dom.
A few examples
Unfortunately, a lot of tutorials and examples on the web around phpThumb() seem to have broken example images. So I've created a few different examples of how you can use pThumb on your MODX Website.
One of my favorite things to do with pThumb is to generate a small, low-quality thumbnail using blur as a placeholder for lazy loading. You'll notice i've done this for the top image, the smaller blured image that loads in first is only 5.5kb! In other areas i've used an inline base 64 GIF as the placeholder:
Generating different images on MODX is really easy when you use an extra like pthumb, by using the webp format (You'll need to check your imagick or GD library installation supports the webp format for proper encoding and compression) you'll be able to improve loading times and SEO scores.