Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Image Optimizer Laravel Package

spatie/laravel-image-optimizer

Laravel integration for spatie/image-optimizer. Optimize PNG, JPG, SVG, and GIF files by running them through available system binaries. Use the ImageOptimizer facade, resolve an OptimizerChain from the container, or apply middleware to optimize uploads automatically.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require spatie/laravel-image-optimizer
    

    Run migrations if using the optional optimized_images table:

    php artisan migrate
    
  2. First Use Case: Optimize an image file directly:

    use Spatie\ImageOptimizer\OptimizerChain;
    
    $optimizer = app(OptimizerChain::class);
    $optimizer->optimize(storage_path('app/public/image.jpg'));
    
  3. Verify Tools: Check installed optimization tools via:

    php artisan image-optimizer:check
    

Where to Look First

  • README: Focus on the optimization tools section to understand supported binaries (e.g., jpegoptim, pngquant).
  • Configuration: Publish the config file for customization:
    php artisan vendor:publish --provider="Spatie\ImageOptimizer\ImageOptimizerServiceProvider"
    
    Key settings: default_optimizer, allowed_optimizers, and optimize_on_demand.

Implementation Patterns

Core Workflows

  1. On-Demand Optimization:

    // Optimize a single file
    $optimizer->optimize($filePath);
    
    // Optimize and save to a new path
    $optimizer->optimize($sourcePath, $destinationPath);
    
  2. Batch Processing: Use Laravel’s Artisan::command to process directories:

    use Spatie\ImageOptimizer\OptimizerChain;
    use Illuminate\Support\Facades\File;
    
    $optimizer = app(OptimizerChain::class);
    $files = File::allFiles(storage_path('app/public/images'));
    foreach ($files as $file) {
        $optimizer->optimize($file->pathname());
    }
    
  3. Middleware for Automatic Optimization: Attach to handle in App\Http\Middleware\OptimizeImages:

    public function handle($request, Closure $next) {
        $response = $next($request);
        if ($response->headers->get('Content-Type') === 'image/jpeg') {
            $path = storage_path('app/public/' . $response->getOriginalContent());
            $optimizer = app(OptimizerChain::class);
            $optimizer->optimize($path);
        }
        return $response;
    }
    
  4. Queue Optimization Jobs: Dispatch a job for async processing:

    use Spatie\ImageOptimizer\Jobs\OptimizeImage;
    
    OptimizeImage::dispatch($filePath)->onQueue('optimize');
    

Integration Tips

  • Storage Integration: Use Storage::disk('public')->put() with optimized files to leverage Laravel’s filesystem. Example:

    $optimizer->optimize($source, $destination);
    Storage::disk('public')->put($destination, file_get_contents($destination));
    
  • Event-Based Optimization: Listen for eloquent.saved or eloquent.updated events to optimize images tied to models:

    public function handle($model) {
        if ($model->image) {
            $optimizer = app(OptimizerChain::class);
            $optimizer->optimize($model->image_path);
        }
    }
    
  • Custom Optimizer Chains: Extend OptimizerChain to add pre/post-processing:

    use Spatie\ImageOptimizer\OptimizerChain;
    
    class CustomOptimizerChain extends OptimizerChain {
        protected function getDefaultOptimizers(): array {
            return array_merge(parent::getDefaultOptimizers(), ['custom-tool']);
        }
    }
    

    Bind it in AppServiceProvider:

    $this->app->bind(
        Spatie\ImageOptimizer\OptimizerChain::class,
        fn($app) => new CustomOptimizerChain()
    );
    

Gotchas and Tips

Pitfalls

  1. Missing Optimization Tools:

    • Symptom: NoOptimizerAvailableException or silent failures.
    • Fix: Install tools (e.g., sudo apt-get install jpegoptim pngquant) or configure allowed_optimizers in config/image-optimizer.php to skip checks.
    • Debug: Run php artisan image-optimizer:check to verify installed tools.
  2. File Permissions:

    • Symptom: Optimized files are created but not saved or corrupted.
    • Fix: Ensure the web server user (e.g., www-data) has write permissions to the target directory:
      chmod -R 775 storage/app/public
      chown -R www-data:www-data storage/app/public
      
  3. SVG/GIF Limitations:

    • Symptom: SVGs or GIFs aren’t optimized or throw errors.
    • Fix: Ensure svgo (for SVGs) or gifsicle (for GIFs) is installed. Configure allowed_optimizers to exclude unsupported formats if needed.
  4. Race Conditions in Async Jobs:

    • Symptom: Optimized files are overwritten or lost.
    • Fix: Use unique filenames or lock files during processing:
      if (!file_exists($lockFile = $filePath . '.lock')) {
          file_put_contents($lockFile, '');
          $optimizer->optimize($filePath);
          unlink($lockFile);
      }
      

Debugging

  • Log Optimization Steps: Enable debug mode in config/image-optimizer.php:

    'debug' => env('IMAGE_OPTIMIZER_DEBUG', false),
    

    Check logs for tool execution details.

  • Verify Output: Compare file sizes before/after optimization:

    $before = filesize($filePath);
    $optimizer->optimize($filePath);
    $after = filesize($filePath);
    logger()->info("Optimized {$filePath}: {$before} -> {$after} bytes");
    

Configuration Quirks

  1. optimize_on_demand:

    • Set to true in config/image-optimizer.php to optimize files only when accessed (requires middleware or caching layer).
  2. Custom Tool Paths:

    • Override tool paths in config:
      'tools' => [
          'jpegoptim' => '/custom/path/to/jpegoptim',
      ],
      
  3. Fallback Optimizers:

    • Define a fallback chain in getDefaultOptimizers() if primary tools fail:
      protected function getDefaultOptimizers(): array {
          return ['jpegoptim', 'pngquant', 'fallback-tool'];
      }
      

Extension Points

  1. Custom Optimizer Classes: Implement Spatie\ImageOptimizer\Optimizers\Optimizer to add new tools:

    class MyCustomOptimizer implements Optimizer {
        public function optimize(string $filePath): void {
            // Custom logic (e.g., call an API)
        }
        public function supports(string $filePath): bool {
            return pathinfo($filePath, PATHINFO_EXTENSION) === 'webp';
        }
    }
    

    Register it in OptimizerChain:

    protected function getDefaultOptimizers(): array {
        return ['jpegoptim', 'MyCustomOptimizer'];
    }
    
  2. Pre/Post-Processing Hooks: Extend OptimizerChain to add logic before/after optimization:

    class ExtendedOptimizerChain extends OptimizerChain {
        protected function beforeOptimize(string $filePath): void {
            // Example: Resize image before optimization
            $this->resize($filePath);
        }
        protected function afterOptimize(string $filePath): void {
            // Example: Update database record
            DB::table('images')->where('path', $filePath)->update(['optimized' => true]);
        }
    }
    
  3. Database Tracking: Use the optional optimized_images table to log optimization jobs:

    use Spatie\ImageOptimizer\Models\OptimizedImage;
    
    $optimized = OptimizedImage::create([
        'path' => $filePath,
        'original_size' => filesize($filePath),
    ]);
    $optimizer->optimize($filePath);
    $optimized->update(['optimized_size' => filesize($filePath)]);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport