2008-11-11 3 views
39

В настоящее время у меня возникают проблемы с изменением размера изображений с использованием GD.Могу ли я обнаружить анимированные gifs, используя php и gd?

Все работает нормально, пока я не хочу изменить размер анимированного gif, который обеспечивает первый кадр на черном фоне.

Я пробовал использовать getimagesize, но это только дает мне размеры и ничего не отличает только любой gif и анимированный.

Фактическое изменение размера не требуется для анимированных gif, просто быть в состоянии пропустить их было бы достаточно для наших целей.

Любые подсказки?

PS. У меня нет доступа к imagemagick.

С наилучшими пожеланиями,

Kris

+0

Автор сказал, что у него нет ImageMagick. Но для всех людей поиск любого способа узнать, оживлен ли gif и найти их здесь из Google (например, я): ImageMagick делает это довольно легко: http://php.net/manual/en/imagick.getimageiterations .php – Lukas 2014-09-29 15:00:59

ответ

17

Существует краткий фрагмент кода на странице функции imagecreatefromgif() PHP вручную, что должно быть то, что вам нужно:

imagecreatefromgif comment #59787 by ZeBadger

+0

Странно, что я не нашел это в моем зеркале по умолчанию в руководстве, но танков много для ссылки. Я изменил функцию и дал как оригинальный плакат, так и ваш комментарий в комментарии. – Kris 2008-11-11 12:25:11

+0

Оптимизированная версия [здесь] (http://it1.php.net/manual/en/function.imagecreatefromgif.php#104473). – 2016-02-18 10:37:44

+1

По этой причине эта ссылка не работает, ее все еще можно найти здесь: http://php.net/manual/en/function.imagecreatefromgif.php # 104473 – robjbrain 2017-05-24 02:16:53

5

Вот рабочая функция:

/** 
* 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

Во время поиска решения по той же проблеме я заметил, что на сайте php.net есть продолжение кода, на который ссылаются Davide и Kris, но, по мнению автора, меньше памяти и, возможно, интенсивный.

Я воспроизведу его здесь, потому что это может представлять интерес.

источник: 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; 
} 
-1

анимированного GIF сусло имеет следующую строку

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

Чтение всего файла с file_get_contents может занять слишком много памяти, если данный файл слишком велик. Я повторно проанализировал ранее заданную функцию, которая считывает достаточно байтов для проверки фреймов и возвращает их, как только найдет не менее 2 кадров.

<?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

Это улучшение текущего голосового ответа, но у меня недостаточно репутации, чтобы комментировать его. Проблема с этим ответом заключается в том, что он читает файл в блоках 100Kb, а маркер конца кадра может быть разделен на 2 куска. Исправить это, чтобы добавить последние 20b предыдущего кадра к следующему:

<?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; 
} 
Смежные вопросы