可以调整gif动画图片尺寸的很实用的php类

类的使用demo:

<?php 
//http://www.cnblogs.com/roucheng/
require_once "roucheng.php";  
$gr = new gifresizer; 
$gr->temp_dir = "keleyi"; 
$gr->resize("keleyi.gif","keleyi_resized.gif",500,500); 
?>

类的源代码,保存为roucheng.php文件:

  1 <? 
  2     /** 
  3     * 
  4     * Resizes Animated GIF Files
  5     *
  6     *   ///IMPORTANT NOTE: The script needs a temporary directory where all the frames should be extracted. 
  7     *   Create a directory with a 777 permission level and write the path into $temp_dir variable below. 
  8     *   
  9     *   Default directory is "frames".
 10     */
 11  
 12     class gifresizer {
 13  
 14         public $temp_dir = "frames";
 15         private $pointer = 0;
 16         private $index = 0;
 17         private $globaldata = array();
 18         private $imagedata = array();
 19         private $imageinfo = array();
 20         private $handle = 0;
 21         private $orgvars = array();
 22         private $encdata = array();
 23         private $parsedfiles = array();
 24         private $originalwidth = 0;
 25         private $originalheight = 0;
 26         private $wr,$hr;
 27         private $props = array();
 28         private $decoding = false;
 29  
 30         /** 
 31         * Public part of the class
 32         * 
 33         * @orgfile - Original file path
 34         * @newfile - New filename with path
 35         * @width   - Desired image width 
 36         * @height  - Desired image height
 37         */
 38         function resize($orgfile,$newfile,$width,$height){
 39             $this->decode($orgfile);
 40             $this->wr=$width/$this->originalwidth;
 41             $this->hr=$height/$this->originalheight;
 42             $this->resizeframes();
 43             $this->encode($newfile,$width,$height);
 44             $this->clearframes();
 45         }   
 46  
 47         /** 
 48         * GIF Decoder function.
 49         * Parses the GIF animation into single frames.
 50         */
 51         private function decode($filename){
 52             $this->decoding = true;            
 53             $this->clearvariables();
 54             $this->loadfile($filename);
 55             $this->get_gif_header();
 56             $this->get_graphics_extension(0);
 57             $this->get_application_data();
 58             $this->get_application_data();
 59             $this->get_image_block(0);
 60             $this->get_graphics_extension(1);
 61             $this->get_comment_data();
 62             $this->get_application_data();
 63             $this->get_image_block(1);
 64             while(!$this->checkbyte(0x3b) && !$this->checkEOF()){
 65                 $this->get_comment_data(1);
 66                 $this->get_graphics_extension(2);
 67                 $this->get_image_block(2);
 68             }
 69             $this->writeframes(time());      
 70             $this->closefile();
 71             $this->decoding = false;
 72         }
 73  
 74         /** 
 75         * GIF Encoder function.
 76         * Combines the parsed GIF frames into one single animation.
 77         */
 78         private function encode($new_filename,$newwidth,$newheight){
 79             $mystring = "";
 80             $this->pointer = 0;
 81             $this->imagedata = array();
 82             $this->imageinfo = array();
 83             $this->handle = 0;
 84             $this->index=0;
 85  
 86             $k=0;
 87             foreach($this->parsedfiles as $imagepart){
 88                 $this->loadfile($imagepart);
 89                 $this->get_gif_header();
 90                 $this->get_application_data();
 91                 $this->get_comment_data();
 92                 $this->get_graphics_extension(0);
 93                 $this->get_image_block(0);
 94  
 95                 //get transparent color index and color
 96                 if(isset($this->encdata[$this->index-1]))
 97                     $gxdata = $this->encdata[$this->index-1]["graphicsextension"];
 98                 else
 99                     $gxdata = null;
100                 $ghdata = $this->imageinfo["gifheader"];
101                 $trcolor = "";
102                 $hastransparency=($gxdata[3]&&1==1);
103  
104                 if($hastransparency){
105                     $trcx = ord($gxdata[6]);
106                     $trcolor = substr($ghdata,13+$trcx*3,3);
107                 }
108  
109                 //global color table to image data;
110                 $this->transfercolortable($this->imageinfo["gifheader"],$this->imagedata[$this->index-1]["imagedata"]); 
111  
112                 $imageblock = &$this->imagedata[$this->index-1]["imagedata"];
113  
114                 //if transparency exists transfer transparency index
115                 if($hastransparency){
116                     $haslocalcolortable = ((ord($imageblock[9])&128)==128);
117                     if($haslocalcolortable){
118                         //local table exists. determine boundaries and look for it.
119                         $tablesize=(pow(2,(ord($imageblock[9])&7)+1)*3)+10;
120                         $this->orgvars[$this->index-1]["transparent_color_index"] = 
121                         ((strrpos(substr($this->imagedata[$this->index-1]["imagedata"],0,$tablesize),$trcolor)-10)/3);        
122                     }else{
123                         //local table doesnt exist, look at the global one.
124                         $tablesize=(pow(2,(ord($gxdata[10])&7)+1)*3)+10;
125                         $this->orgvars[$this->index-1]["transparent_color_index"] = 
126                         ((strrpos(substr($ghdata,0,$tablesize),$trcolor)-10)/3);    
127                     }               
128                 }
129  
130                 //apply original delay time,transparent index and disposal values to graphics extension
131  
132                 if(!$this->imagedata[$this->index-1]["graphicsextension"]) $this->imagedata[$this->index-1]["graphicsextension"] = chr(0x21).chr(0xf9).chr(0x04).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00);
133  
134                 $imagedata = &$this->imagedata[$this->index-1]["graphicsextension"];
135  
136                 $imagedata[3] = chr((ord($imagedata[3]) & 0xE3) | ($this->orgvars[$this->index-1]["disposal_method"] << 2));
137                 $imagedata[4] = chr(($this->orgvars[$this->index-1]["delay_time"] % 256));
138                 $imagedata[5] = chr(floor($this->orgvars[$this->index-1]["delay_time"] / 256));
139                 if($hastransparency){
140                     $imagedata[6] = chr($this->orgvars[$this->index-1]["transparent_color_index"]);
141                 }
142                 $imagedata[3] = chr(ord($imagedata[3])|$hastransparency);
143  
144                 //apply calculated left and top offset 
145                 $imageblock[1] = chr(round(($this->orgvars[$this->index-1]["offset_left"]*$this->wr) % 256));
146                 $imageblock[2] = chr(floor(($this->orgvars[$this->index-1]["offset_left"]*$this->wr) / 256));
147                 $imageblock[3] = chr(round(($this->orgvars[$this->index-1]["offset_top"]*$this->hr) % 256));
148                 $imageblock[4] = chr(floor(($this->orgvars[$this->index-1]["offset_top"]*$this->hr) / 256));           
149  
150                 if($this->index==1){
151                     if(!isset($this->imageinfo["applicationdata"]) || !$this->imageinfo["applicationdata"]) 
152                         $this->imageinfo["applicationdata"]=chr(0x21).chr(0xff).chr(0x0b)."NETSCAPE2.0".chr(0x03).chr(0x01).chr(0x00).chr(0x00).chr(0x00);
153                     if(!isset($this->imageinfo["commentdata"]) || !$this->imageinfo["commentdata"])
154                         $this->imageinfo["commentdata"] = chr(0x21).chr(0xfe).chr(0x10)."PHPGIFRESIZER1.0".chr(0);
155                     $mystring .= $this->orgvars["gifheader"]. $this->imageinfo["applicationdata"].$this->imageinfo["commentdata"];
156                     if(isset($this->orgvars["hasgx_type_0"]) && $this->orgvars["hasgx_type_0"]) $mystring .= $this->globaldata["graphicsextension_0"];
157                     if(isset($this->orgvars["hasgx_type_1"]) && $this->orgvars["hasgx_type_1"]) $mystring .= $this->globaldata["graphicsextension"];
158                 }
159  
160                 $mystring .= $imagedata . $imageblock;
161                 $k++;
162                 $this->closefile();
163             }
164  
165             $mystring .= chr(0x3b); 
166  
167             //applying new width & height to gif header
168             $mystring[6] = chr($newwidth % 256);
169             $mystring[7] = chr(floor($newwidth / 256));
170             $mystring[8] = chr($newheight % 256);
171             $mystring[9] = chr(floor($newheight / 256));
172             $mystring[11]= $this->orgvars["background_color"];
173             //if(file_exists($new_filename)){unlink($new_filename);}
174             file_put_contents($new_filename,$mystring);
175         }
176  
177         /** 
178         * Variable Reset function
179         * If a instance is used multiple times, it's needed. Trust me.
180         */
181         private function clearvariables(){
182             $this->pointer = 0;
183             $this->index = 0;
184             $this->imagedata = array();
185             $this->imageinfo = array();            
186             $this->handle = 0;
187             $this->parsedfiles = array();
188         }
189  
190         /** 
191         * Clear Frames function
192         * For deleting the frames after encoding.
193         */
194         private function clearframes(){
195             foreach($this->parsedfiles as $temp_frame){
196                 unlink($temp_frame);
197             }
198         }
199  
200         /** 
201         * Frame Writer
202         * Writes the GIF frames into files.
203         */
204         private function writeframes($prepend){
205             for($i=0;$i<sizeof($this->imagedata);$i++){
206                 file_put_contents($this->temp_dir."/frame_".$prepend."_".str_pad($i,2,"0",STR_PAD_LEFT).".gif",$this->imageinfo["gifheader"].$this->imagedata[$i]["graphicsextension"].$this->imagedata[$i]["imagedata"].chr(0x3b));
207                 $this->parsedfiles[]=$this->temp_dir."/frame_".$prepend."_".str_pad($i,2,"0",STR_PAD_LEFT).".gif";
208             }
209         }
210  
211         /** 
212         * Color Palette Transfer Device
213         * Transferring Global Color Table (GCT) from frames into Local Color Tables in animation.
214         */
215         private function transfercolortable($src,&$dst){
216             //src is gif header,dst is image data block
217             //if global color table exists,transfer it
218             if((ord($src[10])&128)==128){
219                 //Gif Header Global Color Table Length
220                 $ghctl = pow(2,$this->readbits(ord($src[10]),5,3)+1)*3;
221                 //cut global color table from gif header
222                 $ghgct = substr($src,13,$ghctl);
223                 //check image block color table length
224                 if((ord($dst[9])&128)==128){
225                     //Image data contains color table. skip.
226                 }else{
227                     //Image data needs a color table.
228                     //get last color table length so we can truncate the dummy color table
229                     $idctl = pow(2,$this->readbits(ord($dst[9]),5,3)+1)*3;
230                     //set color table flag and length   
231                     $dst[9] = chr(ord($dst[9]) | (0x80 | (log($ghctl/3,2)-1)));
232                     //inject color table
233                     $dst = substr($dst,0,10).$ghgct.substr($dst,-1*strlen($dst)+10);
234                 }
235             }else{
236                 //global color table doesn't exist. skip.
237             }
238         }
239  
240         /** 
241         * GIF Parser Functions.
242         * Below functions are the main structure parser components.
243         */
244         private function get_gif_header(){
245             $this->p_forward(10);
246             if($this->readbits(($mybyte=$this->readbyte_int()),0,1)==1){
247                 $this->p_forward(2);
248                 $this->p_forward(pow(2,$this->readbits($mybyte,5,3)+1)*3);
249             }else{
250                 $this->p_forward(2);
251             }
252  
253             $this->imageinfo["gifheader"]=$this->datapart(0,$this->pointer);
254             if($this->decoding){
255                 $this->orgvars["gifheader"]=$this->imageinfo["gifheader"];
256                 $this->originalwidth = ord($this->orgvars["gifheader"][7])*256+ord($this->orgvars["gifheader"][6]);
257                 $this->originalheight = ord($this->orgvars["gifheader"][9])*256+ord($this->orgvars["gifheader"][8]);
258                 $this->orgvars["background_color"]=$this->orgvars["gifheader"][11];
259             }
260  
261         }
262         //-------------------------------------------------------
263         private function get_application_data(){
264             $startdata = $this->readbyte(2);
265             if($startdata==chr(0x21).chr(0xff)){
266                 $start = $this->pointer - 2;
267                 $this->p_forward($this->readbyte_int());
268                 $this->read_data_stream($this->readbyte_int());
269                 $this->imageinfo["applicationdata"] = $this->datapart($start,$this->pointer-$start);
270             }else{
271                 $this->p_rewind(2);
272             }
273         }
274         //-------------------------------------------------------
275         private function get_comment_data(){
276             $startdata = $this->readbyte(2);
277             if($startdata==chr(0x21).chr(0xfe)){
278                 $start = $this->pointer - 2;
279                 $this->read_data_stream($this->readbyte_int());
280                 $this->imageinfo["commentdata"] = $this->datapart($start,$this->pointer-$start);
281             }else{
282                 $this->p_rewind(2);
283             }
284         }
285         //-------------------------------------------------------
286         private function get_graphics_extension($type){
287             $startdata = $this->readbyte(2);
288             if($startdata==chr(0x21).chr(0xf9)){
289                 $start = $this->pointer - 2;
290                 $this->p_forward($this->readbyte_int());
291                 $this->p_forward(1);
292                 if($type==2){
293                     $this->imagedata[$this->index]["graphicsextension"] = $this->datapart($start,$this->pointer-$start);
294                 }else if($type==1){
295                     $this->orgvars["hasgx_type_1"] = 1;
296                     $this->globaldata["graphicsextension"] = $this->datapart($start,$this->pointer-$start);
297                 }else if($type==0 && $this->decoding==false){
298                     $this->encdata[$this->index]["graphicsextension"] = $this->datapart($start,$this->pointer-$start);
299                 }else if($type==0 && $this->decoding==true){
300                     $this->orgvars["hasgx_type_0"] = 1;
301                     $this->globaldata["graphicsextension_0"] = $this->datapart($start,$this->pointer-$start);
302                 }
303             }else{
304                 $this->p_rewind(2);
305             }
306         }
307         //-------------------------------------------------------
308         private function get_image_block($type){
309             if($this->checkbyte(0x2c)){
310                 $start = $this->pointer;
311                 $this->p_forward(9);
312                 if($this->readbits(($mybyte=$this->readbyte_int()),0,1)==1){
313                     $this->p_forward(pow(2,$this->readbits($mybyte,5,3)+1)*3);
314                 }
315                 $this->p_forward(1);
316                 $this->read_data_stream($this->readbyte_int());
317                 $this->imagedata[$this->index]["imagedata"] = $this->datapart($start,$this->pointer-$start);
318  
319                 if($type==0){
320                     $this->orgvars["hasgx_type_0"] = 0;
321                     if(isset($this->globaldata["graphicsextension_0"]))
322                         $this->imagedata[$this->index]["graphicsextension"]=$this->globaldata["graphicsextension_0"];
323                     else
324                         $this->imagedata[$this->index]["graphicsextension"]=null;
325                     unset($this->globaldata["graphicsextension_0"]);
326                 }elseif($type==1){
327                     if(isset($this->orgvars["hasgx_type_1"]) && $this->orgvars["hasgx_type_1"]==1){
328                         $this->orgvars["hasgx_type_1"] = 0;
329                         $this->imagedata[$this->index]["graphicsextension"]=$this->globaldata["graphicsextension"];
330                         unset($this->globaldata["graphicsextension"]);
331                     }else{
332                         $this->orgvars["hasgx_type_0"] = 0;
333                         $this->imagedata[$this->index]["graphicsextension"]=$this->globaldata["graphicsextension_0"];
334                         unset($this->globaldata["graphicsextension_0"]);
335                     }
336                 }
337  
338                 $this->parse_image_data();
339                 $this->index++;
340  
341             }
342         }
343         //-------------------------------------------------------
344         private function parse_image_data(){
345             $this->imagedata[$this->index]["disposal_method"] = $this->get_imagedata_bit("ext",3,3,3);
346             $this->imagedata[$this->index]["user_input_flag"] = $this->get_imagedata_bit("ext",3,6,1);
347             $this->imagedata[$this->index]["transparent_color_flag"] = $this->get_imagedata_bit("ext",3,7,1);
348             $this->imagedata[$this->index]["delay_time"] = $this->dualbyteval($this->get_imagedata_byte("ext",4,2));
349             $this->imagedata[$this->index]["transparent_color_index"] = ord($this->get_imagedata_byte("ext",6,1));
350             $this->imagedata[$this->index]["offset_left"] = $this->dualbyteval($this->get_imagedata_byte("dat",1,2));
351             $this->imagedata[$this->index]["offset_top"] = $this->dualbyteval($this->get_imagedata_byte("dat",3,2));
352             $this->imagedata[$this->index]["width"] = $this->dualbyteval($this->get_imagedata_byte("dat",5,2));
353             $this->imagedata[$this->index]["height"] = $this->dualbyteval($this->get_imagedata_byte("dat",7,2));
354             $this->imagedata[$this->index]["local_color_table_flag"] = $this->get_imagedata_bit("dat",9,0,1);
355             $this->imagedata[$this->index]["interlace_flag"] = $this->get_imagedata_bit("dat",9,1,1);
356             $this->imagedata[$this->index]["sort_flag"] = $this->get_imagedata_bit("dat",9,2,1);
357             $this->imagedata[$this->index]["color_table_size"] = pow(2,$this->get_imagedata_bit("dat",9,5,3)+1)*3;
358             $this->imagedata[$this->index]["color_table"] = substr($this->imagedata[$this->index]["imagedata"],10,$this->imagedata[$this->index]["color_table_size"]);
359             $this->imagedata[$this->index]["lzw_code_size"] = ord($this->get_imagedata_byte("dat",10,1));
360             if($this->decoding){
361                 $this->orgvars[$this->index]["transparent_color_flag"] = $this->imagedata[$this->index]["transparent_color_flag"];
362                 $this->orgvars[$this->index]["transparent_color_index"] = $this->imagedata[$this->index]["transparent_color_index"];
363                 $this->orgvars[$this->index]["delay_time"] = $this->imagedata[$this->index]["delay_time"];
364                 $this->orgvars[$this->index]["disposal_method"] = $this->imagedata[$this->index]["disposal_method"];
365                 $this->orgvars[$this->index]["offset_left"] = $this->imagedata[$this->index]["offset_left"];
366                 $this->orgvars[$this->index]["offset_top"] = $this->imagedata[$this->index]["offset_top"];
367             }
368         }
369         //-------------------------------------------------------
370         private function get_imagedata_byte($type,$start,$length){
371             if($type=="ext")
372                 return substr($this->imagedata[$this->index]["graphicsextension"],$start,$length);
373             elseif($type=="dat")
374                 return substr($this->imagedata[$this->index]["imagedata"],$start,$length);
375         }
376         //-------------------------------------------------------
377         private function get_imagedata_bit($type,$byteindex,$bitstart,$bitlength){
378             if($type=="ext")
379                 return $this->readbits(ord(substr($this->imagedata[$this->index]["graphicsextension"],$byteindex,1)),$bitstart,$bitlength);
380             elseif($type=="dat")
381                 return $this->readbits(ord(substr($this->imagedata[$this->index]["imagedata"],$byteindex,1)),$bitstart,$bitlength);
382         }
383         //-------------------------------------------------------
384         private function dualbyteval($s){
385             $i = ord($s[1])*256 + ord($s[0]);
386             return $i;
387         }
388         //------------   Helper Functions ---------------------
389         private function read_data_stream($first_length){
390             $this->p_forward($first_length);
391             $length=$this->readbyte_int();
392             if($length!=0) {
393                 while($length!=0){
394                     $this->p_forward($length);
395                     $length=$this->readbyte_int();
396                 }
397             }
398             return true;
399         }
400         //-------------------------------------------------------
401         private function loadfile($filename){
402             $this->handle = fopen($filename,"rb");
403             $this->pointer = 0;
404         }
405         //-------------------------------------------------------
406         private function closefile(){
407             fclose($this->handle);
408             $this->handle=0;
409         }
410         //-------------------------------------------------------
411         private function readbyte($byte_count){
412             $data = fread($this->handle,$byte_count);
413             $this->pointer += $byte_count;
414             return $data;
415         }
416         //-------------------------------------------------------
417         private function readbyte_int(){
418             $data = fread($this->handle,1);
419             $this->pointer++;
420             return ord($data);
421         }
422         //-------------------------------------------------------
423         private function readbits($byte,$start,$length){
424             $bin = str_pad(decbin($byte),8,"0",STR_PAD_LEFT);
425             $data = substr($bin,$start,$length);
426             return bindec($data);
427         }
428         //-------------------------------------------------------
429         private function p_rewind($length){
430             $this->pointer-=$length;
431             fseek($this->handle,$this->pointer);
432         }
433         //-------------------------------------------------------
434         private function p_forward($length){
435             $this->pointer+=$length;
436             fseek($this->handle,$this->pointer);
437         }
438         //-------------------------------------------------------
439         private function datapart($start,$length){
440             fseek($this->handle,$start);
441             $data = fread($this->handle,$length);
442             fseek($this->handle,$this->pointer);
443             return $data;
444         }
445         //-------------------------------------------------------
446         private function checkbyte($byte){
447             if(fgetc($this->handle)==chr($byte)){
448                 fseek($this->handle,$this->pointer);
449                 return true;
450             }else{
451                 fseek($this->handle,$this->pointer);
452                 return false;
453             }
454         }   
455         //-------------------------------------------------------
456         private function checkEOF(){
457             if(fgetc($this->handle)===false){
458                 return true;
459             }else{
460                 fseek($this->handle,$this->pointer);
461                 return false;
462             }
463         }   
464         //-------------------------------------------------------
465         /** 
466         * Debug Functions.  keleyi.com
467         * Parses the GIF animation into single frames.
468         */
469         private function debug($string){
470             echo "<pre>";
471             for($i=0;$i<strlen($string);$i++){
472                 echo str_pad(dechex(ord($string[$i])),2,"0",STR_PAD_LEFT). " ";
473             }
474             echo "</pre>";
475         }
476         //-------------------------------------------------------
477         private function debuglen($var,$len){
478             echo "<pre>";
479             for($i=0;$i<$len;$i++){
480                 echo str_pad(dechex(ord($var[$i])),2,"0",STR_PAD_LEFT). " ";
481             }
482             echo "</pre>";
483         }   
484         //-------------------------------------------------------
485         private function debugstream($length){
486             $this->debug($this->datapart($this->pointer,$length));
487         }
488         //-------------------------------------------------------
489         /** 
490         * GD Resizer Device
491         * Resizes the animation frames
492         */
493         private function resizeframes(){
494             $k=0;
495             foreach($this->parsedfiles as $img){
496                 $src = imagecreatefromgif($img);
497                 $sw = $this->imagedata[$k]["width"];
498                 $sh = $this->imagedata[$k]["height"];
499                 $nw = round($sw * $this->wr);
500                 $nh = round($sh * $this->hr);
501                 $sprite = imagecreatetruecolor($nw,$nh);    
502                 $trans = imagecolortransparent($sprite);
503                 imagealphablending($sprite, false);
504                 imagesavealpha($sprite, true);
505                 imagepalettecopy($sprite,$src);                 
506                 imagefill($sprite,0,0,imagecolortransparent($src));
507                 imagecolortransparent($sprite,imagecolortransparent($src));                     
508                 imagecopyresized($sprite,$src,0,0,0,0,$nw,$nh,$sw,$sh);     
509                 imagegif($sprite,$img);
510                 imagedestroy($sprite);
511                 imagedestroy($src);
512                 $k++;
513             }
514         }
515     }
516  
517  
518 ?>
原文地址:https://www.cnblogs.com/roucheng/p/3459271.html