Al final de todo tenéis un zip con todo el código fuente y las clases necesarias.
Código PHP:
1.
include(dirname(__FILE__)."/GIFDecoder.class.php");
2.
include(dirname(__FILE__)."/GIFEncoder.class.php");
3.
4.
$gifcontents=file_get_contents("miarchivo.gif");
5.
if(is_gif_animado($gifcontents)){
6.
$GIFS=new GIFDecoder($gifcontents);
7.
$ARRS=$GIFS->GIFGetFrames();
8.
$OFFSETS=$GIFS->GIFGetOffset();
9.
}
* $GIFS->GifGetFrames() contiene los frames del gif
* $GIFS->GifGetOffset() las desviaciones en la posición de cada capa.
Con esto podemos comenzar a operar sobre cada gif a través del array ARRS. El código está explicado en los comentarios. Es importante anotar que tanto el color de la transparencia como el tamaño de la imagen lo obtenemos con las funciones estandard. Esto lo hacemos así porque no encontré la manera de saber el color de transparencia a traves del GIFDecoder y, ya que tenía la imagen abierta, saco el tamaño.
Código PHP:
1.
//con las funciones estandard detectamos el tamaño del primer frame y el color de transparencia
2.
$srcImage = imagecreatefromgif($ipath);
3.
$transcolor=imagecolortransparent($srcImage);
4.
$w=imagesx($srcImage);
5.
$h=imagesy($srcImage);for($i=0; $i<count($ARRS); $i++){
6.
//el primer frame se queda como esta
7.
if($i>0){ $image=imagecreatefromstring($ARRS[$i]);
8.
$wo=imagesx($image);
9.
$ho=imagesy($image);
10.
$off=$OFFSETS[$i];
11.
//fusionamos el frame con el anterior
12.
$temp=imagecreatetruecolor($w, $h);
13.
$temp2=imagecreatefromstring($ARRS[$i-1]);
14.
//hay que tener en cuenta la posible transparencia, sino no hacemos nada
15.
if($transcolor!=-1){
16.
$trnprt_color = @imagecolorsforindex($image, $transcolor);
17.
$trnprt_indx = @imagecolorallocate($temp, $trnprt_color[‘red’], $trnprt_color[‘green’], $trnprt_color[‘blue’]);
18.
if($trnprt_indx){
19.
imagefill($temp, 0, 0, $trnprt_indx);
20.
imagecolortransparent($temp, $trnprt_indx);
21.
imagecolortransparent($image, $transcolor);
22.
}
23.
}
24.
25.
//creamos una imagen con el frame anterior y superponemos el actual con el offset necesario
26.
imagecopymerge($temp, $temp2, 0, 0, 0, 0, $w, $h, 100);
27.
imagecopymerge($temp, $image, $off[0], $off[1], 0, 0, $wo, $ho, 100);
28.
29.
//capturamos el nuevo frame
30.
ob_start();
31.
imagegif($temp);
32.
$GIFS->ARRS[$i]=ob_get_clean();
33.
34.
//ya no hay offsets puesto que todos tienen el mismo tamaño
35.
$GIFS->offsets[$i][0]=0;
36.
$GIFS->offsets[$i][1]=0;
37.
imagedestroy($temp);
38.
}
39.
}
Ahora podemos hacer lo que necesitemos con la imagen, escalarla, imprimir texto, rotarla, etc. Nosotros la escalaremos, haremos un thumbnail de 90×90. Tan sencillo como hacer el proceso en todos y cada uno de los frames.
Código PHP:
1.
//ahora si queremos podemos redimensionar los frames, por ejemplo hacemos thumbnail
2.
for($i=0; $i<count($ARRS); $i++){
3.
$image=imagecreatefromstring($ARRS[$i]);
4.
$wo=imagesx($image);
5.
$ho=imagesy($image);
6.
$dst_img=imagecreatetruecolor (90, 90);
7.
imagecopyresized($dst_img, $image, 0, 0, 0, 0, 90, 90, $wo, $ho);
8.
ob_start();
9.
imagegif($dst_img);
10.
$ARRS[$i]=ob_get_clean();
11.
}
Código PHP:
1.
$gif = new GIFEncoder($GIFS->ARRS, $GIFS->GIFS->GIFGetDelays(), 0, 2, $trnprt_color[‘red’], $trnprt_color[‘green’], $trnprt_color[‘blue’], array(), "bin" );
2.
$fh = fopen("final.gif", ‘w’);
3.
fwrite($fh, $gif->GetAnimation());
4.
fclose($fh);
5.
header("Content-type: image/gif");
6.
readfile("final.gif");
7.
unlink("final.gif");
Como véis el proceso es bastante complejo, pero una vez se entiende el funcionamiento del GIF animado todo es más sencillo. Como comentario adicional, si váis a implementar un sistema de escalado en tiempo real, yo pensaría en cachear los resultados por aquello de optimizar un poco el sistema y no sobrecargar la cpu, después de todo estamos hablando de trabajo con imágenes, algo bastante pesado en memoria.
Finalmente, utilizaba inicialmente la función de comprobación de que una imagen es animada de László Zsidi, sin embargo detectamos que, en determinadas situaciones, entraba en un bucle infinito y terminaba saturando nuestro Apache de procesos ocupados en el bucle infinito. Menos mal que tenía otra versión más antigua de una función que hacía lo mismo. Deuteros me lo agradece enormemente.
Link autor
Parte 1
Parte 2
Parte 3