Foros del Web » Programando para Internet » PHP »

APORTE: Redimencionar Gif transparentes y Animados Parte 3

Estas en el tema de APORTE: Redimencionar Gif transparentes y Animados Parte 3 en el foro de PHP en Foros del Web. Para empezar os preguntaréis cómo separamos un gif animado en sus frames y los volvemos a juntar si las funciones de PHP sólo se quedan ...
  #1 (permalink)  
Antiguo 23/04/2009, 13:02
Avatar de polin2bclan  
Fecha de Ingreso: julio-2008
Mensajes: 73
Antigüedad: 15 años, 10 meses
Puntos: 5
De acuerdo APORTE: Redimencionar Gif transparentes y Animados Parte 3

Para empezar os preguntaréis cómo separamos un gif animado en sus frames y los volvemos a juntar si las funciones de PHP sólo se quedan con el primer frame. Sencillo, con otras funciones. Aquí es donde vienen a nuestra ayuda un par de estupendas clases realizadas por László Zsidi, GIFEncoder y GIFDecoder. Su función es básicamente lo que dice su nombre, coger un gif y separarlo en sus frames o coger varios frames (o imágenes sueltas en disco) y devolver un GIF animado. El cómo no nos importa, queda fuera del alcance de este artículo y puedes consultar el código de las clases si te interesa. Simplemente comentaré que lo hace todo a nivel de bits, no utiliza ninguna función gráfica predefinida.

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.
      

Este sería el principio. Es importante comprobar si es una animación, puesto que sino será todo mucho más sencillo como vimos en el primer capítulo. La función la encontraréis en el código. De aquí, lo importante que nos queda es

* $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[&#8216;red’], $trnprt_color[‘green’], $trnprt_color[‘blue’]);
  
18.
              
if($trnprt_indx){
  
19.
                  imagefill
($temp00$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$temp20000$w$h100);
  
27.
          imagecopymerge
($temp$image$off[0], $off[1], 00$wo$ho100);      
  
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.
      

En este punto tenemos exactamente el proceso que hemos estado explicando. Todos los frames tienen el mismo tamaño y son independientes, es decir, se han ido fusionando hacia arriba de manera que podemos hacer una animación replaced. Interesante es la manera de recuperar el gif de cada frame modificado para restaurarlo al array original. No tenemos otra forma de recuperar el contenido de una imagen que no sea mostrándola o guardándola a un archivo, así que la mostramos y la recuperamos del buffer de salida.

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 (9090);
   
7.
          imagecopyresized
($dst_img$image00009090$wo$ho);
   
8.
          ob_start
();
   
9.
          imagegif
($dst_img);
  
10.
          $ARRS
[$i]=ob_get_clean();
  
11.
      

Para mostrar la imagen, se necesite o no guardarla en disco, es necesario pasarla a un archivo, pues es el proceso que hace la clase GIFEncoder. Si después no la necesitamos se puede eliminar directamente como hacemos en el ejemplo.

Código PHP:
   1.
      $gif 
= new GIFEncoder($GIFS->ARRS$GIFS->GIFS->GIFGetDelays(), 02$trnprt_color[&#8216;red’], $trnprt_color[‘green’], $trnprt_color[‘blue’], array(), "bin" );
   
2.
      $fh 
fopen("final.gif", &#8216;w’);
   
3.
      fwrite
($fh$gif->GetAnimation());
   
4.
      fclose
($fh);
   
5.
      header
("Content-type: image/gif");
   
6.
      readfile
("final.gif");
   
7.
      unlink
("final.gif"); 
Os dejo el enlace con el código fuente y el ejemplo funcionando.

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
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 18:11.