2010-09-16 20 views
5

En PHP GD cómo se puede convertir una imagen de color verdadero a una paletasin perder ningún colores. Con imagetruecolortopalleteno funciona. Tengo una función que se ejecuta en todos los colores y los filtra (por ejemplo, escala de grises). Se y no retiene todos los colores, como esta imagen de un Lamborghini-PHP GD colores de la paleta

Imagen

alt text

Este es mi código

$im = imagecreatefrompng("lamborghini.png"); 
$degrees = 0; 

$img = imagecreatetruecolor(imagesx($im), imagesy($im)); 
imagecopy($img, $im, 0, 0, 0, 0, imagesx($im), imagesy($im)); 
imagetruecolortopalette($img, true, 256); 
$t = imagecolorstotal($img); 
for ($i = 0; $i < $t; $i++) { 
    $rgb = imagecolorsforindex($img, $i); 
    $hsv =rgbtohsv($rgb['red'], $rgb['green'], $rgb['blue']); 
    $h = $degrees; 
    $s = $hsv['s']; 
    $v = $hsv['v']; 
    while ($h > 360) {$h -= 360;}; 
     $nrgb = hsvtorgb($h, $s, $v); 
    imagecolorset($img, $i, $nrgb['r'], $nrgb['g'], $nrgb['b']); 
} 
imagecopy($im, $img, 0, 0, 0, 0, imagesx($img), imagesy($img)); 

header('Content-type: image/png'); 

imagepng($im); 
imagedestroy($im); 

Y se parece a esto

alt text

Se puede ver pierde colores. ¿Hay alguna solución?

Además no creo que tiene que ver con mi código, pero la forma en que imagetruecolortopalette salidas

+0

La conversión de la paleta de la biblioteca GD es rápida, pero muy inexacta. Si desea utilizar la paleta, le recomiendo usar la línea de comando [pngquant] (https://github.com/pornel/improved-pngquant) a través de [popen()] (http://php.net/popen) - mientras esto lo haga sueltos * algunos * colores, la pérdida no será tan mala. – Kornel

Respuesta

5

Compruebe el retorno en imagecolorstotal, siempre obtendrá 256 colores como valor de retorno, sin importar cuán alto haya configurado el número de colores a los que se va a atenuar. PNG-8 & Los formatos GIF solo admiten paletas de hasta 256 colores. Por lo tanto, incluso si puede usar más de 256 en una paleta, tendrá que volver a guardarlo como color verdadero para que cualquiera pueda usarlo, lo que hace que todo el proceso de conversión sea una pérdida de tiempo. En otras palabras, imagetruecolortopallete tiene un límite superior de 256 colores, no puede ir más alto.

Así es como puede hacerlo en color verdadero, aunque requiere muchos recursos. Tal vez mirar en imagemagick si quieres hacer esto de manera más eficiente.

$im = imagecreatefrompng("lamb.png"); 
$img = imagecreatetruecolor(imagesx($im), imagesy($im)); 
$degrees = 0; 
if ($degrees > 360) {$degrees = $degrees % 360 ;} 

foreach (range(0, imagesx($im) - 1) as $x) { 
    foreach (range(0, imagesy($im) - 1) as $y) { 
     $rgb = imagecolorat($im, $x, $y); 
     $r = ($rgb >> 16) & 0xFF; 
     $g = ($rgb >> 8) & 0xFF; 
     $b = $rgb & 0xFF; 
     $hsv = rgbtohsv($r,$g,$b); 
     $rgb = hsvtorgb($degrees, $hsv['s'], $hsv['v']); 
     imagesetpixel($img, $x,$y,imagecolorallocate($img, $rgb['r'], $rgb['g'], $rgb['b'])); 
    } 
} 

imagepng($img, 'lamb2.png'); 

Editar: Adición rgbtohsv & funciones hsvtorgb. No escribí estas funciones.

function rgbtohsv ($R, $G, $B) { 
// HSV Results:Number 0-1 
$HSL = array(); 

$var_R = ($R/255); 
$var_G = ($G/255); 
$var_B = ($B/255); 

$var_Min = min($var_R, $var_G, $var_B); 
$var_Max = max($var_R, $var_G, $var_B); 
$del_Max = $var_Max - $var_Min; 

$V = $var_Max; 

if ($del_Max == 0) 
{ 
$H = 0; 
$S = 0; 
} 
else 
{ 
$S = $del_Max/$var_Max; 

$del_R = ((($var_Max - $var_R)/6) + ($del_Max/2))/$del_Max; 
$del_G = ((($var_Max - $var_G)/6) + ($del_Max/2))/$del_Max; 
$del_B = ((($var_Max - $var_B)/6) + ($del_Max/2))/$del_Max; 

if ($var_R == $var_Max) $H = $del_B - $del_G; 
else if ($var_G == $var_Max) $H = (1/3) + $del_R - $del_B; 
else if ($var_B == $var_Max) $H = (2/3) + $del_G - $del_R; 

if ($H<0) $H++; 
if ($H>1) $H--; 
} 

$HSL['h'] = $H; 
$HSL['s'] = $S; 
$HSL['v'] = $V; 

return $HSL; 
} 

function hsvtorgb ($H, $S, $V) 
{ 
$RGB = array(); 

if($S == 0) 
{ 
$R = $G = $B = $V * 255; 
} 
else 
{ 
$var_H = $H * 6; 
$var_i = floor($var_H); 
$var_1 = $V * (1 - $S); 
$var_2 = $V * (1 - $S * ($var_H - $var_i)); 
$var_3 = $V * (1 - $S * (1 - ($var_H - $var_i))); 

if ($var_i == 0) { $var_R = $V ; $var_G = $var_3 ; $var_B = $var_1 ; } 
else if ($var_i == 1) { $var_R = $var_2 ; $var_G = $V ; $var_B = $var_1 ; } 
else if ($var_i == 2) { $var_R = $var_1 ; $var_G = $V ; $var_B = $var_3 ; } 
else if ($var_i == 3) { $var_R = $var_1 ; $var_G = $var_2 ; $var_B = $V ; } 
else if ($var_i == 4) { $var_R = $var_3 ; $var_G = $var_1 ; $var_B = $V ; } 
else { $var_R = $V ; $var_G = $var_1 ; $var_B = $var_2 ; } 

$R = $var_R * 255; 
$G = $var_G * 255; 
$B = $var_B * 255; 
} 

$RGB['r'] = $R; 
$RGB['g'] = $G; 
$RGB['b'] = $B; 

return $RGB; 
} 
+0

¿Qué es 'rgbtohsv' y' hsvtorgb' – EscoMaji

+0

@EscoMaji He agregado esas funciones a la publicación. – Klinky

0

¿Qué hay de esta función: http://www.php.net/manual/en/function.imagetruecolortopalette.php. Sin embargo, podría tomar un poco de juego con la cantidad de colores para hacerlo bien.

+0

Eso es lo que ya estaba intentando, vea mi edición –

+0

¿Tiene 'dither' habilitado? ¿Y cuántos colores especificaste? –

+0

Esto es lo que tengo 'imagetruecolortopalette ($ img, true, 256);' así que sí –

2

la conversión de color verdadero en paleta siempre implicará la pérdida de colores, a menos que la tabla de paletas sea lo suficientemente grande como para contener cada color único de la imagen. El lamborghini puede tener más de (digamos) 255 tonos de amarillo solo, y luego todavía necesita ranuras de paleta para el resto de la imagen además de eso. Es por eso que hay imágenes de color verdadero. No hay paleta, pero cada píxel puede tener su propio triplete RGB dedicado para representar con mayor precisión la escena original.

Dicho esto, no puedo ver cómo la conversión de una imagen de color verdadero cambiará de amarillo a rojo como en las imágenes de muestra. ¿Cómo estás haciendo exactamente esta conversión de paleta? ¿Muestrea cada píxel y realiza algún tipo de transformación en él?

+0

Déjeme editar para explicar –

+0

¿Qué sucede si elimina el rgb-> hsv-> rgb roundtrip? ¿Ves lo que produce imagetruecolortopalette? Supongo que tienes un error en la función rgbtohsv y/o hsvtorgb, ya que incluso un generador de paleta "malo" no produciría tantos rojos a partir de una imagen fuente que esencialmente no tiene ninguno. –

+0

No Resolví el problema usando opcionalmente la paleta (para la velocidad) y el color verdadero para la calidad. –

Cuestiones relacionadas