laravel-images maintained by anikolab
anikolab/laravel-images
Responsive images for Laravel on plain GD: presets, master copies, AVIF / WebP / JPEG variants and one <x-picture> component — for static site photos and for photos uploaded in the admin panel via spatie/laravel-medialibrary.
- Presets — aspect ratio, fixed
srcsetwidths, JPEG fallback width, defaultsizes, optional separate mobile frame (<source media>). - Master copy — rotated by EXIF Orientation, longest side capped (3200 px by default), metadata stripped. PNG sources keep transparency: AVIF and WebP keep the alpha channel, the JPEG fallback is flattened onto a background colour.
- Variants — every width is resized once and saved in every format; images are never upscaled; file names contain the actual width and a hash of the master copy and all parameters, so variants can be cached as
immutable. - Missing photo — the component renders a grey placeholder with the preset proportions and logs a warning; the page never fails.
Requirements: PHP 8.3+, Laravel 13, ext-gd (with AVIF support for AVIF output) and ext-exif.
Installation
composer require anikolab/laravel-images
php artisan vendor:publish --tag=images-config
Fill config/images.php: presets for every place with a photo in your layout, the list of static photos (photos) and, if needed, admin collections (media).
Static photos
Sources stay out of git (images.sources_path). The flow:
php artisan images:master # sources from images.photos → master copies (images.masters_path)
php artisan images:build # master copies → variants + manifest.json (images.output_path)
images:build rebuilds only what changed and is safe to run on every deploy. Master copies are copied to the server (e.g. rsync); missing ones produce warnings, not errors.
<x-picture photo="hero" preset="hero" alt="…" priority />
<x-picture photo="about" preset="portrait" alt="…" sizes="50vw" class="about__photo" />
priority — first screen: loading="eager" and fetchpriority="high"; otherwise lazy + decoding="async". Extra attributes go to <img>.
Admin uploads (medialibrary)
// config/images.php
'media' => [
App\Models\Work::class => ['gallery' => ['card', 'lightbox']],
],
A new media item of a listed collection is processed in the queue (run a worker): the original is replaced with a master copy, variants are stored next to it in variants/ and listed in the media custom_properties. Deleting the media removes the variants. medialibrary conversions are not used — uploads get the same quality, crop and formats as static photos.
<x-picture :media="$work->getFirstMedia('gallery')" preset="card" alt="…" />
php artisan images:media # queue media without variants (run on deploy)
php artisan images:media --force # queue all, after changing presets or quality
Upload fields must use the same public disk as the collection.
Customising the markup
php artisan vendor:publish --tag=images-views
Testing
composer test
License
MIT
Кратко по-русски
Пакет обработки фото для сайтов Anikolab: пресеты, мастер-копии, варианты AVIF/WebP/JPEG на GD и один компонент <x-picture> для статичных фото и фото из админки (medialibrary). Статичные фото — images:master и images:build, фото из админки — очередь и images:media. Настройка — config/images.php.