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

Отримання домінантного кольору зображення в Laravel

Зображення, що ще не завантажилося, залишає дірку на сторінці. Звичайні рішення - сірий блок, розмитий thumbnail у HTML або взагалі нічого. Дешевша альтернатива, що покриває більшість потреб - заповнити простір середнім кольором фото. Так макет виглядає навмисним ще до того, як завантажиться перший піксель справжнього зображення.

Laravel 13.24 додав метод dominantColor() до вбудованого API для роботи із зображеннями, який повертає цей колір без окремого пакунка. У цій статті розглянемо, як отримати колір, де його зберігати та як ним користуватися.

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

Drайвери GD та Imagick компонента для роботі із зображеннями базуються на Intervention Image - це рекомендована, а не обов'язкова залежність:

composer require intervention/image:^4.0

Більше нічого не потрібно. Визначення домінантного кольору працює на обох драйверах.

Отримання домінантного кольору

Викличте dominantColor() на будь-якому екземплярі зображення - отримаєте hex-рядок:

use Illuminate\Support\Facades\Image;
$color = Image::fromPath(storage_path('app/photo.jpg'))->dominantColor();
// "#8a6f4c"

Реалізація зменшує копію зображення до одного пікселя та зчитує його значення. Це саме середнє значення, а не найчастіший колір - тому фото червоного амбара в зеленому полі дасть каламутний оливковий, а не червоний. Для плейсхолдера це саме те, що потрібно: колір має лежати за всім зображенням, а не представляти його об'єкт.

Префікс # завжди включений. Зображення з альфа-каналом повертають восьмизначну форму (#rrggbbaa), тому враховуйте це при визначенні розміру колонки.

Перетворення застосовуються перед вибіркою кольору - ви отримуєте колір зображення, яке збираєтесь зберегти, а не оригіналу:

$color = Image::fromStorage('uploads/photo.jpg')
 ->crop(800, 600, x: 200, y: 0)
 ->dominantColor();

Обріжте небо - і колір зміниться.

Збереження домінантного кольору при завантаженні

Колір корисний лише тоді, коли він доступний при рендерингу сторінки. Тому обчисліть його один раз при завантаженні та зберігайте в моделі. Почніть із колонки:

Schema::create('photos', function (Blueprint $table) {
 $table->id();
 $table->string('path');
 $table->string('dominant_color', 9)->nullable();
 $table->timestamps();
});

Потім у контролері створіть зображення один раз і використовуйте екземпляр повторно:

use App\Models\Photo;

public function store(Request $request)
{
 $request->validate([
 'photo' => ['required', 'image', 'max:12288'],
 ]);

 $photo = $request->image('photo')
 ->orient()
 ->scale(width: 1600)
 ->optimize();

 return Photo::create([
 'path' => $photo->store('photos'),
 'dominant_color' => $photo->dominantColor(),
 ]);
}

Порядок тут важливий: store() виконує pipeline, кешує оброблені байти в екземплярі та очищає pipeline. Наступний виклик dominantColor() на тому ж екземплярі бере ці закешовані байти без додаткової роботи. Поміняйте рядки місцями - і колір обчислюватиметься для одноразового клону pipeline, а store() обробить зображення вдруге. Той самий результат, вдвічі більше роботи.

Значення також мемоізується для кожного екземпляра - повторний виклик dominantColor() нічого не коштує. Оскільки кожне перетворення повертає новий екземпляр, thumbnail, відгалужений від того самого джерела, обчислює власний колір замість успадкування:

$source = Image::fromStorage('uploads/photo.jpg')->orient();
$thumbnail = $source->cover(300, 300);
$display = $source->scale(width: 1600);

$thumbnail->dominantColor(); // вибірка з обрізаного квадрата
$display->dominantColor(); // вибірка з повного кадру

Використання домінантного кольору як плейсхолдера

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

<div class="aspect-[3/2] overflow-hidden rounded-lg"
 style="background-color: {{ $photo->dominant_color }}">
 <img src="{{ Storage::url($photo->path) }}"
 alt="{{ $photo->caption }}"
 loading="lazy"
 class="h-full w-full object-cover">
</div>

Кольоровий блок малюється з першим кадром, зображення з'являється поверх нього, коли завантажиться, і сторінка ніколи не перебудовується. Це добре поєднується з loading="lazy" у довгій галереї, де більшість зображень не завантажується, поки читач не прокрутить.

Читабельний текст поверх кольору

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

namespace App\Support;

class Color
{
 public static function isLight(string $hex): bool
 {
 [$r, $g, $b] = sscanf(substr($hex, 0, 7), '#%02x%02x%02x');
 // Rec. 709 luma, 0-255.
 return (0.2126 * $r + 0.7152 * $g + 0.0722 * $b) > 140;
 }
}
<figcaption class="{{ Color::isLight($photo->dominant_color) ? 'text-gray-900' : 'text-white' }}">
 {{ $photo->caption }}
</figcaption>

Заповнення letterbox та обертання

Та сама вибірка доступна як фонове значення всередині перетворення. Передача dominant у contain() заповнює letterbox-смуги власним кольором зображення замість фіксованого, який ви вибрали заздалегідь:

Image::fromUpload($request->file('photo'))
 ->contain(1200, 800, background: 'dominant')
 ->store('photos');

Портретне фото, доповнене до альбомного формату, отримує смуги, що належать фото - це виглядає набагато краще в сітці, ніж білі чи чорні смуги на кожній третій плитці. rotate() приймає те саме значення для кутів, що відкриваються:

$image->rotate(8, background: 'dominant');

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

Що це не є

dominantColor() повертає один усереднений колір. Це не екстрактор палітри, і він не знайде акцентний колір, який вибрав би дизайнер. Якщо вам потрібен набір репрезентативних зразків або перцептивна кластеризація, що ігнорує великий плоский фон - це не та функція, і спеціалізована бібліотека залишається правильним вибором.

Для плейсхолдерів, letterbox-заповнення та тонування картки за її власним зображенням один усереднений колір - це вся робота, і тепер він постачається з фреймворком.

Додаткове читання

  • Практичний посібник з вбудованої обробки зображень Laravel охоплює решту API: зміна розміру, обрізка, конвертація форматів та зберігання
  • Image Dominant Color та підтримка HEIC у Laravel 13.24 містить повні примітки до релізу
  • Функцію додав @dr-codswallop у #60932
3

Читати в документації

Коментарі

Увійдіть, щоб залишити коментар

Будьте першим, хто залишить коментар!

Читайте також

Fresh Package
Новини 19 вересня 2026

Fresh Package: новий скелет для розробки Laravel-пакетів з Testbench, CI та інтеграцією Boost

Fresh Package від Mazen Touati - це сучасний скелет для створення Laravel-пакетів, який включає тестове середовище, статичний аналіз, CI/CD, workbench-додаток та шаблони навичок для AI-агентів. Підтримує як backend-only, так і full-stack пакети.

6
Jev: модель, яка повертає рішення замість тексту - і вже є в Laravel AI SDK Рекомендовано
Новини 18 вересня 2026

Jev: модель, яка повертає рішення замість тексту - і вже є в Laravel AI SDK

TypeSafe AI випустила Jev - модель, яка не генерує текст, а повертає типізовані рішення з каліброваними ймовірностями за 70-500 мс. Через два дні підтримка приїхала в гілку 1.x пакета laravel/ai у вигляді API Classification з питаннями Boolean, Choice і Score.

Вакансії за темою

Wayforpay
4 дні тому

PHP Full-Stack Developer

Full-Stack розробник на PHP з досвідом від 4 років. Розробка та оптимізація веб-продуктів (front-end та back-end), інтеграція платіжних систем, поліпшення UX/UI інтерфейсів. Основний стек: PHP, Yii/Yii2, HTML, CSS, JavaScript. Вимоги: досвід з платіжними платформами буде перевагою, увага до деталей, здатність працювати в команді.

Plumrocket Inc
4 дні тому

Middle Magento Back-End Developer

Middle Magento Back-End розробник займатиметься розробкою та підтримкою веб-магазинів на платформі Magento 2, їх оптимізацією. Вимагається практичний досвід з Magento 2 не менше 2 років, знання PHP (OOP), MySQL, Javascript, GIT. Бажані: розробка Magento Extensions, KnockoutJS, RequireJS, досвід з MVC-фреймворками та Docker.

Поліщук Я. В., ФОП
10 днів тому

Програміст PHP (інтерн)

Вакансія на посаду інтерна PHP розробника для початківців з теоретичною базою ООП та базовими знаннями PHP. Потрібні навички Git/GitHub, власні проєкти. Стажування в офісі під керівництвом менторів з перспективою переходу на посаду Junior разробника.