Extract an Image's Dominant Color in Laravel 13.24
Laravel Tips & Tricks #Laravel #Image Processing #PHP #Laravel 13 #Intervention Image

Extract an Image's Dominant Color in Laravel 13.24

3 min read Mohamed Said Mohamed Said

Extract an Image's Dominant Color in Laravel 13.24

Laravel 13.24 shipped dominantColor() as part of the first-party image API, giving you an averaged hex color from any image without reaching for a third-party package. The most practical use case is filling the space a lazy-loaded image will eventually occupy, so the layout looks intentional before a single pixel of the real photo arrives.

Setup

The image API is backed by Intervention Image, which is a suggested dependency. Install it first:

composer require intervention/image:^4.0

Both the GD and Imagick drivers support dominant color detection.

Getting the Dominant Color

Call dominantColor() on any image instance to receive a hex string:

use Illuminate\Support\Facades\Image;

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

Internally, the image is resized to a single pixel and that pixel's value is read. This produces an average rather than the most-frequent color, which is exactly what you want for a full-image placeholder. Images with an alpha channel return an eight-digit hex (#rrggbbaa), so size your database column to 9 characters.

Transformations applied before dominantColor() affect the sampled result:

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

Storing the Color at Upload Time

Compute the color once during upload and persist it on the model. Add a nullable column:

$table->string('dominant_color', 9)->nullable();

In the controller, call store() before dominantColor(). store() caches the processed bytes on the instance, so the subsequent color call samples those bytes at no extra cost:

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

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

Reversing those two lines forces the pipeline to run twice — same result, double the work.

Using the Color as a Placeholder

With the color stored on the model, render a colored box that holds the correct aspect ratio while the image loads:

<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>

This pairs well with loading="lazy" in long galleries: the colored box is painted immediately, the image fades in over it, and the page never reflows.

Readable Text Over the Placeholder

A small helper using Rec. 709 relative luminance picks the right text color automatically:

class Color
{
    public static function isLight(string $hex): bool
    {
        [$r, $g, $b] = sscanf(substr($hex, 0, 7), '#%02x%02x%02x');
        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 and Rotation Fills

Pass 'dominant' to contain() or rotate() to fill exposed areas with the image's own color:

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

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

Sampling happens at that point in the pipeline, so an earlier crop changes the fill color.

What It Is Not

dominantColor() returns one averaged color. It is not a palette extractor and will not identify the accent color a designer would choose. For perceptual clustering or multi-swatch extraction, a dedicated library is still the right tool.

Key Takeaways

  • dominantColor() ships with Laravel 13.24 — no extra package beyond Intervention Image.
  • The method averages the image down to one pixel; it is ideal for placeholders, not palette work.
  • Call store() before dominantColor() on the same instance to avoid processing the image twice.
  • Alpha-channel images return an 8-digit hex; store the column as varchar(9).
  • Pass background: 'dominant' to contain() or rotate() for seamless letterbox fills.

Source: Extract an Image's Dominant Color in Laravel — Laravel News

Found this useful?

Frequently Asked Questions

3 questions
Q01 What does Laravel's dominantColor() method actually return?
It returns a hex color string (e.g., `#8a6f4c`) representing the average color of the image. For images with an alpha channel it returns an 8-digit hex (`#rrggbbaa`). The value is computed by resizing the image to a single pixel and reading that pixel's color.
Q02 Why should I call store() before dominantColor() on the same image instance?
Calling `store()` first runs the transformation pipeline and caches the processed bytes on the instance. A subsequent `dominantColor()` call samples those cached bytes at no extra cost. Reversing the order causes the pipeline to run twice — once for the color sample and once for the actual save.
Q03 Can dominantColor() be used to extract a full color palette?
No. `dominantColor()` returns a single averaged color. It is not a palette extractor and will not identify multiple representative swatches or accent colors. For multi-color extraction or perceptual clustering, a dedicated library is required.

Continue reading

More Articles

View all