jcfrane/laravel-lens

Configuration-driven image manipulation and caching for Laravel, inspired by LiipImagineBundle

Maintainers

Package info

github.com/jcfrane/laravel-lens

pkg:composer/jcfrane/laravel-lens

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-03-13 09:33 UTC

This package is auto-updated.

Last update: 2026-03-13 09:43:12 UTC


README

Latest Version on Packagist GitHub Tests Action Status Total Downloads License

Configuration-driven image manipulation and caching for Laravel, inspired by Symfony's LiipImagineBundle.

Define named filter sets in your config, and Laravel Lens handles the rest — lazy processing on first request, automatic caching, and simple Blade integration. Built on top of Intervention Image and Laravel's filesystem abstraction, it works with any storage driver out of the box.

Quick Examples

Define filter sets in your config:

// config/lens.php
'filter_sets' => [
    'avatar' => [
        'quality' => 80,
        'filters' => [
            ['name' => 'auto_orient'],
            ['name' => 'thumbnail', 'options' => ['size' => [150, 150], 'mode' => 'outbound']],
        ],
    ],
    'hero_banner' => [
        'quality' => 90,
        'format' => 'webp',
        'filters' => [
            ['name' => 'resize', 'options' => ['size' => [1200, null]]],
            ['name' => 'blur', 'options' => ['amount' => 5]],
        ],
    ],
],

Use them anywhere in your application:

// Blade directive
<img src="@lens('photos/profile.jpg', 'avatar')" alt="Profile" />

// Blade component
<x-lens-image path="photos/hero.jpg" filter="hero_banner" alt="Hero" class="w-full" />

// Facade
$url = Lens::url('photos/profile.jpg', 'avatar');

// API route (auto-registered)
// GET /lens/avatar/photos/profile.jpg

Features

  • Configuration-driven filter sets — define once, use everywhere
  • 14 built-in filters — thumbnail, crop, resize, scale, watermark, grayscale, flip, rotate, blur, brightness, contrast, background, strip, auto_orient
  • Lazy processing — images are processed on first request, then served from cache
  • Multiple storage drivers — works with local disk, S3, or any Laravel filesystem driver
  • Blade integration@lens() directive and <x-lens-image /> component
  • Built-in API route/lens/{filterSet}/{path} for on-demand processing
  • Cache management — Artisan commands for clearing and warming up the cache
  • Multiple drivers — GD and Imagick support via Intervention Image
  • Runtime overrides — pass options at call time without creating new filter sets
  • Extensible — register custom filters with a simple interface

Requirements

  • PHP 8.2+
  • Laravel 12
  • GD or Imagick PHP extension

Installation

composer require jcfrane/laravel-lens

Publish the configuration file:

php artisan vendor:publish --tag=lens-config

Configuration

The published config file (config/lens.php) contains all settings:

Driver

'driver' => env('LENS_DRIVER', 'gd'), // 'gd' or 'imagick'

Data Loader

Configure where source images are loaded from. Uses Laravel filesystem disks:

'data_loader' => [
    'default' => 'filesystem',
    'loaders' => [
        'filesystem' => [
            'driver' => 'filesystem',
            'disk' => env('LENS_SOURCE_DISK', 'public'),
            'base_path' => '',
        ],
    ],
],

Cache

Configure where processed images are stored:

'cache' => [
    'default' => 'filesystem',
    'resolvers' => [
        'filesystem' => [
            'driver' => 'filesystem',
            'disk' => env('LENS_CACHE_DISK', 'public'),
            'base_path' => 'lens-cache',
        ],
    ],
],

Filter Sets

Each filter set defines an ordered pipeline of filters:

'filter_sets' => [
    'thumbnail_small' => [
        'quality' => 80,          // encoding quality (1-100)
        'format' => null,         // null = keep original, or 'webp', 'jpeg', 'png'
        'cache' => null,          // null = use default cache resolver
        'data_loader' => null,    // null = use default data loader
        'filters' => [
            ['name' => 'auto_orient'],
            ['name' => 'thumbnail', 'options' => [
                'size' => [150, 150],
                'mode' => 'outbound',  // 'outbound' (cover) or 'inset' (contain)
            ]],
        ],
    ],
],

Routes

'route' => [
    'enabled' => true,
    'prefix' => 'lens',
    'middleware' => ['web'],
    'signed' => false,
],

Usage

Blade Directive

<img src="@lens('photos/landscape.jpg', 'thumbnail_small')" alt="Landscape" />

Blade Component

<x-lens-image path="photos/landscape.jpg" filter="thumbnail_small" alt="Landscape" class="rounded shadow" />

The component renders an <img> tag with the filtered image URL and passes through any additional HTML attributes.

Facade

use JCFrane\LaravelLens\Facades\Lens;

// Get the URL for a filtered image
$url = Lens::url('photos/landscape.jpg', 'thumbnail_small');

// Process and cache an image immediately
$binary = Lens::resolve('photos/landscape.jpg', 'thumbnail_small');

// Check if a filtered image is cached
$cached = Lens::isCached('photos/landscape.jpg', 'thumbnail_small');

// Invalidate cached images
Lens::invalidate('photos/landscape.jpg');
Lens::invalidate('photos/landscape.jpg', ['thumbnail_small']);

Runtime Filter Overrides

Override filter options at call time without creating a new filter set:

$url = Lens::url('photo.jpg', 'thumbnail_small', [
    'thumbnail' => ['size' => [200, 200]],
]);

API Route

The package auto-registers a route for on-demand image processing:

GET /lens/{filterSet}/{path}

On the first request, the image is processed through the filter pipeline and cached. Subsequent requests are served from cache with a redirect.

Example: /lens/thumbnail_small/photos/landscape.jpg

Available Filters

Filter Options Description
auto_orient Rotate based on EXIF orientation data
thumbnail size, mode, upscale Scale and/or crop to thumbnail dimensions
crop size, start Crop a rectangular region
resize size Resize to exact dimensions
scale size Scale proportionally
watermark image, position, opacity, size Overlay a watermark image
grayscale Convert to grayscale
flip direction Mirror horizontally or vertically
rotate angle, background Rotate by degrees
blur amount Apply Gaussian blur
brightness level Adjust brightness (-100 to 100)
contrast level Adjust contrast (-100 to 100)
background color, size, position Set or extend canvas with background color
strip Remove animation frames

Custom Filters

Create a class implementing FilterInterface:

use Intervention\Image\Interfaces\ImageInterface;
use JCFrane\LaravelLens\Contracts\FilterInterface;

class SepiaFilter implements FilterInterface
{
    public function apply(ImageInterface $image, array $options = []): ImageInterface
    {
        return $image->greyscale()->brightness(-10)->contrast(10);
    }

    public function name(): string
    {
        return 'sepia';
    }
}

Register it in a service provider:

use JCFrane\LaravelLens\Facades\Lens;

Lens::filterManager()->register('sepia', new SepiaFilter());

Then use it in your filter sets:

'filter_sets' => [
    'vintage' => [
        'filters' => [
            ['name' => 'sepia'],
            ['name' => 'blur', 'options' => ['amount' => 2]],
        ],
    ],
],

Artisan Commands

# Clear all cached images
php artisan lens:cache:clear

# Clear cache for a specific filter set
php artisan lens:cache:clear --filter=thumbnail_small

# Clear cache for a specific image
php artisan lens:cache:clear --path=photos/old-image.jpg

# Pre-generate cached images
php artisan lens:cache:warmup --path=photos/hero.jpg --path=photos/logo.png

# Warm up specific filter sets only
php artisan lens:cache:warmup --path=photos/hero.jpg --filter=thumbnail_small --filter=thumbnail_medium

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security-related issues, please use the issue tracker.

Credits

Acknowledgments

License

The MIT License (MIT). Please see License File for more information.