Вычисление среднего цвета между двумя цветами в PHP, используя номер индекса в качестве эталонного значения

В PHP я пытаюсь вычислить средний цвет (в шестнадцатеричном формате) между разными шестнадцатеричными цветами. Тем не менее, мне также нужно иметь возможность указывать индекс между 0.0 и 1.0.

Итак, например:

У меня

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

Если бы я написал функцию для получения среднего цвета, и я бы поставил 0.0 в качестве номера индекса, функция должна была бы вернуть "#ffffff". Если бы я поставил 1.0 в качестве номера индекса, функция должна была бы вернуть "#0066CC". Однако, если бы я поставил 0.2, функция должна была бы вернуть средний цвет между двумя цветами, но все же ближе к $color1, чем к $color2. Если бы я поставил индекс номер 0.5, я бы получил точный средний цвет обоих цветов.

Я пытаюсь выполнить это уже несколько дней, но я не могу понять это! Поэтому любая помощь была бы очень благодарна!

Ответ 1

Предположим, что каждый цвет имеет "значение" для целей этого обсуждения. Тогда, что вы хотите, было бы достаточно просто:

$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 или некоторые другие показатели, которые лучше подходят для вашего приложения. Идея останется прежней.

Ответ 2

Я не уверен, скомпилирует ли он, но если вы хотите, чтобы математика позади этого, это будет выглядеть примерно так:

Для простоты всегда $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

Вы можете попробовать:

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

Посмотрите

Ответ 4

Я попробовал это, используя перечисленные выше функции:

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

Ответ 5

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

Ответ 6

Или используя массив в качестве входа:

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