开发者

Calculating the average color between two colors in PHP, using an index number as reference value

In PHP, I am trying to calculate the average color (in hex) between to different hex colors. However, I also need to be able to supply an index number between 0.0 and 1.0.

So for example:

I have

$color1 = "#ffffff" 
$color2 = "#0066CC"

If I would write a function to get the average color and I would supply 0.0 as the index number, the function would need to return "#ffffff". If I would supply 1.0 as the index number, the function would need to return开发者_如何学C "#0066CC". However if I would supply 0.2, the function would need to return an average color between the two colors, but still closer to $color1 than to $color2. If I would supply index number 0.5, I would get the exact average color of both colors.

I have been trying to accomplish this for several days now but I can't seem to figure it out! Any help would therefor be greatly appreciated!


Let's assume that each color has a "value" for the purposes of this discussion. Then, what you want would be simple enough to do:

$index = 0.2;
$val1 = get_value_of_color($color1);
$val2 = get_value_of_color($color2);
$newval = $val1 * $index + $val2 * (1 - $index);
$newcolor = get_color_from_value($newval);

So, the hard part is figuring out what the "value" of each color is.

You could go with simple RGB values, where the "value" of each color is a set of three integers:

function get_value_of_color($color) {
    // assume $color is in the form #xxxxxx
    return array(
        hexdec(substr($color, 1, 2)),
        hexdec(substr($color, 3, 2)),
        hexdec(substr($color, 5, 2)),
    );
}

function get_color_from_value($value) {
    return sprintf('#%02x%02x%02x', $value[0], $value[1], $value[2]);
}

The multiplications and addition would need to be done on each array element separately here. I think at this point it should be easy to make a simple-to-use function to mix colors yourself.

If this is not what you need, then you can go with HSL values or some other metric that better suits your application. The idea would remain the same.


I am not sure if it will compile but if you want the math behind this it would go something like this:

For simplicity, always have $color1 be bigger than $color2.

$dec1 = hexdec($hex_color1);
$dec2 = hexdec($hex_color2);

$dec1 = ($dec1 < $dec2) ? $dec1^=$dec2^=$dec1^=$dec2 : $dec1;

$new_hex_color = dechex($dec1 - ($dec1 - $dec2)*index_number)


You can try:

function color_avg($color1,$color2,$factor) {

        // extract RGB values for color1.
        list($r1,$g1,$b1) = str_split(ltrim($color1,'#'),2);
        // extract RGB values for color2.
        list($r2,$g2,$b2) = str_split(ltrim($color2,'#'),2);

        // get the average RGB values.
        $r_avg = (hexdec($r1)*(1-$factor)+hexdec($r2)*$factor);
        $g_avg = (hexdec($g1)*(1-$factor)+hexdec($g2)*$factor);
        $b_avg = (hexdec($b1)*(1-$factor)+hexdec($b2)*$factor);

        // construct the result color.    
        $color_avg = '#'.sprintf("%02s",dechex($r_avg)).
                        sprintf("%02s",dechex($g_avg)).
                        sprintf("%02s",dechex($b_avg));


        // return it.
        return $color_avg;
}

See it


I tried this using the functions mentioned above:

/* 24-bit RGB */
/* (a + b) / 2 = ((a ^ b) >> 1) + (a & b) */
function averageRGB($a, $b){
  return ((($a ^ $b) & 0xfffefefe) >> 1) + ($a & $b);
}

$index = 0.5;
$val1 = get_value_of_color('#FFFFFF');
$val2 = get_value_of_color('#000000');

$aIndexed = array();

for($i=0; $i < 3; $i++){
     if($index == 0.5){
        $aIndexed[$i] = averageRGB($val1[$i],$val2[$i]);
     }else{
        $aIndexed[$i] = $val1[$i] * $index + $val2[$i] * (1 - $index);
     }    
}

echo get_color_from_value($aIndexed);


function colorDiff($color1,$color2) {
    $color1=    ltrim($color1,'#');
    $color2=    ltrim($color2,'#'); 
    $red1 =     hexdec(substr($color1,0,2));
    $green1 =  hexdec(substr($color1,2,2));
    $blue1 =    hexdec(substr($color1,4,2));
    $red2 =     hexdec(substr($color2,0,2));
    $green2 =  hexdec(substr($color2,2,2));
    $blue2 =   hexdec(substr($color2,4,2));
    $red =  dechex(round(($red1+$red2)/2));
    $green =    dechex(round(($green1+$green2)/2));
    $blue =     dechex(round(($blue1+$blue2)/2));
    if (strlen($red) == 1) { $red = '0'.$red; }
    if (strlen($green) == 1) { $green = '0'.$green; }
    if (strlen($blue) == 1) { $blue = '0'.$blue; }
    $newcolor = '#'.$red.''.$green.''.$blue;
    return $newcolor;
}


Or using an array as input :

 $color_arr =
array('#FF0000','#0000FF','#FF0000','#0000FF','#0000FF','#0000FF');
$newcolor = colorDiffArr($color_arr); foreach ($color_arr as $color) {
    echo '<div style="display:block; background:'.$color.';"
 bgcolor="'.$color.'; width:10px; height:10px;">'.$color.'</div>'; }
 echo '<div style="display:block; background:'.$newcolor.';"
 bgcolor="'.$newcolor.'; width:10px;
 height:10px;">'.$newcolor.'</div>';
 function colorDiffArr($color_arr) {    
       $red = 0; $green = 0; $blue = 0;
       foreach ($color_arr as $color) {         
          $color= ltrim($color,'#');
          $red+=hexdec(substr($color,0,2));         
          $green+=hexdec(substr($color,2,2));       
          $blue+=hexdec(substr($color,4,2));    }
       $red =       dechex(round(($red)/count($color_arr)));    
          $green =
    dechex(round(($green)/count($color_arr)));  $blue =
    dechex(round(($blue)/count($color_arr)));       if (strlen($red) == 1) {
 $red = '0'.$red; }     if (strlen($green) == 1) { $green = '0'.$green; }
    if (strlen($blue) == 1) { $blue = '0'.$blue; }  $newcolor =
 '#'.$red.''.$green.''.$blue;   return $newcolor; }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜