2012-05-11 19 views
5

¿Es posible verificar si un cierto color hexadecimal está más cerca de FFF o 000 según un 'valor-central' definido?Calcular coliformidad

Quiero comprobar si un color se encuentra más cerca de #FFF o # 000 según # 888. Así que si compruebo que #EFEFEF debería devolver #FFF y si intento # 878787 debería devolver # 000.

¿Cómo se puede lograr esto? No estoy seguro de qué buscar en Google ...

Gracias de antemano

+1

no es # 898989 mayor que # 888 (# 888888) y por lo tanto debe devolver #fff? # 878787 debe ser el valor más alto que devuelve # 000 en mi opinión ... – oezi

+0

Debe decidir cómo debe calcularse [distancia] (http://en.wikipedia.org/wiki/Color_difference). – Jon

+1

@oezi: Quiere usar # 888 como color de referencia sesgado, lo que significa que lo que realmente quiere hacer es comparar un color entre # 888 y #FFF, y devolver el # 000 o el #FFF dependiendo de cuál sea más cercano (básicamente devuelve # 000 si el color es más cercano a # 888 que a #FFF). –

Respuesta

2

La manera más fácil de resolver su problema es calcular la distancia entre los colores usando sus valores de escala de grises (hay otras formas, pero esto es simple). Así que algo como:

// returns a distance between two colors by comparing each component 
// using average of the RGB components, eg. a grayscale value 
function color_distance($a, $b) 
{ 
    $decA = hexdec(substr($a, 1)); 
    $decB = hexdec(substr($a, 1)); 
    $avgA = (($decA & 0xFF) + (($decA >> 8) & 0xFF) + (($decA >> 16) & 0xFF))/3; 
    $avgB = (($decB & 0xFF) + (($decB >> 8) & 0xFF) + (($decB >> 16) & 0xFF))/3; 
    return abs($avgA - $avgB); 
} 

// I am going to leave the naming of the function to you ;) 
// How this works is that it'll return $minColor if $color is closer to $refColorMin 
// and $maxColor if $color is closer to $refColorMax 
// all colors should be passed in format #RRGGBB 
function foo($color, $refColorMin, $refColorMax, $minColor, $maxColor) 
{ 
    $distMin = color_distance($color, $refColorMin); 
    $distMax = color_distance($color, $refColorMax); 
    return ($distMin < $distMax) ? $minColor : $maxColor; 
} 

// Example usage to answer your original question: 
$colorA = foo('#EFEFEF', '#888888', '#FFFFFF', '#000000', '#FFFFFF'); 
$colorA = foo('#898989', '#888888', '#FFFFFF', '#000000', '#FFFFFF'); 
// Check the values 
var_dump($colorA, $colorB); 

La salida es:

string(7) "#FFFFFF" 
string(7) "#000000" 
3

Se podría convertir los colores a los números:

$color_num = hexdec(substr($color, 1)); // skip the initial # 

luego compararlas con cualquiera 0x0 o 0xffffff.

También podría desglosarlos en R, G y B y hacer tres comparaciones; luego promediarlos? No está seguro de lo preciso que desea que esta cosa :)

+0

Comparar los valores decimales convertidos directamente no es una buena idea, ya que los bits almacenados para algunos componentes tienen valores más altos que los componentes para otros. Entonces, por ejemplo, si los bits rojos se almacenaron en los bits de mayor orden y los azules en los bits de menor orden, los bits rojos pesarían más que los bits azules y verdes en general, lo que no daría resultados muy precisos. Tu idea de usar un promedio es buena; es lo que utilicé en mi respuesta también. –

+0

@reko_t buen punto :) su respuesta es sustancialmente más elaborada que la mía jeje –

1

Se podría hacer algo como lo siguiente:

function hex2rgb($hex) { 
    $hex = str_replace("#", "", $hex); 

    if(strlen($hex) == 3) { 
     $r = hexdec(substr($hex,0,1).substr($hex,0,1)); 
     $g = hexdec(substr($hex,1,1).substr($hex,1,1)); 
     $b = hexdec(substr($hex,2,1).substr($hex,2,1)); 
    } else { 
     $r = hexdec(substr($hex,0,2)); 
     $g = hexdec(substr($hex,2,2)); 
     $b = hexdec(substr($hex,4,2)); 
    } 
    $rgb = array($r, $g, $b); 
    //return implode(",", $rgb); // returns the rgb values separated by commas 
    return $rgb; // returns an array with the rgb values 
} 

$rgb = hex2rgb("#cc0"); 

Desde que se podía tomar los valores de $ rgb y ver si sus valores, en promedio, una mayor área de que o menos de 122.5. Si es mayor que 122.5 estarás más cerca de #FFFFFF, inferior a 122.5 estarías más cerca de # 000000.

0

Gracias a todos por la ayuda!

En mi startpost hice un pequeño error tipográfico mencionado por oezi. Para mí, la solución fue una pequeña modificación en la respuesta aceptada (por reko_t):

function color_distance($sColor1, $sColor2) 
{ 
    $decA = hexdec(substr($sColor1, 1)); 
    $decB = hexdec(substr($sColor2, 1)); 
    $avgA = (($decA & 0xFF) + (($decA >> 8) & 0xFF) + (($decA >> 16) & 0xFF))/3; 
    $avgB = (($decB & 0xFF) + (($decB >> 8) & 0xFF) + (($decB >> 16) & 0xFF))/3; 
    return abs($avgA - $avgB); 
} 

function determine_color($sInputColor, $sRefColor, $sMinColor, $sMaxColor) 
{ 
    $distRef = color_distance($sInputColor, $sRefColor); 
    $distMin = color_distance($sInputColor, $sMinColor); 
    $distMax = color_distance($sInputColor, $sMaxColor); 

    return $distMax - $distRef < $distMin - $distRef ? $sMinColor : $sMaxColor; 
} 

que necesitaba esta función para determinar texto de color sobre un fondo color que puede ser ajustado por un cierto ajuste. ¡Gracias! :) Créditos para reko_t!