Implementing Laravel Intervention Image — resize & store multiple sizes

Blog Image

Modern websites need multiple image sizes for performance and responsiveness: small thumbnails for listings, medium images for article pages, and large versions for lightboxes. Manually resizing images is repetitive and error-prone. Intervention Image lets you programmatically read, resize, crop and save images in a few lines of code.

Quick links

 

Installation (fast)

  1. Install the package with Composer:

composer require intervention/image

  1. Make sure you have a PHP imaging driver installed — GD or Imagick. Example for Ubuntu + PHP 8.1 (adjust for your PHP version):

sudo apt-get install php8.1-gd   

  1. If you serve files from storage/app/public, ensure the storage symlink exists:

php artisan storage:link

The problem we solve (concise)

Problem: users upload a single original image, but the site needs several pre-sized versions (e.g. 240x240, 800x600) for different UI components. Creating and naming those variants consistently, storing them, and keeping metadata in your DB is tedious and often done incorrectly.

Solution: on upload, store the original file, create resized versions using Intervention, save those files to your storage disk, and record the original file's metadata in the database.

Example: step‑by‑step controller flow

Below is a practical example that:

  • validates and stores the original image,

  • creates resized versions from an ImageSizes enum,

  • saves those resized files to storage/app/public/... in a predictable naming pattern.

Notes:

  • Replace Media and ImageSizes with your actual model/enum.

  • This uses the public storage disk. Adjust if you use S3 or another disk.

  use Intervention\Image\ImageManager; use Illuminate\Support\Str; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Auth; use App\Models\Media; use App\Enums\ImageSizes; // example enum returning sizes like ['240x240','800x600'] use Illuminate\Http\Request;   public function upload(Request $request) { // 1. validate $request-validate([ 'file' = 'required|file|image|max:5120' // 5MB max (adjust as needed) ]);   // 2. basic file details $file = $request-file('file'); $originalName = $file-getClientOriginalName(); $extension = $file-getClientOriginalExtension(); $fileSizeKb = round($file-getSize() / 1024, 2); $mime = $file-getMimeType();   // 3. store original (public disk) $folder = 'uploads/images'; $path = $file-store($folder, 'public'); // e.g. uploads/images/abc123.jpg   // 4. persist metadata (example) $media = Media::create([ 'name' = $originalName, 'url' = $path, 'type' = $mime, 'extension' = $extension, 'size' = $fileSizeKb, 'user_id' = Auth::id(), ]);   // 5. if it's an image, create resized variants if (Str::startsWith($media-type, 'image')) { // Use GD driver or Imagick depending on your server $manager = new ImageManager(['driver' = 'gd']);   // make() from the uploaded file path to preserve EXIF orientation $image = $manager-make($file-getRealPath())-orientate();   foreach (ImageSizes::map() as $size) { [$width, $height] = explode('x', $size);   $resized = $image-resize((int)$width, (int)$height, function ($constraint) { $constraint-aspectRatio(); // keep aspect ratio $constraint-upsize(); // prevent upscaling });   $filenameWithoutExt = pathinfo($media-name, PATHINFO_FILENAME); $newFilename = "{$filenameWithoutExt}-{$size}.{$extension}"; // e.g. image-240x240.jpg $folderPath = dirname($media-url); // keep same folder as original   // ensure the directory exists on the public disk Storage::disk('public')-makeDirectory($folderPath);   // save encoded image bytes to the public disk Storage::disk('public')-put("{$folderPath}/{$newFilename}", (string) $resized-encode()); } }   return response()-json(['media' = $media], 201); }    

Example ImageSizes enum (PHP 8.1+)

Here's a tiny enum helper you can use. Replace the cases with whatever sizes you need.

  ?php   enum ImageSizes: string {      case THUMB = '240x240';      case MEDIUM = '800x600';      case LARGE = '1200x900';        public static function map(): array     {         return array_map(fn($c) = $c-value, self::cases());     } }    

Tips & best practices

  • Use orientate() to fix rotation from mobile photos (EXIF data).

  • Decide on resize() vs fit(): resize() keeps aspect ratio and fits within the box; fit() crops to the exact dimensions.

  • Prevent upscaling with $constraint-upsize() so small originals don't get blown up.

  • Offload heavy processing to a queued job if uploads are large or you expect high volume.

  • Use the right storage disk: use Storage::disk('s3') if you want variants uploaded directly to S3.

  • Generate srcset on the frontend so browsers choose the best size for each device.

  • Validate input strictly (MIME type, max size) to avoid malicious uploads.

  • Keep filenames predictable (e.g. name-240x240.jpg) so you can programmatically reference variants.

 

Final notes

This approach gives you a simple, deterministic way to keep originals and multiple resized variants for responsive design and performance. If you want, I can:

  • convert this example into a queued Laravel Job,

  • show a Blade helper that prints srcset attributes, or

  • write a short post about using Intervention with S3.

Previous Post Next Post

Comments:

Leave a comments: