How to Get Dominant Colours of an Image in PHP

on in Blog
Last modified on

Dominant Color

This feature has been requested by some of my ImagePress customers. It is also being used on my PropertyPin website. Basically, whenever a new image is uploaded, an array of 8 primary colours is extracted and a dominant colour is set.

The 8 primary colours are rounded up, so, for example, a bunch of red shades will be slightly adjusted to have the exact hex code.

Let’s see how I did it, using PHP. Note that, in the code below, I kept both rounded and non-rounded values, as your requirements might vary.

function extract_colors($image, $num, $level = 5) {
    $level = (int) $level;
    $palette = [];
    $size = getimagesize($image);

    if (!$size) {
        return true;
    }

    $img = imagecreatefromstring(file_get_contents($image));

    if (!$img) {
        return true;
    }

    for ($i = 0; $i < $size[0]; $i += $level) {
        for ($j = 0; $j < $size[1]; $j += $level) {
            $thisColor = imagecolorat($img, $i, $j);
            $rgb = imagecolorsforindex($img, $thisColor); 

            // With rounding
            $color = sprintf(
                '%02X%02X%02X',
                round(round(($rgb['red'] / 0x33)) * 0x33),
                round(round(($rgb['green'] / 0x33)) * 0x33),
                round(round(($rgb['blue'] / 0x33)) * 0x33)
            );

            // Without rounding
            /*
            $color = sprintf(
                '%02X%02X%02X',
                $rgb['red'],
                $rgb['green'],
                $rgb['blue']
            );
            /**/

            $palette[$color] = isset($palette[$color]) ? ++$palette[$color] : 1;
        }
    }

    arsort($palette);

    return array_slice(array_keys($palette), 0, $num);
}

Next, let’s use the function above and extract colours from an image.

$img = 'path/to/image.jpg';

// Extract 8 primary colours
$palette = extract_colors($img, 8, 1);

echo '<table>'; 

foreach ($palette as $color) { 
    echo '<tr><td style="background: #' . $color . '; width:36px;"></td><td>#' . $color . '</td></tr>';
} 

echo '</table>';

We now have a neat table with 8 colours. We can do whatever we want with them. In my case, with ImagePress, I built a search-by-colour feature, pretty useful right now, and seen in action on Dribbble, Behance, or even ArtStation.

Next, let’s extract the dominant colour

function extract_dominant_colour($image) {
    $info = getimagesize($image);
    $mime = $info['mime'];

    switch ($mime) {
        case 'image/jpeg':
            $image_create_func = 'imagecreatefromjpeg';
            break;
        case 'image/png':
            $image_create_func = 'imagecreatefrompng';
            break;
        case 'image/gif':
            $image_create_func = 'imagecreatefromgif';
            break;
    }

    $avg = $image_create_func($image);
    list($width, $height) = getimagesize($image);
    $tmp = imagecreatetruecolor(1, 1);
    imagecopyresampled($tmp, $avg, 0, 0, 0, 0, 1, 1, $width, $height);

    $rgb = imagecolorat($tmp, 0, 0);
    $r = ($rgb >> 16) & 0xFF;
    $g = ($rgb >> 8) & 0xFF;
    $b = $rgb & 0xFF;

    return sprintf("#%02x%02x%02x", $r, $g, $b);
}

Now let’s use the code:

$img = 'path/to/image.jpg';

$dominant_colour = extract_dominant_colour($img);

echo '<div style="display:inline-block; width:auto; height:400px; margin:8px; padding:24px; box-sizing:border-box; background-color:' . $dominant_colour . ';">';
echo '<img style="width:auto; max-height:100%; max-width: 100%; height:auto;" src="' . $img . '">';
echo '</div>';

Before using the code above, I used a WordPress plugin based on the Color Thief library with thousands and thousands of lines of code.

Related posts

Leave a Reply

Your email address will not be published. Required fields are marked *