Практичний посібник із Laravel First-Party Image Processing

Перекладено ШІ 0 Laravel News 24 липня, 2026

Laravel 13.20 отримав вбудований компонент Illuminate\Image, що дозволяє обробляти зображення без встановлення додаткових бібліотек. Дізнайтеся, як за допомогою нативного API легко виконувати ресайз, кропінг та оптимізацію медіафайлів.

У Laravel 13.20 з’явився вбудований інструмент для обробки зображень — новий компонент Illuminate\Image, представлений у Pull Request #59276. Раніше для зміни розміру аватара чи конвертації файлів у WebP доводилося встановлювати сторонні пакети.

Тепер фреймворк пропонує зручний (fluent) та незмінний (immutable) API, який охоплює базові потреби: зміну розміру, обрізку, конвертацію форматів, контроль якості, ефекти та збереження результату на будь-який диск файлової системи.

У цьому туторіалі ми розберемо можливості API на практиці: обробимо аватар, згенеруємо адаптивні варіанти зображень та застосуємо трансформації за певних умов.

# Налаштування

Драйвери GD та Imagick працюють на базі Intervention Image v4. Це рекомендована, але не обов'язкова залежність, тому її потрібно встановити вручну:

composer require intervention/image:^4.0

За замовчуванням Laravel використовує драйвер GD. Якщо на вашому сервері встановлено розширення Imagick, ви можете зробити його основним у конфігурації images.default або змінювати драйвер безпосередньо під час виклику:

$image->usingImagick()->toBytes();
 
// Або за назвою:
$image->using('imagick')->toBytes();

Якщо викликати драйвер без встановленого Intervention Image, Laravel видасть ImageException з чіткою інструкцією, що саме потрібно доставити.

# Створення екземпляра Image

Зображення можна отримати з будь-якого джерела: завантаження, диск, локальний шлях, URL або сирі байти. Новий метод Request::image() — найзручніший спосіб для роботи з аплоадами:

$image = $request->image('avatar'); // ?Illuminate\Image\Image

Метод повертає null, якщо поле відсутнє або не є файлом, тому спочатку валідуйте вхідні дані як зазвичай.

Фасад Image та сервіс Storage дозволяють працювати з іншими джерелами:

use Illuminate\Support\Facades\Image;
use Illuminate\Support\Facades\Storage;
 
$image = Image::fromPath('/path/to/photo.jpg');
$image = Image::fromUrl('https://example.com/photo.jpg');
$image = Image::fromStorage('uploads/photo.jpg', 's3');
$image = Image::fromBytes($contents);
$image = Image::fromBase64($encoded);
 
// Еквівалент fromStorage():
$image = Storage::disk('s3')->image('uploads/photo.jpg');

# Як працює ланцюжок викликів

Кожна трансформація повертає новий екземпляр Image. Обробка не розпочнеться, доки ви не запитаєте фінальний результат (через store(), toBytes(), width() тощо). Це дозволяє створювати кілька варіантів зображення на основі одного базового об'єкта, не боячись, що зміни одного варіанту вплинуть на інший:

$photo = Image::fromStorage('uploads/photo.jpg')->orient();
 
$thumbnail = $photo->cover(300, 300)->quality(60)->toWebp();
$display = $photo->scale(width: 1600)->quality(80)->toWebp();
 
$thumbnail->storeAs('photos', 'photo-thumb.webp', disk: 's3');
$display->storeAs('photos', 'photo-display.webp', disk: 's3');

Виклик orient() автоматично повертає зображення згідно з даними EXIF — це корисно для фотографій, зроблених на смартфони.

# Зміна розміру: cover, contain, scale, resize та crop

API пропонує п'ять методів для зміни габаритів:

  • cover($width, $height): масштабує та обрізає зображення, щоб воно повністю заповнило вказані розміри. Ідеально для аватарів та прев’ю.
  • contain($width, $height, $background): вписує зображення в межі, додаючи тло (за потреби) для збереження пропорцій.
  • scale($width, $height): пропорційно змінює розмір, але ніколи не збільшує оригінал (upscale). Можна вказати лише одну сторону.
  • resize($width, $height): примусово встановлює розміри, що може призвести до спотворення пропорцій.
  • crop($width, $height, $x, $y): вирізає фрагмент зображення за заданими координатами.
$image->cover(512, 512);          // Квадрат, обрізаний під розмір
$image->contain(800, 600, '#fff'); // Вписано у рамку на білому тлі
$image->scale(width: 1200);        // Пропорційно, тільки зменшення
$image->crop(400, 300, x: 100, y: 50);

# Ефекти та коригування

Для базової корекції доступні такі методи:

$image
    ->rotate(90)          // Поворот за годинниковою стрілкою
    ->blur(10)            // Розмиття (0–100)
    ->sharpen(15)         // Різкість (0–100)
    ->grayscale()         // Чорно-білий фільтр
    ->flip()              // Вертикальне відображення
    ->flop();             // Горизонтальне відображення

# Формати, якість та optimize()

Конвертація виконується методами toWebp(), toJpg(), toPng(), toGif(), toAvif() та toBmp(). Параметр quality (1–100) працює для WebP, JPEG та AVIF:

$image->toWebp()->quality(80);

Метод optimize() — це швидкий спосіб конвертувати зображення у WebP з якістю 70 за замовчуванням:

$image->optimize();             // WebP, якість 70
$image->optimize('avif', 60);   // AVIF, якість 60

Драйвери підтримують JPEG, PNG, GIF, BMP та WebP на вході.

# Збереження та отримання результату

Методи збереження ідентичні до UploadedFile у Laravel:

$path = $image->store('avatars');                       // Випадкове ім'я (хеш)
$path = $image->storeAs('avatars', 'user-1.webp');      // Чітка назва
$path = $image->storePublicly('avatars', disk: 's3');   // Публічний доступ

При використанні випадкового імені розширення автоматично зміниться на відповідне формату (наприклад, .webp після виклику toWebp()).

Також можна отримати дані безпосередньо через toBytes(), toBase64() або toDataUri().

Методи інспекції повертають дані вже обробленого зображення:

$image->width();       // Ширина
$image->height();      // Висота
$image->dimensions();  // [ширина, висота]
$image->mimeType();    // Наприклад, "image/webp"
$image->extension();   // Наприклад, "webp"

Data URI зручно використовувати для вбудовування маленьких прев’ю прямо в HTML або email:

$avatar = Storage::image("avatars/{$user->avatar}")
    ->cover(64, 64)
    ->toDataUri();

# Приклад: завантаження аватара

Ось повний цикл обробки в контролері: вирівнювання за EXIF, обрізка до 512x512, оптимізація та збереження на S3 з публічним доступом:

public function update(Request $request)
{
    $request->validate([
        'avatar' => ['required', 'image', 'max:5120'],
    ]);
 
    $path = $request->image('avatar')
        ->orient()
        ->cover(512, 512)
        ->optimize()
        ->storePublicly('avatars', disk: 's3');
 
    $request->user()->update(['avatar_path' => $path]);
 
    return back();
}

Генерація адаптивних варіантів у циклі:

foreach ([480, 960, 1440] as $width) {
    Image::fromStorage($path, 's3')
        ->scale(width: $width)
        ->toWebp()
        ->storeAs('photos/variants', "{$name}-{$width}w.webp", disk: 's3');
}

Оскільки scale() не збільшує зображення, оригінал шириною 900 пікселів не буде розтягнутий до 1440.

# Умовні трансформації

Клас Image використовує трейт Conditionable, тому методи when() та unless() працюють як і в інших частинах Laravel:

$image = $request->image('photo')
    ->when($request->boolean('grayscale'), fn ($image) => $image->grayscale())
    ->scale(width: 1200)
    ->optimize();

# Розширення та кастомізація

Laravel дозволяє реєструвати власні драйвери через Image::extend(). Крім того, за допомогою Image::transformUsing() можна перевизначити логіку конкретної трансформації для певного драйвера:

use Illuminate\Image\Transformations\Blur;
use Illuminate\Support\Facades\Image;
 
Image::transformUsing('gd', Blur::class, function ($image, Blur $blur) {
    return $image->blur(min(100, $blur->amount * 2));
});

Ви також можете створити власну трансформацію, реалізувавши контракт Illuminate\Contracts\Image\Transformation, і передати її в метод $image->transform().

# Важливі нюанси

  • Зображення не можна серіалізувати. Ви не можете передати екземпляр Image безпосередньо в чергу (Queue) — це викличе помилку. Спочатку збережіть файл, а в джобу передавайте лише шлях.
  • Лінива обробка та кешування. Трансформації виконуються один раз при першому виклику виводу. Наступні виклики width() чи toBytes() використовують уже готовий результат.
  • Обробка помилок. При роботі з непідтримуваними форматами або пошкодженими файлами Laravel викидає ImageException, що дозволяє зручно обробляти винятки в одному блоці try/catch.

Функціонал доступний у Laravel 13.20, а деталі реалізації можна переглянути в Pull Request #59276.

Популярні

Інше, що варто прочитати

20 Оновлено 26 червня, 2026

Перетворення даних у типобезпечні DTO за допомогою пакету Data Model

Досліджуйте новий пакет Data Model для PHP, який спрощує процес гідратації об'єктів без зайвих складнощів! Дізнайтеся, як впровадження типобезпечних об'єктів може революціонізувати ваш підхід до розробки, читаючи нашу статтю

41 Оновлено 26 червня, 2026

Що нового в PHP 8.5

PHP 8.5 обіцяє безліч нових можливостей, таких як оператор Pipe, функції `array_first()` та `array_last()`, а також нове розширення URI. Чи готові ви дізнатися, як ці функції можуть спростити вашу розробку? Читайте далі, щоб дізнатися більше про ці захоплюючі нововведення

19 Оновлено 26 червня, 2026

Використання штучного інтелекту для управління перекладами в Laravel

Досліджуйте нові можливості локалізації вашого Laravel-додатку з пакунками, які використовують штучний інтелект, такими як ChatGPT та Claude. Які рішення можуть спростити ваш процес перекладу та зробити його більш точним? Читайте далі, щоб дізнатися більше!