Plugin provides powerful Twig filters for manipulating images on-the-fly with automatic caching and optimization.
- Easy-to-use Twig filters for image manipulation
- Automatic caching of manipulated images
- Built-in image optimization
- WebP format conversion
- Watermark support
- Multiple image effects (blur, pixelate, greyscale, sepia, sharpen)
- Color adjustments (brightness, contrast, gamma, colorize)
- Quality control
- Image dimension getters
- Base64 encoding support
- No backend UI required - works directly in templates
- Based on robust Spatie Image package
Something that is free has little or no perceived value. Users do not commit to free products and only use them until something else looks nice and is free comes along. When I invest my time in the development of a new plugin I commit to supporting and maintaining it. I ask my customers to do the same. I do not make money from this plugin by advertisements, upgrades or additional services like hosting or setup.
Did you know that 30% of your purchase or donation goes to help fund the October Project?
My plugins take many hours to develop (40-120+) and even more hours to document and maintain. My paid plugins have to pay for both this time, and the time I am spending on free plugins and less successful paid plugins. This means that it will take even a successful plugin years to become profitable. Please consider buying an extended license if you want me to continue to maintain these plugins for the very small fee I ask in return or hire me for adding functionality that you feel is missing but valuable.
If you like this plugin, give this plugin a Like or Make donation with PayPal.
Please check my other plugins.
Please use GitHub Issues Page to report any issues with plugin.
Reviews should not be used for getting support, if you need support please use the Plugin support link.
Icon made by Freepik from www.flaticon.com.
- October CMS v4.0 or higher
- PHP 8.2 or higher
- GD or Imagick PHP extension
- Composer
- Navigate to Settings → Updates & Plugins in your October CMS backend
- Click Install plugins
- Search for "Renatio Image"
- Click Install
composer require renatio/image-pluginAfter installation, run the migrations (although this plugin doesn't require database tables):
php artisan october:migrateThe Image plugin registers Twig filters that you can use directly in your templates. When you apply a filter to an image:
- The plugin checks if a manipulated version already exists in the cache
- If not, it creates the manipulated image using the Spatie Image library
- The manipulated image is automatically optimized
- The result is saved to
storage/app/uploads/public/manipulations/ - Subsequent requests serve the cached version for optimal performance
Cached file names are generated using MD5 hashing based on:
- Original image path
- Manipulation type
- Manipulation parameters
- Original file modification time
This ensures that:
- Cache is automatically invalidated when source images change
- Different manipulations of the same image are cached separately
- Cache files have unique, collision-free names
All filters are available in Twig templates. Simply pipe your image path through any filter:
{# Apply greyscale effect #}
<img src="{{ 'path/to/image.jpg'|greyscale }}" alt="Greyscale image">
{# Chain multiple filters #}
<img src="{{ 'path/to/image.jpg'|brightness(20)|contrast(1.2)|sharpen(15) }}" alt="Enhanced image"><picture>
<source srcset="{{ 'assets/images/hero.jpg'|webp }}" type="image/webp">
<img src="{{ 'assets/images/hero.jpg' }}" alt="Hero image">
</picture>Adjust image brightness.
Parameters:
brightness(int): Brightness level from -100 (darker) to +100 (brighter)
Example:
{# Increase brightness #}
<img src="{{ 'images/dark-photo.jpg'|brightness(30) }}">
{# Decrease brightness #}
<img src="{{ 'images/bright-photo.jpg'|brightness(-20) }}">Adjust image contrast.
Parameters:
level(float): Contrast level. Use values like 0.5 (low contrast), 1.0 (normal), 1.5 (high contrast)
Example:
<img src="{{ 'images/photo.jpg'|contrast(1.3) }}">Adjust image gamma correction.
Parameters:
gamma(float): Gamma value. Typical range: 0.1 to 3.0
Example:
<img src="{{ 'images/photo.jpg'|gamma(1.5) }}">Apply color tint to image.
Parameters:
red(int): Red channel adjustment (-255 to +255)green(int): Green channel adjustment (-255 to +255)blue(int): Blue channel adjustment (-255 to +255)
Example:
{# Add red tint #}
<img src="{{ 'images/photo.jpg'|colorize(100, 0, 0) }}">
{# Add sepia-like tint #}
<img src="{{ 'images/photo.jpg'|colorize(100, 50, -50) }}">Apply blur effect to image.
Parameters:
blur(int): Blur amount (0-100, higher values = more blur)
Example:
<img src="{{ 'images/background.jpg'|blur(15) }}">Apply pixelation effect to image.
Parameters:
pixelate(int, optional): Pixel block size. Default: 50
Example:
{# Default pixelation #}
<img src="{{ 'images/photo.jpg'|pixelate }}">
{# Custom pixel size #}
<img src="{{ 'images/photo.jpg'|pixelate(20) }}">Convert image to greyscale (black and white).
Parameters: None
Example:
<img src="{{ 'images/color-photo.jpg'|greyscale }}">Alternative spelling:
<img src="{{ 'images/color-photo.jpg'|grayscale }}">Apply sepia tone effect to image.
Parameters: None
Example:
<img src="{{ 'images/photo.jpg'|sepia }}">Sharpen image details.
Parameters:
amount(float): Sharpening amount (typical range: 10-50)
Example:
<img src="{{ 'images/blurry-photo.jpg'|sharpen(25) }}">Add watermark image overlay.
Parameters:
watermarkImage(string, optional): Path to watermark image. Default:themes/demo/assets/images/watermark.pngoptions(array, optional): Additional watermark options (position, opacity, etc.)
Example:
{# Use default watermark #}
<img src="{{ 'images/photo.jpg'|watermark }}">
{# Use custom watermark #}
<img src="{{ 'images/photo.jpg'|watermark('assets/images/logo.png') }}">Note: Watermark positioning options are currently being developed. The watermark will be placed according to Spatie Image defaults.
Convert image to WebP format for better compression and web performance.
Parameters: None
Example:
{# Simple conversion #}
<img src="{{ 'images/photo.jpg'|webp }}">
{# Use in picture element for progressive enhancement #}
<picture>
<source srcset="{{ 'images/hero.jpg'|webp }}" type="image/webp">
<source srcset="{{ 'images/hero.jpg' }}" type="image/jpeg">
<img src="{{ 'images/hero.jpg' }}" alt="Hero image">
</picture>Optimize image file size without quality loss using image optimizers.
Parameters: None
Example:
<img src="{{ 'images/large-photo.jpg'|optimize }}">Note: This filter uses the Spatie Image Optimizer package which requires system-level optimizer binaries (optipng, pngquant, jpegoptim, etc.). See Installation Requirements for details.
Adjust image quality (compression level).
Parameters:
quality(int): Quality level (1-100, where 100 is highest quality/largest file size)
Example:
{# High quality for important images #}
<img src="{{ 'images/portfolio-item.jpg'|quality(90) }}">
{# Lower quality for thumbnails #}
<img src="{{ 'images/thumbnail.jpg'|quality(70) }}">Encode image as Base64 data URI for embedding directly in HTML.
Parameters:
imageFormat(string, optional): Output format ('jpeg', 'png', 'gif', 'webp'). Default: 'jpeg'prefixWithFormat(bool, optional): Include data URI prefix. Default: true
Example:
{# Inline image as data URI #}
<img src="{{ 'images/small-icon.png'|base64 }}" alt="Icon">
{# Specify format #}
<img src="{{ 'images/logo.png'|base64('png') }}" alt="Logo">
{# Without data URI prefix (for CSS or other uses) #}
{% set imageData = 'images/icon.png'|base64('png', false) %}Best Practice: Only use Base64 encoding for small images (icons, small logos) to avoid bloating your HTML.
Get image width in pixels.
Parameters: None
Returns: int
Example:
{% set imageWidth = 'images/photo.jpg'|get_width %}
<p>Image width: {{ imageWidth }}px</p>
{# Use in conditional logic #}
{% if 'images/photo.jpg'|get_width > 1200 %}
<p>This is a large image</p>
{% endif %}Get image height in pixels.
Parameters: None
Returns: int
Example:
{% set imageHeight = 'images/photo.jpg'|get_height %}
<p>Image height: {{ imageHeight }}px</p>
{# Calculate aspect ratio #}
{% set width = 'images/photo.jpg'|get_width %}
{% set height = 'images/photo.jpg'|get_height %}
{% set aspectRatio = (height / width * 100)|round(2) %}
<p>Aspect ratio: {{ aspectRatio }}%</p>You can chain multiple filters together to create complex image manipulations:
{# Create a vintage photo effect #}
<img src="{{ 'images/photo.jpg'|sepia|contrast(0.8)|brightness(10)|sharpen(15) }}">
{# Optimize and convert to WebP #}
<img src="{{ 'images/photo.jpg'|optimize|webp }}">
{# Create blurred background image #}
<div style="background-image: url({{ 'images/bg.jpg'|blur(30)|brightness(-20) }})">
Content here
</div>Performance Note: Each filter in the chain creates a new manipulation. The plugin caches the final result, so chained filters don't impact runtime performance on subsequent requests.
{# Product image with optimization #}
<div class="product-image">
<picture>
<source srcset="{{ product.image|quality(85)|webp }}" type="image/webp">
<img src="{{ product.image|quality(85) }}" alt="{{ product.name }}">
</picture>
</div><section class="hero" style="background-image: url({{ 'images/hero.jpg'|blur(10)|brightness(-15) }})">
<div class="hero-content">
<h1>Welcome</h1>
</div>
</section>{% for image in gallery.images %}
<div class="gallery-item">
<img src="{{ image.path|greyscale }}"
data-color="{{ image.path }}"
alt="{{ image.title }}"
onmouseover="this.src=this.dataset.color"
onmouseout="this.src='{{ image.path|greyscale }}'">
</div>
{% endfor %}<div class="portfolio-grid">
{% for item in portfolio.items %}
<div class="portfolio-item">
<img src="{{ item.image|watermark('assets/images/logo.png')|quality(90) }}"
alt="{{ item.title }}">
</div>
{% endfor %}
</div>{% set imagePath = 'images/product.jpg' %}
{% set width = imagePath|get_width %}
{% set height = imagePath|get_height %}
<img src="{{ imagePath }}"
width="{{ width }}"
height="{{ height }}"
alt="Product"
loading="lazy">Manipulated images are stored in:
storage/app/uploads/public/manipulations/
Files are named using MD5 hashes to ensure uniqueness:
{md5_hash}.{extension}
The hash is generated from:
- Original image path
- Manipulation type
- Manipulation parameters
- Source file modification time
The cache is automatically invalidated when:
- The source image is modified (detected via file modification time)
- You manually delete the cached files
To clear the image manipulation cache:
# Remove all manipulated images
rm -rf storage/app/uploads/public/manipulations/*Or create a backend controller action:
use Illuminate\Support\Facades\File;
public function clearImageCache()
{
$path = storage_path('app/uploads/public/manipulations');
if (File::isDirectory($path)) {
File::deleteDirectory($path, true);
File::makeDirectory($path);
}
Flash::success('Image cache cleared successfully');
}Currently, the plugin uses hardcoded defaults. Configuration options may be added in future versions for:
- Cache directory path
- Optimization timeout (currently 120 seconds)
- Global optimization toggle
- Default watermark image path
- Default quality settings
The optimize filter requires system-level image optimizer binaries to be installed on your server.
sudo apt-get install jpegoptim optipng pngquant gifsicle webpbrew install jpegoptim optipng pngquant gifsicle webpDownload and install optimizers manually, or use tools like Chocolatey:
choco install jpegoptim optipng pngquant gifsicle webpCheck if optimizers are available:
which jpegoptim optipng pngquant gifsicle cwebpFor more details, see Spatie Image Optimizer documentation.
Possible causes:
- Source image path is incorrect
- GD or Imagick extension not installed
- Insufficient disk space
- Permission issues with storage directory
Solutions:
# Check if GD is installed
php -m | grep -i gd
# Check if Imagick is installed
php -m | grep -i imagick
# Fix storage permissions
chmod -R 775 storage/app/uploads/public/manipulations/
chown -R www-data:www-data storage/app/uploads/public/manipulations/Problem: The plugin can't find the source image.
Solution: Always use paths relative to your October CMS base directory:
{# ✅ Correct #}
<img src="{{ 'themes/mytheme/assets/images/photo.jpg'|blur(10) }}">
{# ❌ Incorrect - absolute path #}
<img src="{{ '/var/www/html/themes/mytheme/assets/images/photo.jpg'|blur(10) }}">Possible causes:
- Exception occurred during processing (silently caught)
- Source file doesn't exist
- Image manipulation failed
Debug:
Enable October CMS debug mode in config/app.php:
'debug' => true,Check October CMS log files:
tail -f storage/logs/system.logProblem: The optimize filter doesn't reduce file size significantly.
Possible causes:
- Optimizers not installed on the system
- Images already optimized
- Optimizer binaries not in system PATH
Solution: Verify optimizers are installed (see Optimizer Installation).
Problem: Watermark filter doesn't show the watermark.
Possible causes:
- Watermark image path is incorrect
- Watermark image doesn't exist
- Watermark positioning options need to be configured
Solution:
{# Verify watermark file exists #}
{% if 'themes/demo/assets/images/watermark.png'|file_exists %}
<img src="{{ 'images/photo.jpg'|watermark('themes/demo/assets/images/watermark.png') }}">
{% endif %}Problem: Image manipulation causes memory errors.
Possible causes:
- Processing very large images
- PHP memory limit too low
Solutions:
Increase PHP memory limit in php.ini:
memory_limit = 256MOr temporarily in your code:
ini_set('memory_limit', '256M');Consider resizing large images before applying filters:
{# Use October's |resize filter first #}
<img src="{{ 'images/huge-photo.jpg'|resize(1920, 1080)|blur(10) }}">Problem: WebP filter doesn't convert images.
Possible causes:
- GD or Imagick doesn't support WebP
- WebP libraries not installed
Solutions:
Verify WebP support:
# For GD
php -r "var_dump(function_exists('imagewebp'));"
# For Imagick
php -r "var_dump(in_array('WEBP', \Imagick::queryFormats()));"Install WebP libraries:
# Ubuntu/Debian
sudo apt-get install libwebp-dev
# Rebuild PHP with WebP support or install/enable imagick extensionProblem: Can't write to cache directory.
Solution:
# Create directory if it doesn't exist
mkdir -p storage/app/uploads/public/manipulations
# Set correct permissions
chmod -R 775 storage/app/uploads/public/manipulations/
chown -R www-data:www-data storage/app/uploads/public/manipulations/
# For development (less secure, don't use in production)
chmod -R 777 storage/app/uploads/public/manipulations/The plugin includes comprehensive tests using Pest PHP.
# Run all Image plugin tests
php artisan test --testsuite="Image Plugin"
# Run specific test file
php artisan test plugins/renatio/image/tests/Unit/Classes/ImageManipulationTest.php
# Run with coverage
php artisan test --testsuite="Image Plugin" --coverageFor detailed testing documentation, see tests/README.md.
-
Use appropriate quality settings: Balance file size and visual quality
{# Good for web #} <img src="{{ image|quality(85) }}">
-
Chain filters efficiently: Order filters to minimize processing
{# Optimize last #} <img src="{{ image|brightness(10)|contrast(1.2)|optimize }}">
-
Leverage caching: The first request processes the image; subsequent requests serve from cache
-
Use WebP for modern browsers: Significantly smaller file sizes
<picture> <source srcset="{{ image|webp }}" type="image/webp"> <img src="{{ image }}" alt="Fallback"> </picture>
-
Avoid processing very large images: Resize before manipulating if possible
- First request: ~100-500ms (depending on image size and manipulations)
- Cached requests: ~1-5ms (serving static files)
- Storage impact: Manipulated images are stored permanently until cache is cleared
While designed for Twig templates, you can use the ImageManipulation class directly in PHP:
use Renatio\Image\Classes\ImageManipulation;
$imageManipulation = new ImageManipulation();
// Apply brightness
$brightImage = $imageManipulation->brightness('path/to/image.jpg', 30);
// Apply blur
$blurredImage = $imageManipulation->blur('path/to/image.jpg', 20);
// Get image dimensions
$width = $imageManipulation->getWidth('path/to/image.jpg');
$height = $imageManipulation->getHeight('path/to/image.jpg');
// Convert to WebP
$webpImage = $imageManipulation->webp('path/to/image.jpg');This plugin is built on top of these excellent packages:
- Spatie Image - Image manipulation library
- Spatie Image Optimizer - Image optimization
- Intervention Image - Underlying image processing (used by Spatie Image)
This is a proprietary commercial plugin. License is granted per October CMS installation.
See UPGRADE.md for version history and upgrade notes.
