wazum / thumb-hash
TYPO3 extension for generating ThumbHash for images. Enhance user experience with fast image thumbnails.
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 0
Type:typo3-cms-extension
Requires
- php: ^8.2
- ext-gd: *
- srwiez/thumbhash: ^1.4
- typo3/cms-core: ^12.4 || ^13.4
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.86
- phpunit/phpunit: ^11.5
- squizlabs/php_codesniffer: ^3.13
- vimeo/psalm: ^6.13
Suggests
- ext-imagick: Recommended for better alpha channel precision. ImageMagick provides more accurate alpha transparency handling than GD.
This package is auto-updated.
Last update: 2025-09-05 20:33:54 UTC
README
Enhance user experience with fast, ultra-compact, and appealing image placeholders for TYPO3 websites.
ThumbHash creates placeholders in just ~28 bytes ✨ that accurately represent your images while they load. It seamlessly enhances native lazy loading (loading="lazy"
) by showing a meaningful preview until the image appears.
Benefits at a Glance
- Show a soft, on‑brand preview while images load — no more empty space.
- No extra image files, no extra requests — just a few characters embedded alongside your image.
- Works automatically with your existing TYPO3 images, templates and lazy loading (
loading="lazy"
or JS libraries).
Perfect For
- Product listings and category grids (e‑commerce)
- News teasers and card layouts (publishers)
- Portfolios, galleries and hero images (agencies/creatives)
- Landing pages with many visuals (marketing)
- Any site where images load over slow networks or on mobile
What Makes It Great
- Tiny & Fast: About 25–35 bytes per image; nothing else to download.
- Smooth UX: Beautiful blurred preview that matches the final image and prevents layout shift.
- Automatic: Generated on upload and for every cropped/processed variant.
- Drop‑in: A single Fluid attribute adds the placeholder to your images.
Quick Start
composer require wazum/thumb-hash
<!-- The 'thumbhash' namespace is globally registered, no import needed --> <f:image image="{image}" loading="lazy" additionalAttributes="{data-thumbhash: '{thumbhash:thumbHash(file: image)}'}" />
Output: <img src="..." loading="lazy" data-thumbhash="3OcRJYB4d3h/iIeHeEh3eIhw+j3A" alt="">
That's it! Hashes are generated automatically on upload. Add the frontend JavaScript for the blur effect.
Use Cases
- E‑commerce lists: Give shoppers instant visual context while product images stream in.
- News portals: Keep article cards readable without jarring pop‑in as thumbnails load.
- Portfolios & galleries: Maintain composition and color feel while high‑res shots load.
- Hero banners: Avoid a blank hero on slow connections; show a pleasant preview immediately.
- Long pages with lazy images: Reduce perceived wait time as users scroll.
- Low‑bandwidth audiences: Improve mobile experience in regions with spotty coverage.
Why ThumbHash?
The Problem
When images load on slow connections, users see:
- Empty gray rectangles that suddenly pop into images
- Layout shifts as images load with different aspect ratios
- Poor perceived performance
The Solution
ThumbHash generates tiny placeholders that:
- Show a blurred preview of the actual image
- Preserve the exact aspect ratio
- Fade smoothly into the loaded image
- Work without additional network requests
Visual Demo
↓ Encoded to just 28 bytes (on the server) ↓
3OcRJYB4d3h/iIeHeEh3eIhw+j3A
↓ Decoded to placeholder (on the client) ↓
What your users will see while the image is loading:

From a 200 KB image → to 28 characters → back to a beautiful placeholder that preserves colors, composition, and aspect ratio.
Try the interactive demo with your own images →
Photo by Frank Cone: https://www.pexels.com/photo/lightning-strikes-2258536/
How It Compares
Size | Quality | Network Requests | Aspect Ratio | |
---|---|---|---|---|
ThumbHash | ~25-35 bytes¹ | Excellent | None | Preserved |
BlurHash (alternative) | 20-30 chars² | Good | None | Not preserved |
LQIP (webp) | 150-350 bytes³ | Good | 1 per image | Preserved |
Solid Color | ~7 bytes | Poor | None | Not preserved |
¹ThumbHash documentation
²BlurHash repository
³LQIP Modern benchmarks
Features
- Automatic generation — Hashes are created when images are uploaded
ProcessedFile
support — Each cropped variant gets its own placeholder- Database storage — Hashes are stored in
sys_file_metadata
andsys_file_processedfile
- Multiple processors — Supports both GD and ImageMagick
- ViewHelper integration — Simple Fluid template integration
- Event-driven — Responds to TYPO3 file events automatically
- Console command — Process existing files via CLI with
thumbhash:generate
- Scheduler support — Run batch processing as scheduled tasks
- Minified JavaScript — Ready-to-use decoder included
FAQ
- Does this slow down my site? No. The hash is embedded as a tiny string — there are no extra requests. Images load as usual; users just see a better preview.
- What if JavaScript is disabled? Images still load normally. The JS only paints the blurred background until the image finishes loading.
- Does this replace lazy loading? No. Keep using
loading="lazy"
(or your lazy‑loading library). ThumbHash complements it by filling the visual gap with a matching preview while the image is deferred. - Does this affect SEO or accessibility? No. Your
alt
text, dimensions and markup remain unchanged; placeholders help prevent layout shifts that can harm Core Web Vitals. - Which image types are supported? JPEG, PNG, GIF by default; you can adjust allowed MIME types. Works regardless of your output format (e.g., WebP/AVIF delivery).
- Will it work with cropped images and variants? Yes. Every processed variant gets its own accurate placeholder.
- Can I turn it off for certain folders? Yes. Use configuration to exclude folders for original files while still handling processed variants.
Installation
composer require wazum/thumb-hash
The extension works out of the box with sensible defaults. After installation:
- Go to Admin Tools > Maintenance > Analyze Database Structure to add the required database fields
- New uploads generate ThumbHash values automatically
- Existing images can be processed using the command line tool
- Configuration can be adjusted in the Admin Tools > Settings > Extension Configuration section if needed
Usage
In Fluid Templates
The extension globally registers the thumbhash
namespace, so you can use it immediately:
<f:image image="{image}" loading="lazy" additionalAttributes="{data-thumbhash: '{thumbhash:thumbHash(file: image)}'}" />
If you prefer explicit namespace imports (optional, since it's globally registered):
<html xmlns:thumbhash="http://typo3.org/ns/Wazum/ThumbHash/ViewHelpers" data-namespace-typo3-fluid="true"> <!-- Your template --> </html>
This generates the following HTML output:
<img src="/fileadmin/images/photo.jpg" width="1200" height="800" loading="lazy" data-thumbhash="3OcRJYB4d3h/iIeHeEh3eIhw+j3A" alt="">
The ViewHelper works with File
, FileReference
, and ProcessedFile
objects.
Command Line Tool
Generate ThumbHash values for existing files that don't have them yet:
# Process up to 100 files (default) vendor/bin/typo3 thumbhash:generate # Process a specific number of files vendor/bin/typo3 thumbhash:generate --limit=500 # Process all files (use with caution on large installations) vendor/bin/typo3 thumbhash:generate --limit=999999
The command:
- Processes both original files and their processed variants
- Respects the extension configuration (allowed MIME types, excluded folders)
- Shows progress for each processed file
- Skips files that already have hashes
- Can be run as a scheduler task for automatic processing
Scheduler Configuration:
- Go to System > Scheduler
- Create a new task of type "Execute console commands"
- Select thumbhash:generate from the dropdown
- Set options (e.g.,
--limit=50
) - Configure the schedule (e.g., daily at night)
Frontend Implementation
Note: ThumbHash uses progressive enhancement — images load normally even with JavaScript disabled. The placeholder effect is a visual enhancement only. It also complements native lazy loading and JS lazy‑loading libraries by providing an instant visual preview while the browser defers the image.
The extension includes a minified ThumbHash decoder at Resources/Public/JavaScript/thumb-hash.min.js
that provides the thumbHashToDataURL
function.
Add to your PAGE setup
Add your initialization code after the page (and all the images):
page {
includeJS {
thumbHash = EXT:thumb_hash/Resources/Public/JavaScript/thumb-hash.min.js
thumbHash.forceOnTop = 1
}
10 = FLUIDTEMPLATE
10 {
…
}
20 = TEXT
20.value (
<script>
document.querySelectorAll('[data-thumbhash]').forEach(function(img) {
var hash = img.dataset.thumbhash;
if (!hash) return;
var bytes = new Uint8Array(atob(hash).split('').map(function(c) {
return c.charCodeAt(0);
}));
var dataUrl = thumbHashToDataURL(bytes);
img.style.background = 'url(' + dataUrl + ') center/cover no-repeat';
img.addEventListener('load', function() {
img.style.background = '';
}, { once: true });
});
</script>
)
}
Configuration
Extension configuration allows you to customize:
- autoGenerate — Enable/disable automatic generation (default: true)
- allowedMimeTypes — Supported MIME types (default: image/jpeg,image/jpg,image/png,image/gif)
- excludedFolders — Folders to skip for original files only (default: fileadmin/processed/,fileadmin/temp/)
- Note: Processed file variants are always handled regardless of folder exclusions, ensuring cropped/resized images get their own accurate placeholders
- imageProcessor — Select processing backend:
auto
|imagick
|gd
auto
triesimagick
→gd
- Explicit choices have no fallback. Ensure the dependency exists (e.g., PHP Imagick extension for
imagick
). - Set via Install Tool: Admin Tools → Settings → Extension Configuration →
thumb_hash
or in configuration:$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['thumb_hash']['imageProcessor'] = 'gd';
Architecture
Storage
- Original images:
sys_file_metadata.thumb_hash
- Processed images:
sys_file_processedfile.thumb_hash
Event Listeners
AfterFileAddedEvent
— Generate for new uploads (respects folder exclusions)AfterFileProcessingEvent
— Generate for processed variants (ignores folder exclusions)AfterFileReplacedEvent
— Regenerate when files change (respects folder exclusions)
Image Processing
Processor selection respects the imageProcessor
setting. With auto
, priority is:
- Imagick (PHP extension) — High quality, good alpha handling
- GD — Ubiquitous fallback
Why no CLI (GraphicalFunctions) support?
- External process overhead is large (hundreds of ms/iter), dominated by process spawn and TXT I/O.
- Placeholder generation downsamples to ≤100px; color/alpha precision gains from CLI paths are negligible compared to GD/Imagick.
- Benchmarks showed GD/Imagick are orders of magnitude faster with indistinguishable results at this size.
User Experience Benefits
ThumbHash enhances perceived performance:
- Eliminates layout shift — Placeholders reserve the exact space needed, preventing content jumping
- Instant visual feedback — Users see a meaningful preview immediately instead of empty rectangles
- Smoother loading experience — Images fade in gracefully from their blurred placeholders
- Better perceived performance — The page feels faster even though actual load times remain the same
Requirements
- TYPO3 CMS 12.4+ or 13.4+
- PHP 8.2+
- GD PHP extension (required; fallback processor and part of standard TYPO3 installs)
- Imagick PHP extension (optional but recommended), otherwise GD is used
- Composer dependency:
srwiez/thumbhash ^1.4
Notes:
- You can choose the processor via
imageProcessor
(auto|imagick|gd). Explicit choices have no fallback.
License
GNU General Public License version 2 or later (GPL-2.0-or-later)
Credits
ThumbHash algorithm by Evan Wallace