Cambia Color de GIF con PHP

© Carolina Casanova García (a.k.a. quinqui)

Debido a varias solicitudes realizadas acerca de mi funcionalidad que permite modificar el color de una imagen usando PHP, he decidido colocar una adaptación del código, acá para que puedan ver cómo fue desarrollado.
Si deciden usar este código por vuestra cuenta, o lo usan como base para hacer el propio, les pido que por favor me mencionen en sus créditos, o al menos pongan un link a mi página o email, como una forma de respeto a mi persona. Gracias!

Acá la imagen del ejemplo:

Original Variaciones usando el Script

El código a continuación debe ser ejecutado por sí solo en un script, ya que retorna la imagen en $mrutaGif, o sea, el resultado de ejecutar ese script, es un archivo de imagen GIF.

Noten que la función reemplazará los colores exactos de la imagen por el solicitado. La función se encarga de generar, a partir del color seleccionado, la gama de sombras y luces respectivas, para poder reemplazar los colores de sombra y luces respectivos también en la imagen. Si quieren, pueden cambiar la cantidad de luces y sombras, así como los colores usados como base de reemplazo. Yo elegí una gama de grises, porque para mis intereses (dollmaker) me viene bien que los usuarios puedan ver la ropa con el usual shading que aplicamos las dollerz.

<?php
/**
-------------------------------------------------------------------------------
@about  Retorna la imagen GIF con el color seleccionado cambiado.
        Realiza un mapeo pixel a pixel de una imagen, reemplazando el color
        seleccionado por el nuevo color.
@comment  Esta es una version simplificada de mi script cambiaColor, adaptado
        para fines instructivos.
@author  Carolina Casanova Garcia (aka quinqui)
@copyright  Carolina Casanova Garcia (aka quinqui)
@url    http://www.quinqui.cl
@email  quinqui_unica [at] yahoo.com.ar
@date    01/08/2011
@update  04/07/2013 Creado esta version simplificada de la funcionalidad cambiarColor.
-------------------------------------------------------------------------------
*/

/**
****************************** IMPORTANTE *************************************
Si vas a usar este codigo en tu pagina, te pido que por favor NO BORRES los creditos,
me ha tomado tiempo y esfuerzo lograr esta funcionalidad, y no quisiera ver que
luego es usada como si nada en otros sitios, seria demasiado el descaro, no crees?

No olvides darme credito por su factoria, agregando un enlace a mi sitio web o a
mi email, en tu seccion de creditos o donde utilices este codigo.

Si no vas a usarlo tal y como lo presento aca, pero vas a crear el tuyo basado
en el mio, igual seria amable de tu parte darme el credito respectivo.

Gracias por tu consideracion.

quinqui ;)
****************************** IMPORTANTE *************************************
*/

/**
---------------------------------------
@author  Carolina Casanova Garcia
@date    01/08/2011
@return  array
*/

function nuevoColor($fcolor)
{
  global $mcolor;
  $fnuevo = false;
 
  if (!empty($fcolor) && !empty($mcolor))
  {
    $fcolor     = strtoupper($fcolor);
    $fnueColor  = $mcolor;
   
    # Obtiene nuevas Paletas
    $fpaleta["base"]  = array("red"    => hexdec(substr($fcolor, 0, 2)),
                              "green"  => hexdec(substr($fcolor, 2, 2)),
                              "blue"  => hexdec(substr($fcolor, 4, 2)),
                              "alpha"  => 0);
    $ftonos  = array("sombra"  => -32,
                    "luz"      => 32,
                    "linea"    => -80);
   
    foreach ($ftonos as $ftono => $fmodif)
    {
      $fred  = hexdec(substr($fnueColor, 0, 2)) + $fmodif;
      $fgre  = hexdec(substr($fnueColor, 2, 2)) + $fmodif;
      $fblu  = hexdec(substr($fnueColor, 4, 2)) + $fmodif;
     
      $fpaleta[$ftono]["red"]    = ($fred < 0 ? 0: ($fred > 255 ? 255: $fred));
      $fpaleta[$ftono]["green"]  = ($fgre < 0 ? 0: ($fgre > 255 ? 255: $fgre));
      $fpaleta[$ftono]["blue"]  = ($fblu < 0 ? 0: ($fblu > 255 ? 255: $fblu));
    }
   
    switch ($fcolor)
    {
      # Paleta: Base DDDDDD - Sombra BBBBBB - Luz EEEEEE - Linea 999999
      case "DDDDDD":  $fnuevo = $fpaleta["base"]; break;
      case "BBBBBB":  $fnuevo = $fpaleta["sombra"]; break;
      case "FFFFFF":  $fnuevo = $fpaleta["luz"]; break;
      case "999999":  $fnuevo = $fpaleta["linea"]; break;
    }
  } 
  return $fnuevo;
} #------------Fin Funcion-------------

# -------------------------------------
# Recibe nuevo color:

$mcolor  = $_GET["col"];

# -------------------------------------
# Propiedades de imagen:

$mrutaGif  = "polo2.gif";
$minfo  = getimagesize($mrutaGif);
$mgif["width"]  = $minfo[0];
$mgif["height"]  = $minfo[1];

# -------------------------------------
# Crea objeto Imagen (Libreria Grafica PHP)

$mimagen      = imagecreatetruecolor($mgif["width"], $mgif["height"]);
$mgif["obj"]  = imagecreatefromgif($mrutaGif);

$mcolorBG      = imagecolorallocate($mimagen, 0x11, 0xFF, 0x11);
$mcolorDebug  = imagecolorallocate($mimagen, 0, 0, 0);

# Llena fondo de imagen con el color que será transparente al final
imagefill($mimagen, $mcolorBG, 0, 0);

# -------------------------------------
# Recorre imagen pixel por pixel:

for ($y = 0; $y < $mgif["height"]; $y++)
{
  for ($x = 0; $x < $mgif["width"]; $x++)
  {
    # Obtiene color del pixel
    $mrgb = imagecolorat($mgif["obj"], $x, $y);
    $mpix  = imagecolorsforindex($mgif["obj"], $mrgb);
   
    # Si color no es transparente:
    if ($mpix["alpha"] == 0)
    {
      $mhex  = (strlen(dechex($mpix["red"])) < 2 ? "0":"").dechex($mpix["red"]).(strlen(dechex($mpix["green"])) < 2 ? "0":"").dechex($mpix["green"]).(strlen(dechex($mpix["blue"])) < 2 ? "0":"").dechex($mpix["blue"]);
      # Obtiene configuracion de nuevo color:
      $mcolorReemp  = nuevoColor($mhex);
      $mcolorReemp  = (!is_array($mcolorReemp) ? $mpix: $mcolorReemp);
      # Reemplaza color antiguo con el nuevo:
      $mnuevoColor  = imagecolorallocate($mimagen, $mcolorReemp["red"], $mcolorReemp["green"], $mcolorReemp["blue"]);
      imagesetpixel($mimagen, $x, $y, $mnuevoColor);
      unset($mcolorReemp);
    }
    # Si color es transparente:
    else
    {
      imagesetpixel($mimagen, $x, $y, $mcolorBG);
    }
    unset($mrgb, $mpix);
  }
}

# -------------------------------------
# Salida de Imagen Final

imagecolortransparent($mimagen, $mcolorBG);
imageinterlace($mimagen, 1);
header("Content-type:image/gif");
header('Content-Disposition: inline; filename="'.$mrutaGif.'"');
imagegif($mimagen);
imagedestroy($mimagen);
?>