Un superbe solution en javascript a été trouvée ici : https://stackoverflow.com/questions/42966641/how-to-transform-black-into-any-given-color-using-only-css-filters/43960991#43960991
La démo fonctionnelle est ici : https://codepen.io/sosuke/pen/Pjoqqp
Voici sa version en PHP : 1)
<?php class Color { public float $r; public float $g; public float $b; function __construct($r, $g, $b) { $this->r=$r; $this->g=$g; $this->b=$b; } function clamp($value) { if ($value > 255) $value = 255; elseif ($value < 0) $value = 0; return $value; } function multiply($matrix) { $newr = $this->clamp($this->r * $matrix[0] + $this->g * $matrix[1] + $this->b * $matrix[2]); $newg = $this->clamp($this->r * $matrix[3] + $this->g * $matrix[4] + $this->b * $matrix[5]); $newb = $this->clamp($this->r * $matrix[6] + $this->g * $matrix[7] + $this->b * $matrix[8]); $this->r=$newr; $this->g=$newg; $this->b=$newb; } function hueRotate($angle=0) { $angle=$angle/180*M_PI; $angsin = sin($angle); $angcos = cos($angle); $this->multiply([ 0.213 + $angcos * 0.787 - $angsin * 0.213, 0.715 - $angcos * 0.715 - $angsin * 0.715, 0.072 - $angcos * 0.072 + $angsin * 0.928, 0.213 - $angcos * 0.213 + $angsin * 0.143, 0.715 + $angcos * 0.285 + $angsin * 0.140, 0.072 - $angcos * 0.072 - $angsin * 0.283, 0.213 - $angcos * 0.213 - $angsin * 0.787, 0.715 - $angcos * 0.715 + $angsin * 0.715, 0.072 + $angcos * 0.928 + $angsin * 0.072, ]); } function grayscale($value=1) { $this->multiply([ 0.2126+0.7874*(1-$value), 0.7152-0.7152*(1-$value), 0.0722-0.0722*(1-$value), 0.2126-0.2126*(1-$value), 0.7152+0.2848*(1-$value), 0.0722-0.0722*(1-$value), 0.2126-0.2126*(1-$value), 0.7152-0.7152*(1-$value), 0.0722+0.9278*(1-$value), ]); } function sepia($value=1) { $this->multiply([ 0.393+0.607*(1-$value), 0.769-0.769*(1-$value), 0.189-0.189*(1-$value), 0.349-0.349*(1-$value), 0.686+0.314*(1-$value), 0.168-0.168*(1-$value), 0.272-0.272*(1-$value), 0.534-0.534*(1-$value), 0.131+0.869*(1-$value), ]); } function saturate($value=1) { $this->multiply([ 0.213 + 0.787 * $value, 0.715 - 0.715 * $value, 0.072 - 0.072 * $value, 0.213 - 0.213 * $value, 0.715 + 0.285 * $value, 0.072 - 0.072 * $value, 0.213 - 0.213 * $value, 0.715 - 0.715 * $value, 0.072 + 0.928 * $value, ]); } function brightness($value=1) { $this->linear($value); } function contrast($value=1) { $this->linear($value,-(0.5*$value)+0.5); } function linear($slope=1,$intercept=0) { $this->r=$this->clamp($this->r*$slope + $intercept*255); $this->g=$this->clamp($this->g*$slope + $intercept*255); $this->b=$this->clamp($this->b*$slope + $intercept*255); } function invert($value=1) { $this->r = $this->clamp(($value + $this->r/255 * (1- 2*$value)) * 255); $this->g = $this->clamp(($value + $this->g/255 * (1- 2*$value)) * 255); $this->b = $this->clamp(($value + $this->b/255 * (1- 2*$value)) * 255); } } function hsl($r,$g,$b) { $r = $r/255; $g = $g/255; $b = $b/255; $max=max($r,$g,$b); $min=min($r,$g,$b); $h=($max+$min)/2; $s=($max+$min)/2; $l=($max+$min)/2; if ($max==$min) { $h=0; $s=0; } else { $d=$max-$min; $s=($l>0.5)?$d/(2-$max-$min):$d/($max+$min); switch ($max) { case $r: $h=($g-$b)/$d+($g<$b?6:0); break; case $g: $h=($b-$r)/$d+2; break; case $b: $h=($r-$g)/$d+4; break; } $h/=6; } return array("h"=>$h*100,"s"=>$s*100,"l"=>$l*100); } function loss($filters) // Argument is array of percentages. { global $target,$targetHSL; $color=new Color(0,0,0); $color->invert($filters[0] / 100); $color->sepia($filters[1] / 100); $color->saturate($filters[2] / 100); $color->hueRotate($filters[3] * 3.6); $color->brightness($filters[4] / 100); $color->contrast($filters[5] / 100); $colorHSL=hsl($color->r,$color->g,$color->b); return ( abs($color->r - $target->r) + abs($color->g - $target->g) + abs($color->b - $target->b) + abs($colorHSL["h"] - $targetHSL["h"]) + abs($colorHSL["s"] - $targetHSL["s"]) + abs($colorHSL["l"] - $targetHSL["l"]) ); } function spsa($A, $a2, $c, $values, $iters) { $alpha = 1; $gamma = 0.16666666666666666; $best = NULL; $bestLoss = INF; $deltas=array(); $highArgs=array(); $lowArgs=array(); for ($k=0;$k<$iters;$k++) { $ck=$c/pow($k+1,$gamma); for ($i=0;$i<6;$i++) { $deltas[$i]=(rand(0,1)>0.5)?1:-1; $highArgs[$i]=$values[$i] + $ck * $deltas[$i]; $lowArgs[$i]=$values[$i] - $ck * $deltas[$i]; } $lossDiff = loss($highArgs) - loss($lowArgs); for ($i=0;$i<6;$i++) { $g = $lossDiff / (2 * $ck) * $deltas[$i]; $ak = $a2[$i] / pow($A + $k + 1, $alpha); $values[$i] = fix($values[$i] - $ak * $g, $i); } $loss=loss($values); if ($loss<$bestLoss) { $best=$values; $bestLoss=$loss; } } return array("values"=>$best,"loss"=>$bestLoss); } function fix($value, $idx) { $max=100; if ($idx==2 /* saturate */) $max=7500; elseif ($idx==4 /* brightness */ || $idx==5 /* contrast */) $max=200; if ($idx==3 /* hue-rotate */) { if ($value > $max) $value %= $max; elseif ($value<0) $value = $max + $value % $max; } elseif ($value<0) $value = 0; elseif ($value>$max) $value = $max; return $value; } function solveWide() { $A = 5; $c = 15; $a2 = [60, 180, 18000, 600, 1.2, 1.2]; $best=array("loss"=>INF); for ($i=0;$best["loss"]>25 && $i<3;$i++) { $initial = [50, 20, 3750, 50, 100, 100]; $result = spsa($A, $a2, $c, $initial, 1000); if ($result["loss"] < $best["loss"]) { $best = $result; } } return $best; } function solveNarrow($wide) { $A=$wide["loss"]; $c=2; $A1=$A+1; $a2 = [0.25*$A1, 0.25*$A1,$A1,0.25*$A1,0.2*$A1,0.2*$A1]; return spsa($A,$a2,$c,$wide["values"],500); } function solve() { $result = solveNarrow(solveWide()); return array( "values"=> $result["values"], "loss"=> $result["loss"], "filter"=> css($result["values"]), ); } function css($filters) { return "filter: invert(".round($filters[0])."%) sepia(".round($filters[1])."%) saturate(".round($filters[2])."%) hue-rotate(".round($filters[3]*3.6)."deg) brightness(".round($filters[4])."%) contrast(".round($filters[5])."%);"; } function hexToRgb($hex) { $r=hexdec(substr($hex,1,2)); $g=hexdec(substr($hex,3,2)); $b=hexdec(substr($hex,5,2)); return array($r,$g,$b); } $targetColor="#00a4d6"; // Couleur à récréer $rgb=hexToRgb($targetColor); $target=new Color($rgb[0],$rgb[1],$rgb[2]); $targetHSL=hsl($rgb[0],$rgb[1],$rgb[2]); $result=solve(); echo "<div style=\"background-color:#000;width:200px;height:200px;{$result["filter"]}\"></div>"; ?>