d'Hinnisdaël Posted October 20, 2023 Posted October 20, 2023 Generate image placeholders for smoother lazyloading. Currently supports ThumbHash, BlurHash, and average color placeholders. I've been using the wonderful ImageBlurhash module for this in the past, but unfortunately it's no longer in active development. This new module adds ThumbHash and Average Color placeholder algorithms, improves performance by caching generated placeholders, fixes an issue when replacing images, and allows regenerating and clearing placeholders via the admin interface. Try it out using the installation instructions below or check out the GitHub repo for details. Why use image placeholders? Low-Quality Image Placeholders (LQIP) are used to improve the perceived performance of sites by displaying a small, low-quality version of an image while the high-quality version is being loaded. The LQIP technique is often used in combination with progressive lazyloading. How it works This module will automatically generate a small blurry image placeholder for each image that is uploaded to fields configured to use them. In your frontend templates, you can access the image placeholder as a data URI string to display while the high-quality image is loading. See below for markup examples. Placeholder types The module supports generating various types of image placeholders. The recommended type is ThumbHash which encodes most detail and supports transparent images. ThumbHash is a newer image placeholder algorithm with improved color rendering and support for transparency. BlurHash is the original placeholder algorithm, developed at Wolt. It currently has no support for alpha channels and will render transparency in black. Average color calculates the average color of the image. Installation Install the module using composer from the root of your ProcessWire installation. composer require daun/processwire-image-placeholders Open the admin panel of your site and navigate to Modules → Site → ImagePlaceholders to finish installation. Configuration You'll need to configure your image fields to generate image placeholders. Setup → Fields → [images] → Details → Image placeholders There, you can choose the type of placeholder to generate. If you're installing the module on an existing site, you can also choose to batch-generate placeholders for any existing images. Usage Accessing an image's lqip property will return a data URI string of its placeholder. $page->image->lqip; // data:image/png;base64,R0lGODlhEAAQAMQAA Accessing it as a method allows setting a custom width and/or height of the placeholder. $page->image->lqip(300, 200); // 300x200px Markup Using a lazyloading library like lazysizes or vanilla-lazyload, you can show a placeholder image by using its data URI as src of the image. <!-- Using the placeholder as src while lazyloading the image --> <img src="<?= $page->image->lqip ?>" data-src="<?= $page->image->url ?>" data-lazyload /> Another technique is rendering the placeholder and the original image as separate images on top of each other. This allows smoother animations between the blurry unloaded and the final loaded state. <!-- Display placeholder and image on top of each other --> <div class="ratio-box"> <img src="<?= $page->image->lqip ?>" aria-hidden="true"> <img data-src="<?= $page->image->url ?>" data-lazyload> </div> 12 7
videokid Posted December 23, 2023 Posted December 23, 2023 Hi, I decided to try out this module, however, I got this: Error generating image placeholder: Class "Thumbhash\Thumbhash" not found Kind regards,
d'Hinnisdaël Posted December 23, 2023 Author Posted December 23, 2023 @videokid Sounds like the composer dependencies haven‘t been installed. Have you installed the module using composer? Merely installing via the admin UI won‘t work as it‘ll be missing the dependencies.
videokid Posted December 24, 2023 Posted December 24, 2023 @d'Hinnisdaël Ah, no I didn't install the module using composer. I got busy with something else and today I was thinking about it, and I had a feeling it was something like that. I'll install using composer ? Thank you anyway for your answer.
FireWire Posted September 23, 2024 Posted September 23, 2024 @bernhard This is the module I mentioned for generating placeholder images. Has worked very well. 1
FireWire Posted October 10, 2024 Posted October 10, 2024 @d'Hinnisdaël Found a bug that may cause the module to break on the next major release. Output formatting needs to be turned off before modifying a page value. I fixed it by adding `$image->page->of(false)` in the setPlaceholder module method.
d'Hinnisdaël Posted October 10, 2024 Author Posted October 10, 2024 @FireWire Thanks for the heads-up! So you're saying it's currently working but will break in a future version of ProcessWire? Is there a specific release that triggers the issue on your end? The module should probably also reset the output formatting state to the value it was before setting it to false, just in case.
FireWire Posted October 10, 2024 Posted October 10, 2024 @d'Hinnisdaël I was testing the dev branch when it happened, but it also happened on main release after switching between the two. I was running code on non-image fields when it saw the output formatting error called out by a WireException. I wish I could be more specific on that. I guess for the sake of good practice AFAIK turning output formatting off when setting field values via the API is the right approach. Also, thank you for your work on this module, it's really useful and a great implementation!
FireWire Posted October 29, 2024 Posted October 29, 2024 Hey there. It's me again. Question- is the module designed to regenerate lqip on module refresh? I'm having an issue where refreshing modules takes a really long time and it caused an execution timeout on a new server. I bumped it up so that doesn't happen but it takes a few minutes and the site currently has ~200 pages but will be going into the 1000s by next year. I see that there's a way to regenerate on a per-field basis, but a global regeneration at some point is going to crash my server haha. Any insights?
d'Hinnisdaël Posted October 29, 2024 Author Posted October 29, 2024 @FireWire The placeholders are cached and there's no logic for regenerating anything on module refresh, especially not globally, so that'd be a surprise for me at least. Are you sure it's related to this module? Feel free to share the exception stacktrace in case.
FireWire Posted October 29, 2024 Posted October 29, 2024 @d'Hinnisdaël I'll check it out again. I'm juggling a few things so haven't had time to dig in and wanted to ask just in case. If I find anything useful I'll let you know. Thanks for the quick reply!
Noboru Posted October 31, 2024 Posted October 31, 2024 Hi @d'Hinnisdaël, when I clone a page with an image with placeholder, I get an exception: “Can't save field from a new page - please save the entire page first”. I solved this in line 55: if ($type && $images->count() && !$page->hasStatus(Page::statusDeleted) && !$page->isNew()) {... The placeholder data is cloned with the image. Many thanks for the great module! I use it in the frontend with unlazy. Armin
d'Hinnisdaël Posted November 1, 2024 Author Posted November 1, 2024 Thanks @Noboru for the pointer! I've released version 0.3.1 with your suggested fix. 1
Jules Vau Posted April 9 Posted April 9 Hello, I use Average color, and it works like a charm. There is a way to get the value of the hex color? Thank you!
d'Hinnisdaël Posted April 10 Author Posted April 10 @Jules Vau The hashes (or in your case, color codes) are stored as filedata. If you have access to the Pageimage object, this should do: $type = $image->filedata("image-placeholder-type"); $hash = $image->filedata("image-placeholder-data"); 1
FireWire Posted July 31 Posted July 31 On 10/29/2024 at 4:31 PM, d'Hinnisdaël said: Are you sure it's related to this module? Feel free to share the exception stacktrace in case. Hey @d'Hinnisdaël. I recently tracked down a behavior that isn't a fault of your module, but where an additional feature in ImagePlaceholders would be a really big help. Since this module can affect so many fields and because it hooks into very common actions (savedField, savePageField) it would be really helpful if there was a module setting to globally disable placeholder generation. The issue I reported above ended up being with another module that was triggering placeholder regeneration for a very large group of fields due to a bug. This caused major slowdowns on the server as regeneration happened for all images in dozens of fields, many with multiple images. Up to hundreds of images in total. Regardless of the cause, having the ability to temporarily disable image generation for troubleshooting or whatever need may arise would be a very great feature. If you're open to a PR on Github, I've already written this into a local copy of ImagePlaceholders where the module is configurable and a checkbox is provided on the module config page to globally disable placeholder generation. Would be happy to contribute if you're interested. Thanks again for the great module!
d'Hinnisdaël Posted July 31 Author Posted July 31 @FireWire Sure! Wouldn't say no to a PR implementing this. I think there's a long-standing feature request in the core for disabling modules (as opposed to completely uninstalling them). That would be the ideal solution of course 🙂 But yeah, having it in the module is a close second, I'd say. 1
FireWire Posted July 31 Posted July 31 1 minute ago, d'Hinnisdaël said: I think there's a long-standing feature request in the core for disabling modules (as opposed to completely uninstalling them). That would be the ideal solution of course That would be a great feature, however I will make a case for an implementation for your module. Since the module adds the lqip property and lqip() method to the image field object it would be important to selectively disable some features of the module and not others. It's important that they're always available so that there aren't any errors or unexpected behaviors. A full module disable might cause some of those. I'll send over the PR 👍
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now