欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

一个很实用的类,php调整gif图片的尺寸!

程序员文章站 2022-05-21 11:02:24
...
这个类可以对GIF格式的动态文件进行调整。提取动态图片帧文件到一个临时目录中。调整图像的大小并提取和重建成动画的GIF格式的新文件。

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