Расчет среднего цвета между двумя цветами в PHP с использованием номера индекса в качестве справочного - PullRequest
11 голосов
/ 24 декабря 2010

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

Так, например:

У меня есть

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

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

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

Ответы [ 6 ]

12 голосов
/ 24 декабря 2010

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

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

3 голосов
/ 24 декабря 2010

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

Для простоты всегда $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)
1 голос
/ 24 декабря 2010

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

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

Посмотреть

0 голосов
/ 22 февраля 2013

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

 $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 голосов
/ 22 февраля 2013
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 голосов
/ 26 декабря 2010

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

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