best = ['r' => 204, 'g' => 204, 'b' => 204]; // #cccccc // We will be needing to read this... if (!file_exists($asset->getPath())) return; // Try the arcane stuff again. try { $image = new Imagick($asset->getPath()); $width = $image->getImageWidth(); $height = $image->getImageHeight(); // Sample six points in the image: four based on the rule of thirds, as well as the horizontal and vertical centre. $topy = round($height / 3); $bottomy = round(($height / 3) * 2); $leftx = round($width / 3); $rightx = round(($width / 3) * 2); $centery = round($height / 2); $centerx = round($width / 2); // Grab their colours. $rgb = [ $image->getImagePixelColor($leftx, $topy)->getColor(), $image->getImagePixelColor($rightx, $topy)->getColor(), $image->getImagePixelColor($leftx, $bottomy)->getColor(), $image->getImagePixelColor($rightx, $bottomy)->getColor(), $image->getImagePixelColor($centerx, $centery)->getColor(), ]; // We won't be needing this anymore, so save us some memory. $image->clear(); $image->destroy(); } // In case something does go wrong... catch (ImagickException $e) { // Fall back to default color. return; } // Process rgb values into hsv values foreach ($rgb as $i => $color) { $colors[$i] = $color; list($colors[$i]['h'], $colors[$i]['s'], $colors[$i]['v']) = self::rgb2hsv($color['r'], $color['g'], $color['b']); } // Figure out which color is the best saturated. $best_saturation = $best_brightness = 0; $the_best_s = $the_best_v = ['v' => 0]; foreach ($colors as $color) { if ($color['s'] > $best_saturation) { $best_saturation = $color['s']; $the_best_s = $color; } if ($color['v'] > $best_brightness) { $best_brightness = $color['v']; $the_best_v = $color; } } // Is brightest the same as most saturated? $this->best = ($the_best_s['v'] >= ($the_best_v['v'] - ($the_best_v['v'] / 2))) ? $the_best_s : $the_best_v; } public static function hex2rgb($hex) { return sscanf($hex, '%2X%2X%2X'); } public static function rgb2hex($red, $green, $blue) { return sprintf('%02X%02X%02X', $red, $green, $blue); } public static function rgb2hsv($r, $g, $b) { $max = max($r, $g, $b); $min = min($r, $g, $b); $delta = $max - $min; $v = round(($max / 255) * 100); $s = ($max != 0) ? (round($delta / $max * 100)) : 0; if ($s == 0) { $h = false; } else { if ($r == $max) $h = ($g - $b) / $delta; elseif ($g == $max) $h = 2 + ($b - $r) / $delta; elseif ($b == $max) $h = 4 + ($r - $g) / $delta; $h = round($h * 60); if ($h > 360) $h = 360; if ($h < 0) $h += 360; } return [$h, $s, $v]; } /** * Get a normal (light) background color as hexadecimal value (without hash prefix). * @return color string */ public function hex() { $c = $this->best; return self::rgb2hex($c['r'], $c['g'], $c['b']); } /** * Get a 50% darker version of the best color as string. * @param factor, defaults to 0.5 * @param alpha, defaults to 0.7 * @return rgba(r * factor, g * factor, b * factor, alpha) */ public function rgba($factor = 0.5, $alpha = 0.7) { $c = $this->best; return 'rgba(' . round($c['r'] * $factor) . ', ' . round($c['g'] * $factor) . ', ' . round($c['b'] * $factor) . ', ' . $alpha . ')'; } }