2008-11-11 19 views
39

Actualmente estoy teniendo problemas para cambiar el tamaño de las imágenes usando GD.¿Puedo detectar gifs animados usando php y gd?

Todo funciona bien hasta que quiera cambiar el tamaño de un gif animado, que entrega el primer fotograma sobre un fondo negro.

He intentado usar getimagesize pero eso solo me da las dimensiones y nada para distinguir entre cualquier gif y uno animado.

No es necesario el cambio de tamaño real para los gifs animados, solo para poder omitirlos sería suficiente para nuestros propósitos.

¿Alguna pista?

PS. No tengo acceso a imagemagick.

Saludos cordiales,

Kris

+0

El autor dijo que no tiene ImageMagick. Pero para todo el mundo, la búsqueda de alguna forma de averiguar si un gif está animado y se ha abierto camino aquí desde Google (como yo): ImageMagick lo hace con bastante facilidad: http://php.net/manual/en/imagick.getimageiterations .php – Lukas

Respuesta

17

Hay un breve fragmento de código en la página del manual de PHP de la función imagecreatefromgif() que debe ser lo que necesita:

imagecreatefromgif comment #59787 by ZeBadger

+0

Extraño que no encontré eso en mi espejo por defecto del manual, pero los tanques para el enlace. Modifiqué la función y le di tanto el póster original como tu crédito en el comentario. – Kris

+0

Una versión optimizada [aquí] (http://it1.php.net/manual/en/function.imagecreatefromgif.php#104473). –

+1

Ese enlace está inactivo por alguna razón, todavía se puede encontrar aquí: http://php.net/manual/en/function.imagecreatefromgif.php # 104473 – robjbrain

5

Aquí está la función de trabajo:

/** 
* Thanks to ZeBadger for original example, and Davide Gualano for pointing me to it 
* Original at http://it.php.net/manual/en/function.imagecreatefromgif.php#59787 
**/ 
function is_animated_gif($filename) 
{ 
    $raw = file_get_contents($filename); 

    $offset = 0; 
    $frames = 0; 
    while ($frames < 2) 
    { 
     $where1 = strpos($raw, "\x00\x21\xF9\x04", $offset); 
     if ($where1 === false) 
     { 
      break; 
     } 
     else 
     { 
      $offset = $where1 + 1; 
      $where2 = strpos($raw, "\x00\x2C", $offset); 
      if ($where2 === false) 
      { 
       break; 
      } 
      else 
      { 
       if ($where1 + 8 == $where2) 
       { 
        $frames ++; 
       } 
       $offset = $where2 + 1; 
      } 
     } 
    } 

    return $frames > 1; 
} 
37

Mientras buscaba una solución para el mismo problema, noté que el sitio php.net tiene una continuación del código al que se refieren Davide y Kris, pero, según el autor, menos memoria intensiva y posiblemente menos disco- intensivo.

Lo replicaré aquí, porque puede ser de su interés.

fuente: http://www.php.net/manual/en/function.imagecreatefromgif.php#88005

function is_ani($filename) { 
    if(!($fh = @fopen($filename, 'rb'))) 
     return false; 
    $count = 0; 
    //an animated gif contains multiple "frames", with each frame having a 
    //header made up of: 
    // * a static 4-byte sequence (\x00\x21\xF9\x04) 
    // * 4 variable bytes 
    // * a static 2-byte sequence (\x00\x2C) 

    // We read through the file til we reach the end of the file, or we've found 
    // at least 2 frame headers 
    while(!feof($fh) && $count < 2) { 
     $chunk = fread($fh, 1024 * 100); //read 100kb at a time 
     $count += preg_match_all('#\x00\x21\xF9\x04.{4}\x00[\x2C\x21]#s', $chunk, $matches); 
    } 

    fclose($fh); 
    return $count > 1; 
} 
+0

Se agregó la corrección de Stevio a continuación. –

+7

Una nota agregada recientemente menciona que photoshop puede usar '\ x00 \ x21' en lugar de' \ x00 \ x2C' –

+6

La nota de Frank no es tan explícita como debería ser. Para otros que estén viendo esta página, consulte su explicación completa en [aquí] (http://www.php.net/manual/en/function.imagecreatefromgif.php#104473) – billmalarky

-1

GIF animados deben tiene la siguiente cadena

"\x21\xFF\x0B\x4E\x45\x54\x53\x43\x41\x50\x45\x32\x2E\x30" 
2

Leyendo el archivo entero con file_get_contents puede tomar demasiada memoria si el archivo dado es demasiado grande. He vuelto a factorizar la función dada previamente que lee suficientes bytes para verificar cuadros y regresa tan pronto como encuentra al menos 2 fotogramas.

<?php 
/** 
* Detects animated GIF from given file pointer resource or filename. 
* 
* @param resource|string $file File pointer resource or filename 
* @return bool 
*/ 
function is_animated_gif($file) 
{ 
    $fp = null; 

    if (is_string($file)) { 
     $fp = fopen($file, "rb"); 
    } else { 
     $fp = $file; 

     /* Make sure that we are at the beginning of the file */ 
     fseek($fp, 0); 
    } 

    if (fread($fp, 3) !== "GIF") { 
     fclose($fp); 

     return false; 
    } 

    $frames = 0; 

    while (!feof($fp) && $frames < 2) { 
     if (fread($fp, 1) === "\x00") { 
      /* Some of the animated GIFs do not contain graphic control extension (starts with 21 f9) */ 
      if (fread($fp, 1) === "\x2c" || fread($fp, 2) === "\x21\xf9") { 
       $frames++; 
      } 
     } 
    } 

    fclose($fp); 

    return $frames > 1; 
} 
+0

+1 por ser absolutamente cierto. En aquel entonces, sin embargo, los archivos eran pequeños y leerlos en su totalidad era más rápido que byte a byte por razones que no investigaba, o que no recuerdo haber investigado. – Kris

+0

Tenga en cuenta que 'fread ($ fp, 1) ===" \ x2c "|| fread ($ fp, 2) === "\ x21 \ xf9" 'leerá primero un byte (A), verifique que sea 0x2C, de lo contrario leerá los dos bytes ** después de ** byte A, no después el byte 0x00. Entonces, las cadenas de bytes coincidentes son '00 2C' o' 00 ** 21 F9' donde '**' significa cualquier byte. No estoy seguro de si esto es intencionado o no, pero no está muy claro en el código. – Qtax

0

Esta es una mejora de la parte superior actual votado respuesta, pero no tengo la reputación suficiente para comentar todavía. El problema con esa respuesta es que lee el archivo en trozos de 100 Kb y el marcador de fin de trama se puede dividir entre 2 trozos. Una solución para eso es agregar los últimos 20b del cuadro anterior al siguiente:

<?php 
function is_ani($filename) { 
    if(!($fh = @fopen($filename, 'rb'))) 
    return false; 
    $count = 0; 
    //an animated gif contains multiple "frames", with each frame having a 
    //header made up of: 
    // * a static 4-byte sequence (\x00\x21\xF9\x04) 
    // * 4 variable bytes 
    // * a static 2-byte sequence (\x00\x2C) (some variants may use \x00\x21 ?) 

    // We read through the file til we reach the end of the file, or we've found 
    // at least 2 frame headers 
    $chunk = false; 
    while(!feof($fh) && $count < 2) { 
    //add the last 20 characters from the previous string, to make sure the searched pattern is not split. 
    $chunk = ($chunk ? substr($chunk, -20) : "") . fread($fh, 1024 * 100); //read 100kb at a time 
    $count += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches); 
    } 

    fclose($fh); 
    return $count > 1; 
} 
Cuestiones relacionadas