Изменение размера анимированного GIF-файла без разрушения анимации

Мне нужно изменить размер анимированного файла GIF, не разрушая анимацию.

Как я могу сделать это с помощью PHP?


person riad    schedule 05.04.2009    source источник


Ответы (13)


если у вас есть доступ к imagemagick, вы можете сделать это:

system("convert big.gif -coalesce coalesce.gif");
system("convert -size 200x100 coalesce.gif -resize 200x10 small.gif");

это, скорее всего, возможно с плагином imagemagick, если у вас нет доступа к system()

ПРИМЕЧАНИЕ: это может создать больший размер файла, хотя изображение меньшего размера из-за объединения, существенно деоптимизирующего изображение.

ОБНОВЛЕНИЕ: если у вас нет доступа к ImageMagick, вы сможете использовать комбинацию следующих шагов для изменения размера анимированного gif (при условии, что у вас есть доступ к GD):

  1. Определите, является ли изображение анимированным gif: Могу ли я обнаружить анимированные gif используя php и gd? (верхний ответ)
  2. Разделите анимированный gif на отдельные кадры: http://www.phpclasses.org/package/3234-PHP-Split-GIF-animations-into-multiple-images.html
  3. Измените размер отдельных кадров: http://www.akemapa.com/2008/07/10/php-gd-resize-transparent-image-png-gif/
  4. Снова скомпонуйте кадры в анимированный gif: http://www.phpclasses.org/package/3163-PHP-Generate-GIF-animations-from-a-set-of-GIF-images.html

Это определенно намного интенсивнее, чем маршрут ImageMagick, но это должно быть технически возможно.

Если у вас получится, поделитесь с миром!

person Jeremy Stanley    schedule 05.04.2009
comment
извините, у меня нет доступа к imagemagic. Любое другое решение? - person riad; 05.04.2009
comment
Опубликовано обновление с рядом шагов с использованием GD и сторонних классов, чтобы это произошло (теоретически). - person Jeremy Stanley; 05.04.2009
comment
Я думаю, что получил теорию только о работе на практике: forssto.com/gifexample - person Tommi Forsström; 22.03.2011
comment
Большое спасибо @TommiForsström! - person hultberg; 04.05.2014
comment
Подход @JeremyStanley очень правильный. Полное руководство можно посмотреть здесь - person FONGOH MARTIN; 09.12.2016

Попробуйте GDEnhancer (используйте ImageCraft). Нужна только библиотека GD, и она сохраняет анимацию gif.

person nut    schedule 28.08.2013
comment
Спасибо. Можно ли его использовать с PHP 5.2? На сайте написано 5.4+, что является довольно передовым для большинства сред (включая мою целевую среду в этом случае). В остальном выглядит отлично! - person Rolf; 19.11.2013
comment
Увы, сайт GDEnhancer мертв. - person TechNyquist; 15.02.2017
comment
@TechNyquist теперь GDEnhacer устарел, вместо этого используйте github.com/coldume/imagecraft - person BredeBS; 23.02.2017

Вам нужно будет разложить гифку на кадры, миниатюру и собрать заново.

Взгляните на ImageMagick и этого руководства.

person cherouvim    schedule 05.04.2009

Я пробовал множество примеров изменения размера анимированных GIF-файлов с помощью PHP-модуля Imagick, но ни один из них не работал у меня. Затем, после некоторого времени отладки, наконец, я обнаружил настоящую проблему: анимация была потеряна при сохранении изображения на диск с помощью $animation->writeImage($file_dst); или $animation->writeImages($file_dst, true);.

Я изменил его на file_put_contents($file_dst, $animation->getImagesBlob());, и большинство примеров сразу заработало.

Надеюсь, это поможет кому-то.

person Antony Harder    schedule 13.03.2013
comment
Удивительный!! Это спасло мой день! Спасибо Энтони. Старые версии Imagick содержат ошибки при использовании writeImages, но использование вашего метода работает нормально и никаких проблем! :) - person FidoBoy; 19.11.2013
comment
это сработало, когда writeImages() удалил анимацию. - person ; 04.11.2014

Пример на http://www.php.net/manual/en/imagick.coalesceimages.php изменит размер вашего GIF, сохранив синхронизацию кадров. Что-то, чего не делает большинство других примеров.

Другие примеры перестраивают gif, а этот позволяет изменить кадры изображения.

person Matt Crossley    schedule 22.02.2012
comment
imagick лучше всего справляется со сложными манипуляциями с изображениями. PHP знает несколько трюков. - person transilvlad; 27.10.2012
comment
Это решение, которое я выбрал, наконец, я пробовал другие решения, но они были непозволительно медленными. Убедитесь, что на вашем хостинге есть Imagick (в наше время это не такая уж редкость), и используйте его. - person Rolf; 21.11.2013

Если у вас установлен ImageMagick, вы можете использовать один вызов convert:

system("convert big.gif -coalesce -repage 0x0 -resize 200x100 -layers Optimize small.gif");
person Alec Jacobson    schedule 20.04.2015

Я думаю, что у меня есть это в сумке.

Это решение ни в коем случае не является идеальным и содержит некоторую грубую силу здесь и там, но я смог добавить свой скрипт изменения размера изображения на основе GD / PHP с достаточной функциональностью для поддержки анимации.

Решение в значительной степени основано на превосходных бесплатных библиотеках Ласло Зсиди — http://www.phpclasses.org/browse/author/283569.html

Вы можете просмотреть краткую демонстрацию и загрузить исходные коды с http://forssto.com/gifexample/ (прямое ссылка: http://forssto.com/gifexample/gifanimresize.zip)

ИЗВЕСТНЫЕ ПРОБЛЕМЫ:

  • Поддержка прозрачности — это было бы легко добавить к этому решению, но поскольку у меня нет непосредственной необходимости в этом, я останавливаюсь на этом.

  • Частота кадров — по какой-то неизвестной причине класс GifEncoder не учитывает указанную частоту кадров. Мне нужно будет изучить это позже.

  • Я нашел один gif-файл из своего набора тестов, в котором каким-то образом были кадры разного размера, и эта анимация не работала правильно. Тогда еще немного отладки.

person Tommi Forsström    schedule 22.03.2011
comment
Привет. Спасибо. Я попробовал ваше решение. Я модифицировал исходники для чтения изображения из строки (дайте мне знать, если вам интересно), но оказалось, что это ОЧЕНЬ медленно. Я наконец понял, что Imagick доступен на хостинге, и вместо этого использовал его. - person Rolf; 21.11.2013

просто создайте 3 имени папки 1.frame_output 2.images 3.resized_frame_output и загрузите 2 класса кодировщика и декодера по этой ссылке ниже 1. Загрузите класс «GIFDecoder.class.php» из http://phpclasses.elib.com/browse/package/3234.html 2. Загрузите класс "GIFEncoder.class.php" из http://phpclasses.betablue.net/browse/package/3163.html

а затем запустите имя сценария как «resize_animator.php», создайте загружаемый html-файл и дайте насладиться сценарием.

..сохраните этот скрипт как .....index.php.......

<html>
<body>
<table width="500" border="0" align="center" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<form action="resize_animator.php" method="post" enctype="multipart/form-data" >
<td>
<table width="100%" border="0" cellpadding="3" cellspacing="1" bgcolor="#FFFFFF">
<tr>
<td align="center"><font face="Tahoma">SELECT ANIMATED FILE</font> 
<input type="file" name="uploadfile" size="20" accept="image/gif"/>
</td>
</tr>
<tr>
<td align="center"><input type="submit" name="Submit" value="PROCESS ANIMATION" /></td>
</tr>
</table>
</td>
</form>
</tr>
</table>
</body>
</html>

................................сохраните и этот скрипт как resize_animator.php............

   <?php

   require "GIFDecoder.class.php";
   include "GIFEncoder.class.php";
   $file_name= $_FILES['uploadfile']['name'];
   $file_ext = substr($file_name, -4);
   $file_size=($_FILES["uploadfile"]["size"] /1024 );
   if($file_ext=='.gif')
    {
 if($file_size > 0 && $file_size < 2000 )
  {
    session_start ( );
        $uploaded_file = $_FILES['uploadfile']['tmp_name'];
        $fp=file_get_contents($uploaded_file);

        if ( $fp )
            {
                $_SESSION['delays'] = Array ( );
                $gif = new GIFDecoder ( $fp );
                $arr = $gif->GIFGetFrames ( );
                $_SESSION [ 'delays' ] = $gif -> GIFGetDelays ( );

                for ( $i = 0; $i < count ( $arr ); $i++ )
                {
                        fwrite ( fopen ( ( $i < 10 ? "frame_output/$i$i_frame.gif" : "frame_output/$i_frame.gif" ), "wb" ), $arr [ $i ] );
                }
          }

        function resize_frames($newwidth,$newheight)
            {
                    $dir=opendir("frame_output/");
                    $i=0;
                    while($imgfile=readdir($dir))
                    {
                         if ($imgfile != "." && $imgfile!="..")
                             {
                                        $imgarray[$i]=$imgfile;
                                        $uploadedfile = "frame_output/".$imgarray[$i];
                                        $src = imagecreatefromgif($uploadedfile);
                                        list($width,$height)=getimagesize($uploadedfile);
                                        $tmp=imagecreatetruecolor($newwidth,$newheight);
                                        imagecopyresampled($tmp,$src,0,0,0,0,$newwidth,$newheight,$width,$height);
                                        $filename = "resized_frame_output/".$imgarray[$i];
                                        imagegif($tmp,$filename,100);
                                        imagedestroy($src);
                                        imagedestroy($tmp);
                                        $i++;
                            }
                    }
                    closedir($dir);

                if ( $dh = opendir ( "resized_frame_output/" ) )
                {
                    while ( false !== ( $dat = readdir ( $dh ) ) )
                    {
                        if ( $dat != "." && $dat != ".." )
                        {
                            $frames [ ] = "resized_frame_output/$dat";
                        }
                    }
                    closedir ( $dh );
                }

            $gif = new GIFEncoder   ( $frames,$_SESSION [ 'delays' ],0, 2, 0, 0, 0,"url" );
            $data = $gif->GetAnimation ( );

            $x='x';
            $y='_';
            $uploaded_file_name= $_FILES['uploadfile']['name'];
            $actual_file_name = substr($uploaded_file_name, 0, -4);
            $file_extention = substr($uploaded_file_name, -4);
            $new_name=$actual_file_name.$y.$newwidth.$x.$newheight.$file_extention ;

            //$output_image_name=$newwidth.$x.$newheight;
            fwrite ( fopen ( "images/$new_name", "wb" ), $data );
            //remove resized frames from folder
            //sleep for 1 second
            // usleep(2000000);
            $dir = 'resized_frame_output/';
            foreach(glob($dir.'*.*') as $v)
                {
                 unlink($v);
                }
        }  // end of function resize_frames


            $gif = new GIFEncoder   ( $frames,$_SESSION [ 'delays' ],0, 2, 0, 0, 0,"url" );
            $data = $gif->GetAnimation ( );

            $x='x';
            $y='_';
            $z='_p';
            $uploaded_file_name= $_FILES['uploadfile']['name'];
            $actual_file_name = substr($uploaded_file_name, 0, -4);
            $file_extention = substr($uploaded_file_name, -4);
            $new_name=$actual_file_name.$y.$newwidth.$x.$newheight.$z.$file_extention ;

            //$output_image_name=$newwidth.$x.$newheight;
            fwrite ( fopen ( "images/$new_name", "wb" ), $data );
            //remove resized frames from folder
            //sleep for 1 second
             //usleep(2000000);
            $dir = 'resized_frame_output/';
            foreach(glob($dir.'*.*') as $v)
                {
                 unlink($v);
                }
        }  // end of function resize_frames

            resize_frames(110,110);
            resize_frames(120,160);
            resize_frames(120,80);
            resize_frames(128,96);
            resize_frames(128,128);
            resize_frames(208,208);
            resize_frames(208,320);

            session_destroy();

            //usleep(200000);

            //remove resized frames from folder
            $dir = 'frame_output/';
            foreach(glob($dir.'*.*') as $v)
                {
                 unlink($v);
                }
      echo "<center><h1>Your Animation processing is compleated.</h1></center>";
      echo "<center><h2><a href=\"index.php\">BACK TO UPLOAD PAGE</h2></center>";
  }  //end of file size checker
else
 {
      echo "<center><h2>You Upload a unfit size image .Upload a file within 2000 KB</h2></center>";
      echo "<center><h2><a href=\"index.php\">BACK TO UPLOAD PAGE</h2></center>";
 }
   } //end of file extention checker
  else
  {
   echo "<center><h2>Uplaod a gif file!</h2></center>";
   echo "<center><h2><a href=\"index.php\">BACK TO UPLOAD PAGE</h2></center>";
  }
  ?>

.......................ДАВАЙ НАСЛАДИМСЯ............

раскомментируйте функцию usleep, чтобы увидеть, как происходит работа с этими папками. Это не обязательно, но я использую ее, чтобы увидеть функциональность.

person riad    schedule 07.04.2009

Если на вашем сервере нет Imagemagick, вы можете попробовать это:

http://www.phpclasses.org/package/7353-PHP-Resize-animations-in-files-of-the-GIF-format.html

Класс изменяет размер анимации GIF с помощью GD. Сначала анализирует кадры, затем изменяет их размеры, после чего снова компилирует их в один файл без потери времени задержки, методов утилизации, таблиц цветов и т. д.

Попробуйте, и если вы найдете ошибку или захотите предложить некоторые оптимизации и т. д., вы можете использовать форум класса или оставить комментарий на странице на моем веб-сайте. И я отвечу на это как можно скорее.

person Taha Paksu    schedule 11.03.2012

Все эти ответы, кроме как через ImageMagick, у меня не сработали. Сценарии в ответах до этого полны ошибок.

Даже с установкой ImageMagick было сложно справиться, так что вот мой опыт.

Вот как установить ImageMagick на Windows 7 и xampp 1.7.4.
Примечание. Выберите 64-битную версию (для win7), а при установке оставьте отмеченной опцию "Добавить в системный путь".

А затем следуйте: http://www.creativearmory.com/tutorials/resize-animated-gifs-with-php-and-imagemagick

Я потратил часы на скрипты в этом посте, а ImageMagick и этот туториал были успешно завершены за считанные минуты.

И еще одно замечание: на моем веб-сервере по умолчанию установлен ImageMagick, поэтому я думаю, что он есть и на большинстве серверов.

person Sturko    schedule 23.09.2011

Изменение размера GIF-анимации — это простой одноклассовый инструмент, который сделает свое дело.

Примечание. Для записи отдельных кадров используется временная папка. Несмотря на то, что кадры помечаются временными метками, вам может потребоваться создать уникальную папку, если вы собираетесь использовать ее на сервере, где несколько пользователей будут одновременно изменять размер GIF-файлов.

person David Harkness    schedule 27.02.2015

Imagecraft — это надежная библиотека PHP GD и расширение, которое поддерживает анимацию GIF, редактирует и компонует изображения в нескольких слоях и поддерживает водяной знак.

person Syed Waqas Bukhary    schedule 20.01.2017

Я использовал эту функцию:

function gifResize($file_origin,$file_dest,$percent){       
   $crop_w = 0;
   $crop_h = 0;
   $crop_x = 0;
   $crop_y = 0;
   $image = new Imagick($file_origin);
   $originalWidth = $image->getImageWidth();
   $originalHeight = $image->getImageHeight();
   $size_w = ($originalWidth*$percent)/100;
   $size_h = ($originalHeight*$percent)/100;
   if(($size_w-$originalWidth)>($size_h-$originalHeight)){
       $s = $size_h/$originalHeight;
       $size_w = round($originalWidth*$s);
       $size_h = round($originalHeight*$s);
   }else{
       $s = $size_w/$originalWidth;
       $size_w = round($originalWidth*$s);
       $size_h = round($originalHeight*$s);
   }       
   $image = $image->coalesceImages();

   foreach ($image as $frame) {
       $frame->cropImage($crop_w, $crop_h, $crop_x, $crop_y);
       $frame->thumbnailImage($size_h, $size_w);
       $frame->setImagePage($size_h, $size_w, 0, 0);
   }
   $imageContent = $image->getImagesBlob();
   $fp = fopen($file_dest,'w');
   fwrite($fp,$imageContent);
   fclose($fp);

}

person Fernando RIS    schedule 09.05.2017