Foros del Web » Programando para Internet » PHP »

Redimensionar imagenes GIF animadas

Estas en el tema de Redimensionar imagenes GIF animadas en el foro de PHP en Foros del Web. Hola, estoy tratando de redimensionar imagenes GIF animadas, pero no he conseguido ninguna funcion que me sirva. El codigo que estoy usando ahorita me sirve ...
  #1 (permalink)  
Antiguo 20/09/2007, 15:13
 
Fecha de Ingreso: septiembre-2007
Mensajes: 4
Antigüedad: 16 años, 6 meses
Puntos: 0
Exclamación Redimensionar imagenes GIF animadas

Hola,

estoy tratando de redimensionar imagenes GIF animadas, pero no he conseguido ninguna funcion que me sirva.

El codigo que estoy usando ahorita me sirve para imagenes estaticas, pero al redimensionar las animadas dejan de ser animadas !

alguna idea de como hacerlo??

gracias!!
  #2 (permalink)  
Antiguo 28/09/2007, 10:21
 
Fecha de Ingreso: septiembre-2007
Mensajes: 52
Antigüedad: 16 años, 6 meses
Puntos: 2
Re: Redimensionar imagenes GIF animadas

Desafortunadamente algunas bibliotecas de imágenes (como la usada por PHP en funciones como imagecopyresampled()) no manejan correctamente los GIF animados, pero existen algunas alternativas.

Una solución sería usar otra biblioteca que sí soporte GIFs de varios cuadros, por ejemplo en PHP la extensión imagick{1} podría servir. El problema es que es una extensión independiente, con todo lo que eso implica en términos de instalación y configuración (la extensión requiere tener ImageMagick instalado, y una versión reciente de PHP).

Un ejemplo de cómo redimensionar un GIF usando imagick podría ser algo así:

Código PHP:
<?php

$entrada 
'ejemplo.gif';
$salida  'ej_reducido_imagick.gif';

// Reducir al 80% del tamaño original
$conversion 0.8;

$img = new Imagick ($entrada);

$tam $img->getImageGeometry ();

$n $img->getNumberImages ();

for (
$i 0$i $n$i++) {
    
$img->scaleImage ($tam['width'] * $conversion,
                      
$tam['height'] * $conversion);

    
$img->nextImage ();
}

$img->writeImages ($salidaTRUE);

?>

{1} http://pecl.php.net/package/imagick

(Continúa..)
  #3 (permalink)  
Antiguo 28/09/2007, 10:23
 
Fecha de Ingreso: septiembre-2007
Mensajes: 52
Antigüedad: 16 años, 6 meses
Puntos: 2
Re: Redimensionar imagenes GIF animadas

Alternativamente, si no es posible usar otras extensiones, podría manipularse el GIF directamente, redimensionando cada cuadro uno por uno usando una de las funciones que trabajan con imágenes estáticas, como imagecopyresampled(). El formato de un GIF animado no es demasiado complicado, así que con un poco de ayuda de la especificación{1} y de un programa decodificador de ejemplo{2}, he escrito un pequeño ejemplo de cómo podría implementarse esto:

Código PHP:
<?php

class GifInfo
{
    
// Gestor de lectura de archivo
    
var $_gestor;

    
// Matriz con secuencias de bytes que componen el archivo GIF
    
var $_datos;

    
// Matriz que indica cuáles índices en $datos corresponden a imágenes
    
var $_imagenes;

    
// Tabla global de colores, y su especificación de tamaño
    
var $_tcg;
    var 
$_tcg_tam;


    function 
ExtraerCompleto ()
    {
        
$bufer '';

        
$n_datos count ($this->_datos);
        for (
$i 0$i $n_datos$i++) {
            
$bufer .= $this->_datos[$i];
        }

        return 
$bufer;
    }

    function 
ExtraerImagen ($n)
    {
        if (
$n || $n $this->_imagenes['cantidad'])
            
trigger_error ("No se puede extraer la imagen número $n");

        
$bufer '';

        
$n_datos count ($this->_datos);
        for (
$i 0$i $n_datos$i++) {
            if (! isset (
$this->_imagenes['indices'][$i])
                || 
$this->_imagenes['indices'][$i] == $n)
                
$bufer .= $this->_datos[$i];
        }

        return 
$bufer;
    }

    function 
Leer ($archivo)
    {
        if (
$this->_gestor !== NULL) {
            
fclose ($this->_gestor);
        }

        
$this->_gestor fopen ($archivo'r');

        
$this->_datos = array ();

        
$this->_imagenes = array (
            
'cantidad'  => 0,
            
'cabeceras' => array (),
            
'indices'   => array ());

        
// Cabecera
        
$this->_datos[] = fread ($this->_gestor6);

        
// Descriptor lógico de pantalla
        
$this->_datos[] = fread ($this->_gestor7);
        
$dlp $this->dato_reciente ();

        
$this->_tcg '';
        
$this->_tcg_tam 0;

        if (
$this->byte ($dlp5) & 0x80 != 0) {
            
$n << ($this->byte ($dlp5) & 7);
            
$this->_tcg_tam $this->byte ($dlp5) & 7;

            
// Tabla global de colores
            
$this->_tcg fread ($this->_gestor$n);
            
$this->_datos[] = $this->_tcg;
        }

        
$fin FALSE;

        while (! 
$fin) {
            
$cod $this->leer_byte ();
            
$pos $this->dato_reciente ();

            switch (
$cod) {
            case 
0x2c:
                
$cab $this->leer_imagen ();

                
$this->agregar_imagen ($pos$this->dato_reciente (), $cab);
                break;

            case 
0x21:
                
$this->leer_extension ();
                break;

            case 
0x3b:
                
$fin TRUE;
                break;

            case 
0x00:
                break;

            default:
                
trigger_error ('Byte inválido en la imagen GIF');
            }
        }
    }

    function 
NumImagenes ()
    {
        return 
$this->_imagenes['cantidad'];
    }

    function 
ReemplazarImagen ($n$archivo_gif)
    {
        
$otro_gif = new GifInfo ();
        
$otro_gif->Leer ($archivo_gif);

        
$n_datos count ($this->_datos);

        
$bufer '';
        for (
$i 0$i $n_datos$i++) {
            if (isset (
$this->_imagenes['indices'][$i])
                && 
$this->_imagenes['indices'][$i] == $n)
                break;

            
$bufer .= $this->_datos[$i];
        }

        while (isset (
$this->_imagenes['indices'][$i])
               && 
$this->_imagenes['indices'][$i] == $n)
            
$i++;

        
$otro_n count ($otro_gif->_datos);
        
$otro_cab $otro_gif->_imagenes['cabeceras'][1];

        for (
$j 0$j $otro_n$j++) {
            if (isset (
$otro_gif->_imagenes['indices'][$j])
                && 
$otro_gif->_imagenes['indices'][$j] == 1) {

                
// Si la imagen no tiene tabla de colores local, usar la
                // global
                
if ($j == $otro_cab
                    
&& ($otro_gif->byte ($otro_cab9) & 0x80) == 0) {
                    
$byte $otro_gif->byte ($otro_cab9);

                    
$byte |= 0x80;
                    
$byte &= 0xF8;
                    
$byte |= $otro_gif->_tcg_tam;

                    
$bufer .= substr_replace ($otro_gif->_datos[$j],
                                              
chr ($byte), 81);
                    
$bufer .= $otro_gif->_tcg;

                    continue;
                }

                
$bufer .= $otro_gif->_datos[$j];
            }
        }

        for (; 
$i $n_datos$i++) {
            
$bufer .= $this->_datos[$i];
        }

        return 
$bufer;
    }

    function 
TamImagen ($n 1)
    {
        if (
$n || $n $this->_imagenes['cantidad'])
            
trigger_error ('No se puede obtener el tamaño de la imagen');

        
$cab $this->_imagenes['cabeceras'][$n];

        
$ancho $this->byte ($cab5) | ($this->byte ($cab6) << 8);
        
$alto  $this->byte ($cab7) | ($this->byte ($cab8) << 8);

        return array (
$ancho$alto);
    }


    function 
agregar_imagen ($ind_comienzo$ind_final$cabecera)
    {
        
$this->_imagenes['cantidad']++;
        
$img $this->_imagenes['cantidad'];

        
$this->_imagenes['cabeceras'][$img] = $cabecera;

        for (
$i $ind_comienzo$i <= $ind_final$i++) {
            
$this->_imagenes['indices'][$i] = $img;
        }
    }

    function 
byte ($ind_dato$ind_byte)
    {
        return 
ord (substr ($this->_datos[$ind_dato], $ind_byte 11));
    }

    function 
dato_reciente ()
    {
        return 
count ($this->_datos) - 1;
    }


    function 
leer_bloque ()
    {
        
$tam $this->leer_byte ();

        if (
$tam 0) {
            
$bloque fread ($this->_gestor$tam);

            if (
strlen ($bloque) != $tam)
                
trigger_error ('Error al leer bloque del archivo GIF');

            
$this->_datos[] = $bloque;
        }

        return 
$tam;
    }

    function 
leer_bloques ()
    {
        do {
            
$tam $this->leer_bloque ();
        } while (
$tam 0);
    }

    function 
leer_byte ()
    {
        
$byte fread ($this->_gestor1);
        
$this->_datos[] = $byte;

        return 
ord ($byte);
    }

    function 
leer_extension ()
    {
        
$cod $this->leer_byte ();

        switch (
$cod) {
        case 
0xf9:
            
$this->_datos[] = fread ($this->_gestor6);
            break;

        default:
            
$this->leer_bloques ();
        }
    }

    function 
leer_imagen ()
    {
        
// Cabecera de imagen (posición, tamaño, info)
        
$this->_datos[] = fread ($this->_gestor9);
        
$cab $this->dato_reciente ();

        if (
$this->byte ($cab9) & 0x80 != 0) {
            
$n << ($this->byte ($cab9) & 7);

            
$this->_datos[] = fread ($this->_gestor$n 3);
        }

        
// Tamaño de código LZW mínimo
        
$this->leer_byte ();

        
$this->leer_bloques ();

        return 
$cab;
    }

}


/********************
 ** Ejemplo de uso **
 ********************/

$entrada 'ejemplo.gif';
$salida  'ej_reducido.gif';
$tmp     'tmp.gif';          // archivo temporal para realizar los cambios

// Reducir al 80% del tamaño original
$conversion 0.8;

$gif = new GifInfo ();

$gif->Leer ($entrada);

$n $gif->NumImagenes ();

for (
$i 1$i <= $n$i++) {
    
$img $gif->ExtraerImagen ($i);

    list (
$ancho$alto) = $gif->TamImagen ($i);

    
$ancho_salida $ancho $conversion;
    
$alto_salida  $alto $conversion;

    
$img_fuente imagecreatefromstring ($img);
    
$img_destino imagecreate ($ancho_salida$alto_salida);

    
imagecopyresampled ($img_destino$img_fuente,
                        
0000,
                        
$ancho_salida$alto_salida,
                        
$ancho$alto);

    
imagegif ($img_destino$tmp);

    
$img $gif->ReemplazarImagen ($i$tmp);
    
file_put_contents ($tmp$img);
    
$gif->Leer ($tmp);
}

file_put_contents ($salida$gif->ExtraerCompleto ());

?>
Quizás el detalle más delicado al redimensionar un GIF animado es el manejo de las tablas de colores. La paleta de colores de cada cuadro redimensionado suele ser diferente a la paleta de la imagen original, y por esto no pueden simplemente copiarse directamente los cuadros redimensionados, ya que entonces éstos podrían aparecer con colores extraños.

Una solución bastante razonable sería computar una nueva tabla de colores global en base a las paletas de cada cuadro redimensionado, pero todo eso ya luce más como labor para una biblioteca especializada de imágenes :). En su lugar, el ejemplo anterior copia cada cuadro con su propia paleta de colores como paleta local. El GIF final no resulta tan optimizado como podría ser, pero es algo :).


Finalmente, nota que el proceso de redimensionar un GIF animado suele ser un poco lento, especialmente si hay muchos cuadros, así que si te resulta posible, sería recomendable que hagas las conversiones usando un programa independiente, como por ejemplo ImageMagick{3}, antes de usar tus imágenes desde PHP.


{1} http://www.w3.org/Graphics/GIF/spec-gif89a.txt
{2} http://www.fmsware.com/stuff/GifDecoder.java
{3} http://www.imagemagick.org/script/index.php
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.
Tema Cerrado




La zona horaria es GMT -6. Ahora son las 16:33.