Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти
Інше
Події Про нас

Обробка зображень

Вступ

Laravel надає плавний API для обробки зображень, який дозволяє змінювати розмір, обрізати, кодувати й зберігати зображення за тими самими виразними домовленостями, що діють в усьому фреймворку. Можливості роботи із зображеннями в Laravel побудовані на Intervention Image і підтримують PHP-розширення GD та Imagick.

API зображень стане в пригоді під час роботи із завантаженими файлами, файлами на дисках файлової системи Laravel, локальними файлами, віддаленими URL чи сирими байтами зображення:

use Illuminate\Support\Facades\Image;

$path = Image::fromStorage('avatars/photo.jpg', 'public')
    ->cover(400, 400)
    ->toWebp()
    ->quality(80)
    ->storePublicly('avatars', 'public');

Обробка зображень може бути вимогливою до процесора й пам'яті. Розгляньте можливість виконувати великі обсяги обробки зображень у завданні в черзі, а не під час HTTP-запиту, який приймає завантаження.

Встановлення

Перш ніж користуватися можливостями обробки зображень у Laravel, встановіть пакет Intervention Image через Composer:

composer require intervention/image:^4.0

Також переконайтеся, що у вашій інсталяції PHP встановлено розширення GD або Imagick - залежно від того, який драйвер використовуватиме ваш застосунок.

Конфігурація

Файл конфігурації зображень Laravel лежить у config/images.php. Якщо у вашому застосунку немає файлу конфігурації images, опублікуйте його командою Artisan config:publish:

php artisan config:publish images

Файл конфігурації зображень дозволяє вказати драйвер зображень за замовчуванням для вашого застосунку. Ви також можете вказати драйвер за замовчуванням через змінну середовища IMAGE_DRIVER. Підтримувані драйвери - gd та imagick:

IMAGE_DRIVER=imagick

Читання зображень

Фасад Image надає кілька методів для читання зображень із поширених джерел. Вміст зображень завантажується ліниво, тож джерело зазвичай не читається, доки зображення не оброблено або доки не запитано його байти.

Завантажені файли

Ви можете дістати завантажене зображення з вхідного запиту методом image. Цей метод повертає екземпляр Illuminate\Image\Image для завантаженого файлу або null, якщо файлу немає:

use Illuminate\Http\Request;

Route::post('/avatar', function (Request $request) {
    $request->validate(['avatar' => ['required', 'image']]);

    $path = $request->image('avatar')
        ->cover(400, 400)
        ->toWebp()
        ->storePublicly('avatars', 'public');

    // ...
});

Як варіант, ви можете створити екземпляр зображення з екземпляра Illuminate\Http\UploadedFile методом fromUpload:

use Illuminate\Support\Facades\Image;

$image = Image::fromUpload($request->file('avatar'));

Коли зображення створено із завантаженого файлу, ви можете дістати цей файл методом file:

$file = $image->file();

Файли у сховищі

Ви можете створити екземпляр зображення з файлу, що зберігається на одному з дисків файлової системи вашого застосунку, методом fromStorage. Перший аргумент - шлях до файлу, другий - назва диска:

use Illuminate\Support\Facades\Image;

$image = Image::fromStorage('avatars/photo.jpg', disk: 'public');

Ви також можете створювати екземпляри зображень безпосередньо з екземпляра диска методом image:

use Illuminate\Support\Facades\Storage;

$image = Storage::disk('public')->image('avatars/photo.jpg');

Інші джерела

Фасад Image також містить методи для створення екземплярів зображень із сирих байтів, локальних шляхів, віддалених URL і рядків у Base64:

use Illuminate\Support\Facades\Image;

$image = Image::fromBytes($contents);
$image = Image::fromBase64($base64);
$image = Image::fromPath(storage_path('app/avatars/photo.jpg'));
$image = Image::fromUrl('https://example.com/photo.jpg');

Обробка зображень

Екземпляри зображень незмінні. Кожен метод обробки повертає новий екземпляр зображення з доданим до його конвеєра перетворенням, тож методи можна плавно поєднувати ланцюжком:

$image = $request->image('avatar')
    ->orient()
    ->cover(400, 400)
    ->sharpen(10);

Перетворення обробляються в порядку, у якому їх додано до конвеєра зображення, а саме зображення кодується лише один раз, у кінці.

Зміна розміру зображень

Метод resize змінює розмір зображення до заданих величин. Ви можете передати і ширину, і висоту або лише одну величину через іменовані аргументи:

$image = $image->resize(800, 600);
$image = $image->resize(width: 800);
$image = $image->resize(height: 600);

Метод scale пропорційно зменшує зображення так, щоб воно вмістилося в задані величини. Цей метод ніколи не збільшує зображення:

$image = $image->scale(800, 600);
$image = $image->scale(width: 800);
$image = $image->scale(height: 600);

Метод cover змінює розмір і обрізає зображення так, щоб воно повністю вкривало задані величини:

$image = $image->cover(400, 400);

Метод contain змінює розмір зображення так, щоб воно вмістилося в задані величини, зберігши все зображення. За потреби порожній простір буде заповнено необов'язковим кольором тла:

$image = $image->contain(400, 400);
$image = $image->contain(400, 400, '#ffffff');

Обрізати зображення можна методом crop. Перші два аргументи - потрібні ширина й висота, а необов'язкові третій і четвертий задають координати x та y обрізання:

$image = $image->crop(300, 200);
$image = $image->crop(300, 200, x: 50, y: 25);

Інші перетворення

Laravel також надає низку додаткових методів перетворення зображень:

$image = $image->orient();
$image = $image->rotate(90);
$image = $image->rotate(90, '#ffffff');
$image = $image->blur(5);
$image = $image->grayscale();
$image = $image->sharpen(10);
$image = $image->flipVertically();
$image = $image->flipHorizontally();

Метод orient повертає зображення відповідно до даних орієнтації EXIF. Метод rotate повертає зображення за годинниковою стрілкою на заданий кут і приймає необов'язковий колір тла. Методи blur і sharpen приймають значення від 0 до 100.

Умовні перетворення

Екземпляри зображень підтримують трейт Conditionable Laravel, тож ви можете застосовувати перетворення умовно, методами when та unless:

$image = $request->image('avatar')
    ->when($request->boolean('crop'), fn ($image) => $image->cover(400, 400))
    ->unless($request->boolean('preserve_format'), fn ($image) => $image->toWebp());

Кодування зображень

За замовчуванням оброблені зображення кодуються у своєму оригінальному форматі. Проте ви можете конвертувати зображення в інший підтримуваний формат перед отриманням чи збереженням:

$image = $image->toWebp();
$image = $image->toJpg();
$image = $image->toJpeg();
$image = $image->toPng();
$image = $image->toGif();
$image = $image->toAvif();
$image = $image->toBmp();

Метод quality дозволяє задати якість на виході. Якість буде обмежено діапазоном від 1 до 100:

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

Метод optimize - зручне скорочення для конвертації зображення в заданий формат із заданням якості. За замовчуванням зображення оптимізуються як WebP з якістю 70:

$image = $image->optimize();

$image = $image->optimize(format: 'jpg', quality: 85);

Ви можете отримати вміст обробленого зображення як рядок байтів, рядок у Base64 чи data URI:

$bytes = $image->toBytes();
$base64 = $image->toBase64();
$dataUri = $image->toDataUri();

Екземпляр зображення можна також привести до рядка, щоб отримати його оброблені байти:

$bytes = (string) $image;

Збереження зображень

Метод store зберігає оброблене зображення на одному з дисків файлової системи вашого застосунку. Як і для завантажених файлів, Laravel згенерує унікальне ім'я файлу й поверне шлях збереження. Другим аргументом можна вказати диск:

$path = $request->image('avatar')
    ->cover(400, 400)
    ->store(path: 'avatars');

$path = $request->image('avatar')
    ->cover(400, 400)
    ->store(path: 'avatars', disk: 's3');

Метод storeAs дозволяє вказати ім'я збереженого файлу:

$path = $request->image('avatar')
    ->cover(400, 400)
    ->storeAs(path: 'avatars', name: 'avatar.jpg', disk: 'public');

Методи storePublicly та storePubliclyAs зберігають зображення з видимістю public:

$path = $request->image('avatar')
    ->cover(400, 400)
    ->storePublicly(path: 'avatars', disk: 'public');

$path = $request->image('avatar')
    ->cover(400, 400)
    ->storePubliclyAs(path: 'avatars', name: 'avatar.webp', disk: 'public');

Якщо зображення не вдалося зберегти, методи збереження повертають false.

Огляд зображень

Отримати MIME-тип, розширення, розміри, ширину й висоту зображення можна такими методами:

$mimeType = $image->mimeType();
$extension = $image->extension();

[$width, $height] = $image->dimensions();
$width = $image->width();
$height = $image->height();

Ці методи працюють з обробленим зображенням. Наприклад, виклик width після cover(400, 400) поверне 400.

Драйвери зображень

Власні драйвери зображень

Менеджер зображень Laravel розширює базовий клас Illuminate\Support\Manager. Це означає, що ви можете реєструвати власні драйвери зображень методом extend, доступним у менеджері зображень і фасаді Image.

Власні драйвери зображень мають реалізовувати інтерфейс Illuminate\Contracts\Image\Driver. Метод process отримує оригінальний вміст зображення та впорядкований Illuminate\Image\ImagePipeline, який слід застосувати до зображення, і має повернути оброблені байти:

<?php

namespace App\Images;

use Illuminate\Contracts\Image\Driver;
use Illuminate\Image\ImagePipeline;

class VipsDriver implements Driver
{
    /**
     * Process the given image contents with the specified pipeline.
     */
    public function process(string $contents, ImagePipeline $pipeline): string
    {
        // Apply the pipeline's transformations and output options...

        return $contents;
    }

    /**
     * Register a transformation handler.
     */
    public function transformUsing(string $transformation, callable $callback): static
    {
        // Store the handler so it may be applied while processing the pipeline...

        return $this;
    }
}

Щоб краще зрозуміти, як реалізувати власний драйвер зображень, перегляньте вбудований клас фреймворку Illuminate\Image\Drivers\InterventionDriver.

Щойно ви реалізували власний драйвер, зареєструйте його методом extend фасаду Image. Зазвичай це роблять у методі boot сервіс-провайдера:

use App\Images\VipsDriver;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Image;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Image::extend('vips', function (Application $app) {
        return new VipsDriver;
    });
}

Зареєструвавши драйвер, ви можете скористатися ним для конкретного зображення методом using:

$image = $request->image('avatar')
    ->using('vips')
    ->cover(400, 400);

Ви також можете зробити власний драйвер драйвером зображень за замовчуванням для вашого застосунку через опцію default у файлі config/images.php або змінну середовища IMAGE_DRIVER:

IMAGE_DRIVER=vips

Власні перетворення

Застосунки й пакети можуть описувати власні перетворення, створивши клас, який реалізує контракт Illuminate\Contracts\Image\Transformation. Далі власні перетворення можна додавати до конвеєра зображення методом transform:

<?php

namespace App\Images\Transformations;

use Illuminate\Contracts\Image\Transformation;

class Pixelate implements Transformation
{
    public function __construct(
        public readonly int $size,
    ) {
        //
    }
}

Далі зареєструйте обробник для перетворення й драйвера методом transformUsing фасаду Image. Зазвичай це роблять у методі boot сервіс-провайдера:

use App\Images\Transformations\Pixelate;
use Illuminate\Support\Facades\Image;
use Intervention\Image\Interfaces\ImageInterface;

Image::transformUsing('gd', Pixelate::class, function (ImageInterface $image, Pixelate $transformation) {
    return $image->pixelate($transformation->size);
});

Щойно обробник перетворення зареєстровано, ви можете застосувати перетворення до зображення:

use App\Images\Transformations\Pixelate;

$image = $request->image('avatar')
    ->transform(new Pixelate(12))
    ->store('avatars');