问题 使用索引号作为参考值计算PHP中两种颜色之间的平均颜色


在PHP中,我试图计算不同的十六进制颜色之间的平均颜色(以十六进制)。但是,我还需要能够提供介于0.0和1.0之间的索引号。

例如:

我有

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

如果我写一个函数来获得平均颜色,我会提供0.0作为索引号,该函数将需要返回“#ffffff“。如果我提供1.0作为索引号,那么函数将需要返回”#0066CC“但是如果我提供0.2,那么该函数需要返回两种颜色之间的平均颜色,但仍然更接近 $color1 而不是 $color2。如果我提供索引号0.5,我会得到两种颜色的确切平均颜色。

我一直试图完成这几天,但我似乎无法弄明白!任何帮助将非常感谢!


8438
2017-12-24 11:32


起源



答案:


为了讨论的目的,我们假设每种颜色都有一个“值”。那么,你想要的就是这么简单:

$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);

因此,困难的部分是弄清楚每种颜色的“价值”是什么。

您可以使用简单的RGB值,其中每种颜色的“值”是一组三个整数:

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]);
}

这里需要分别对每个数组元素进行乘法和加法。我认为在这一点上应该很容易使用一个简单易用的功能来自己混合颜色。

如果这不是您所需要的,那么您可以使用HSL值或其他更适合您应用的指标。这个想法将保持不变。


12
2017-12-24 11:43



删除了我的答案,因为它根本不适用于十六进制RGB颜色的设计方式。你的事情要简单得多。 - BoltClock♦
删除了我的答案,并了解了sprintf功能,谢谢!对于此代码,这意味着您不必检查十进制数是否只有1位数,因为您使用0填充它。 - Andy
大家好!好吧,我用Andy的版本说实话,它完美无缺!!正是我需要的..但​​是你们这些人说我应该使用Jon的版本而不是??? - R_K
@Roel:使用你喜欢的任何东西。我的回答是故意解释而不是功能,所以我不是说这是复制/粘贴的最佳解决方案。 - Jon


答案:


为了讨论的目的,我们假设每种颜色都有一个“值”。那么,你想要的就是这么简单:

$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);

因此,困难的部分是弄清楚每种颜色的“价值”是什么。

您可以使用简单的RGB值,其中每种颜色的“值”是一组三个整数:

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]);
}

这里需要分别对每个数组元素进行乘法和加法。我认为在这一点上应该很容易使用一个简单易用的功能来自己混合颜色。

如果这不是您所需要的,那么您可以使用HSL值或其他更适合您应用的指标。这个想法将保持不变。


12
2017-12-24 11:43



删除了我的答案,因为它根本不适用于十六进制RGB颜色的设计方式。你的事情要简单得多。 - BoltClock♦
删除了我的答案,并了解了sprintf功能,谢谢!对于此代码,这意味着您不必检查十进制数是否只有1位数,因为您使用0填充它。 - Andy
大家好!好吧,我用Andy的版本说实话,它完美无缺!!正是我需要的..但​​是你们这些人说我应该使用Jon的版本而不是??? - R_K
@Roel:使用你喜欢的任何东西。我的回答是故意解释而不是功能,所以我不是说这是复制/粘贴的最佳解决方案。 - Jon


我不确定它是否会编译,但如果你想要数学背后,它会是这样的:

为简单起见,总是有 $color1 大于 $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)

3
2017-12-24 12:05



兑换单行程+1。 Sweeet!
@Junky:这样的代码看起来很好......如果你不需要维护它。 - Jon
有什么可以保持?这是一条线?! - TheDarkIn1978


你可以试试:

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

看见


1
2017-12-24 12:08



+1为 str_split。我不知道PHP有第574个字符串操作函数! - Jon


我尝试使用上面提到的功能:

/* 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);

0
2017-12-26 18:26





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

0
2018-02-22 14:01





或者使用数组作为输入:

 $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; }

-1
2018-02-22 14:21