askancy / laravel-smart-thumbnails
Advanced thumbnail generation with smart cropping for Laravel applications
Requires
- php: ^8.1
- ext-gd: *
- intervention/image: ^2.7
- laravel/framework: ^10.0|^11.0|^12.0
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0|^11.0
README
The most advanced thumbnail generation package for Laravel with intelligent cropping, multi-disk support, subdirectory organization, and bulletproof error handling that never breaks your application.
๐ Features
- โจ Smart Crop Algorithm - Based on dont-crop with energy detection
- ๐ก๏ธ Bulletproof Error Handling - Never breaks your application, always shows something
- ๐ Subdirectory Organization - Handles millions of thumbnails with optimal filesystem performance
- ๐พ Multi-Disk Support - S3, local, scoped disks, and custom storage solutions
- ๐จ Multiple Variants - Responsive design with preset variants
- ๐ Lazy Generation - Thumbnails created only when needed
- ๐ Intelligent Fallbacks - Original image โ Custom placeholder โ Generated placeholder
- โก High Performance - Optimized for large-scale applications
- ๐๏ธ Maintenance Commands - Purge, optimize, and analyze thumbnails
- ๐งช Fully Tested - Comprehensive PHPUnit test suite
๐ Requirements
- PHP 8.1+
- Laravel 10.0+
- Intervention Image 2.7+ or 3.0+
- GD or ImageMagick extension
๐ฆ Installation
Install via Composer:
composer require askancy/laravel-smart-thumbnails
Publish configuration:
php artisan vendor:publish --tag=laravel-smart-thumbnails-config
๐ก๏ธ Error-Safe Usage (Recommended)
The package offers bulletproof error handling that ensures your application never breaks due to missing images or storage issues.
Silent Mode (Never Fails)
{{-- โ NEVER throws exceptions, always shows something --}} <img src="{{ Thumbnail::set('gallery')->src($photo->path, 's3')->urlSafe() }}" alt="Gallery"> {{-- โ Explicit silent mode --}} <img src="{{ Thumbnail::silent()->set('products')->src($image, 's3')->url('thumb') }}" alt="Product">
Strict Mode (For Development/Admin)
{{-- โ ๏ธ May throw exceptions for debugging --}} <img src="{{ Thumbnail::strict()->set('gallery')->src($photo->path, 's3')->url() }}" alt="Gallery"> {{-- โ ๏ธ Standard mode (configurable default) --}} <img src="{{ Thumbnail::set('gallery')->src($photo->path, 's3')->url('large') }}" alt="Gallery">
๐ฏ Quick Examples
Responsive Blog Headers
<picture> <source media="(max-width: 640px)" srcset="{{ Thumbnail::set('blog')->src($post->image, 's3')->urlSafe('card') }}"> <source media="(min-width: 641px)" srcset="{{ Thumbnail::set('blog')->src($post->image, 's3')->urlSafe('hero') }}"> <img src="{{ Thumbnail::set('blog')->src($post->image, 's3')->urlSafe('hero') }}" alt="{{ $post->title }}" loading="lazy"> </picture>
Homepage Slider (Never Breaks)
<div class="hero-slider"> @foreach($slides as $slide) <div class="slide"> {{-- This slider will NEVER break, even with missing images --}} <img src="{{ Thumbnail::set('slider')->src($slide->image, 's3')->urlSafe('desktop') }}" alt="Hero Slide" loading="lazy"> </div> @endforeach </div>
โ๏ธ Advanced Configuration
Multi-Disk Setup
// config/filesystems.php 'disks' => [ 's3_products' => [ 'driver' => 'scoped', 'disk' => 's3', 'prefix' => 'products', ], 's3_gallery' => [ 'driver' => 'scoped', 'disk' => 's3', 'prefix' => 'gallery', ], ],
Preset Configuration
// config/thumbnails.php 'presets' => [ 'products' => [ 'format' => 'webp', 'smartcrop' => '400x400', 'destination' => ['disk' => 's3_products', 'path' => 'thumbnails/'], 'quality' => 90, 'smart_crop_enabled' => true, 'silent_mode' => false, // Strict for admin 'subdirectory_strategy' => 'hash_prefix', // Optimal for high volume 'variants' => [ 'thumb' => ['smartcrop' => '120x120', 'quality' => 75], 'card' => ['smartcrop' => '250x250', 'quality' => 85], 'detail' => ['smartcrop' => '600x600', 'quality' => 95], 'zoom' => ['smartcrop' => '1200x1200', 'quality' => 95], ] ], ],
๐ Subdirectory Organization
Handle millions of thumbnails efficiently with automatic subdirectory organization:
Hash Prefix Strategy (Recommended)
thumbnails/products/
โโโ a/b/ (47 files)
โโโ c/d/ (52 files)
โโโ e/f/ (48 files)
โโโ ... (256 total directories)
Date-Based Strategy
thumbnails/blog/
โโโ 2025/01/28/ (today's posts)
โโโ 2025/01/27/ (yesterday's posts)
โโโ 2025/01/26/ (older posts)
Configuration
'subdirectory_strategy' => 'hash_prefix', // Uniform distribution (recommended) 'subdirectory_strategy' => 'date_based', // Organized by date 'subdirectory_strategy' => 'filename_prefix', // By filename initials 'subdirectory_strategy' => 'hash_levels', // Multi-level (a/b/c/) 'subdirectory_strategy' => 'none', // No subdirectories
๐ง Smart Crop Algorithm
Advanced intelligent cropping based on image energy analysis:
// Enable smart crop for better results 'smart_crop_enabled' => true, // Uses energy detection algorithm 'smart_crop_enabled' => false, // Uses simple center crop
How it works:
- Analyzes image energy using gradient magnitude
- Finds areas of interest based on contrast and details
- Avoids aggressive cropping that removes important subjects
- Uses rule of thirds for optimal positioning
๐ ๏ธ Artisan Commands
Purge Thumbnails
# Purge all thumbnails php artisan thumbnail:purge # Purge specific preset php artisan thumbnail:purge products # Silent purge (no confirmation) php artisan thumbnail:purge products --confirm
Statistics & Analysis
php artisan tinker >>> Thumbnail::analyzeDistribution('products') >>> Thumbnail::getSystemStats() >>> Thumbnail::optimize() // Remove duplicates and empty directories
๐๏ธ Advanced Features
Conditional Error Handling
{{-- Admin sees errors, users get safe fallbacks --}} @admin <img src="{{ Thumbnail::strict()->set('gallery')->src($image, 's3')->url() }}" alt="Gallery"> @else <img src="{{ Thumbnail::silent()->set('gallery')->src($image, 's3')->url() }}" alt="Gallery"> @endadmin
Performance Optimization
// config/thumbnails.php 'optimization_profiles' => [ 'high_volume' => [ 'subdirectory_strategy' => 'hash_prefix', 'quality' => 75, 'silent_mode' => true, ], 'high_quality' => [ 'quality' => 95, 'webp_lossless' => true, 'silent_mode' => false, ], ],
Batch Processing
// Process multiple thumbnails efficiently 'batch_size' => 50, 'batch_timeout' => 300, 'queue_enabled' => true, // Use Laravel queues
Security Features
'allowed_extensions' => ['jpg', 'jpeg', 'png', 'webp', 'gif'], 'max_file_size' => 10 * 1024 * 1024, // 10MB 'validate_image_content' => true, 'sanitize_filenames' => true,
๐ Monitoring & Statistics
System Analysis
// Get complete system statistics $stats = Thumbnail::getSystemStats(); // Returns: total files, size, distribution by disk, preset analysis // Analyze specific preset $analysis = Thumbnail::analyzeDistribution('products'); // Returns: file count, size, directory distribution, format breakdown
Performance Monitoring
'enable_stats' => true, 'log_generation_time' => true, 'monitor_disk_usage' => true,
๐ง Troubleshooting
Common Issues
# Test disk connectivity php artisan tinker >>> Thumbnail::testDisk('s3_products') # Validate configuration >>> Thumbnail::validateConfiguration() # Clear Laravel caches php artisan config:clear php artisan cache:clear
Debug Mode
{{-- Debug information in development --}} @if(app()->environment('local')) @foreach(Thumbnail::getAvailableDisks() as $disk) @php $status = Thumbnail::testDisk($disk) @endphp <p>{{ $disk }}: {{ $status['accessible'] ? 'โ ' : 'โ' }}</p> @endforeach @endif
๐ Performance Benefits
Files | Without Subdirectories | With Hash Prefix |
---|---|---|
1,000 | โ ๏ธ Slow | โ Fast |
10,000 | โ Very Slow | โ Fast |
100,000 | โ Unusable | โ Fast |
1,000,000 | โ Impossible | โ Fast |
With subdirectories:
- ๐ 200x faster filesystem operations
- ๐ Instant directory listings
- โก Efficient backup and sync
- ๐ฏ Optimal for CDN delivery
๐ค Contributing
We welcome contributions! Please see CONTRIBUTING.md for details.
๐ License
MIT License. See LICENSE.md for details.
๐ Credits
๐ก Pro Tip: Always use
urlSafe()
orsilent()
for public-facing content and reservestrict()
mode for admin interfaces and development!