gif_reader.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. <?php
  2. class GIFReader {
  3. //时间: 2009-03-21
  4. //author: lael
  5. //http://www.gzyd.net
  6. //http://hi.baidu.com/lael80
  7. var $BUF = "";
  8. var $IMGS = array();
  9. function GIFReader(){
  10. //
  11. }
  12. /*
  13. $mod = url / bin
  14. */
  15. function load($src, $mod = "url"){
  16. if($mod == "url"){
  17. $this->BUF = file_get_contents($src);
  18. }else{
  19. $this->BUF = $src;
  20. }
  21. $this->IMGS = array("info" => array(), "frames" => array());
  22. $this->IMGS["info"]["Loops"] = -1;
  23. $this->IMGS["info"]["UsesBkBuffer"] = false;
  24. $this->IMGS["info"]["Version"] = substr($this->BUF, 0, 6);
  25. $this->IMGS["info"]["HdrOffset"] = 0;
  26. $this->IMGS["info"]["Width"] = ord(substr($this->BUF, 6, 2));
  27. $this->IMGS["info"]["Height"] = ord(substr($this->BUF, 8, 2));
  28. $gByte = ord($this->BUF{10});
  29. $this->IMGS["info"]["gTableUsed"] = $this->DoBitwise($gByte, 0x80);
  30. $this->IMGS["info"]["gTableCount"] = $this->DoBitwise($gByte, 0x07);
  31. if($this->IMGS["info"]["gTableUsed"]){
  32. $this->IMGS["info"]["BkgColor"] = ord($this->BUF{11});
  33. $this->ColorFromTable(0xE, $this->IMGS["info"]["BkgColor"], $this->IMGS["info"]["gTableCount"]);
  34. if($this->IMGS["info"]["BkgColor"] < 0)$this->IMGS["info"]["BkgColor"] = 0;
  35. $seek = 0xE + 3 * (2 << $this->IMGS["info"]["gTableCount"]) - 1;
  36. }else{
  37. $seek = 13;
  38. $this->IMGS["info"]["BkgColor"] = 0;
  39. $this->IMGS["info"]["gTableCount"] = 0;
  40. }
  41. $fColor = - 1;
  42. $tmp = array();
  43. while(true){
  44. switch (ord($this->BUF{$seek})){
  45. case 0:
  46. $seek ++;
  47. break;
  48. case 33:
  49. $seek ++;
  50. switch (ord($this->BUF{$seek})){
  51. case 255:
  52. $seek ++;
  53. if(count($this->IMGS["frames"]) == 0){
  54. $gByte = ord($this->BUF{$seek});
  55. $seek ++;
  56. $gifString = strtoupper(substr($this->BUF, $seek, 8));
  57. $seek += 8;
  58. if($gifString == "NETSCAPE"){
  59. $seek += 3;
  60. $gByte = ord($this->BUF{$seek});
  61. $seek ++;
  62. if($gByte == 3){
  63. $seek ++;
  64. $this->IMGS["info"]["Loops"] = ord(substr($this->BUF, $seek, 2));
  65. $seek += 2;
  66. if($this->IMGS["info"]["Loops"] < 1)$this->IMGS["info"]["Loops"] = 0;
  67. }else{
  68. //
  69. }
  70. }else{
  71. $seek += 3;
  72. }
  73. }
  74. $gByte = ord($this->BUF{$seek});
  75. $seek ++;
  76. while($gByte > 0){
  77. $seek += $gByte;
  78. $gByte = ord($this->BUF{$seek});
  79. $seek ++;
  80. }
  81. break;
  82. case 254:
  83. $seek ++;
  84. $gByte = ord($this->BUF{$seek});
  85. $seek ++;
  86. while($gByte > 0){
  87. $seek += $gByte;
  88. $gByte = ord($this->BUF{$seek});
  89. $seek ++;
  90. }
  91. break;
  92. case 249:
  93. $seek ++;
  94. if($this->IMGS["info"]["HdrOffset"] == 0)$this->IMGS["info"]["HdrOffset"] = $seek - 1;
  95. $tmp["byteOffset(Begin)"] = $seek;
  96. $seek += 1;
  97. $gByte = ord($this->BUF{$seek});
  98. $seek ++;
  99. $tmp["FrameDisposal"] = $this->DoBitwise($gByte, 0x1C);
  100. if($tmp["FrameDisposal"] == 3)$this->IMGS["info"]["UsesBkBuffer"] = True;
  101. $tmp["isTransparent"] = $this->DoBitwise($gByte, 0x01);
  102. $tmp["frameDelay"] = ord(substr($this->BUF, $seek, 2));
  103. $seek += 2;
  104. if($tmp["isTransparent"]){
  105. $fColor = ord($this->BUF{$seek});
  106. $seek ++;
  107. }
  108. $seek += $tmp["isTransparent"];
  109. break;
  110. case 1:
  111. $seek ++;
  112. $gByte = ord($this->BUF{$seek});
  113. $seek ++;
  114. while($gByte > 0){
  115. $seek += $gByte;
  116. $gByte = ord($this->BUF{$seek});
  117. $seek ++;
  118. }
  119. break;
  120. default:
  121. $seek ++;
  122. $gByte = ord($this->BUF{$seek});
  123. $seek ++;
  124. while($gByte > 0){
  125. $seek += $gByte;
  126. $gByte = ord($this->BUF{$seek});
  127. $seek ++;
  128. }
  129. break;
  130. }
  131. break;
  132. case 44:
  133. $seek ++;
  134. if($this->IMGS["info"]["HdrOffset"] == 0){
  135. $tmp["byteOffset(Begin)"] = $seek;
  136. $this->IMGS["info"]["HdrOffset"] = $seek - 1;
  137. }
  138. $tmp["FrameLeft"] = ord(substr($this->BUF, $seek, 2));
  139. $seek += 2;
  140. $tmp["FrameTop"] = ord(substr($this->BUF, $seek, 2));
  141. $seek += 2;
  142. $tmp["FrameWidth"] = ord(substr($this->BUF, $seek, 2));
  143. $seek += 2;
  144. $tmp["FrameHeight"] = ord(substr($this->BUF, $seek, 2));
  145. $seek += 2;
  146. $gByte = ord($this->BUF{$seek});
  147. $seek ++;
  148. $tmp["lTableUsed"] = $this->DoBitwise($gByte, 0x80);
  149. if($tmp["lTableUsed"]){
  150. $tmp["lTableCount"] = $this->DoBitwise($gByte, 0x07);
  151. $lTableLoc = $seek;
  152. $seek += 3 * (2 << $tmp["lTableCount"]);
  153. }else{
  154. $tmp["lTableCount"] = 0;
  155. $seek ++;
  156. }
  157. if($tmp["isTransparent"]){
  158. if($this->IMGS["info"]["gTableCount"]){
  159. $this->ColorFromTable(0xE, $fColor, $this->IMGS["info"]["gTableCount"]);
  160. } elseif($tmp["lTableCount"]){
  161. $this->ColorFromTable($lTableLoc, $fColor, $tmp["lTableCount"]);
  162. }
  163. $tmp["FrameTransparentColor"] = $fColor;
  164. }else{
  165. $tmp["FrameTransparentColor"] = -1;
  166. }
  167. $gByte = ord($this->BUF{$seek});
  168. $seek ++;
  169. while($gByte > 0){
  170. $seek += $gByte;
  171. $gByte = ord($this->BUF{$seek});
  172. $seek ++;
  173. }
  174. $tmp["byteOffset(End)"] = $seek;
  175. array_push($this->IMGS["frames"], $tmp);
  176. $tmp = array();
  177. $fColor = -1;
  178. break;
  179. case 59:
  180. break(2);
  181. default:
  182. $seek ++;
  183. $gByte = ord($this->BUF{$seek});
  184. $seek ++;
  185. while($gByte > 0){
  186. $seek += $gByte;
  187. $gByte = ord($this->BUF{$seek});
  188. $seek ++;
  189. }
  190. break;
  191. }
  192. }
  193. }
  194. function getgif($i){
  195. if(!isset($this->IMGS["frames"][$i]["byteOffset(Begin)"]))return "";
  196. $pos1 = $this->IMGS["frames"][$i]["byteOffset(Begin)"];
  197. $pos2 = $this->IMGS["frames"][$i]["byteOffset(End)"];
  198. return $this->getheader().substr($this->BUF, $pos1, $pos2 - $pos1).";";
  199. }
  200. //$mode 0直接用数据生成图,1按原图高宽及当前帧位置生成图
  201. //返回 $im 图片对象
  202. function fixgif($i, $mode = 1){
  203. if(!isset($this->IMGS["frames"][$i]["byteOffset(Begin)"]))return false;
  204. $src = $this->getgif($i);
  205. $sim = imagecreatefromstring($src);
  206. if($mode === 0)return $sim;
  207. if($sim){
  208. $dim = imagecreate($this->IMGS["info"]["Width"], $this->IMGS["info"]["Height"]);
  209. if($this->IMGS["info"]["BkgColor"] > -1){
  210. imagefilledrectangle($dim, 0, 0, $this->IMGS["info"]["Width"], $this->IMGS["info"]["Height"], $this->getcolor($dim, dechex($this->IMGS["info"]["BkgColor"])));
  211. }else{
  212. imagecolortransparent($dim, $this->getcolor($dim));//透明
  213. }
  214. imagecopyresampled($dim, $sim, $this->IMGS["frames"][$i]["FrameLeft"], $this->IMGS["frames"][$i]["FrameTop"], 0, 0, $this->IMGS["frames"][$i]["FrameWidth"], $this->IMGS["frames"][$i]["FrameHeight"], $this->IMGS["frames"][$i]["FrameWidth"], $this->IMGS["frames"][$i]["FrameHeight"]);
  215. imagedestroy($sim);
  216. if($this->IMGS["info"]["BkgColor"] == -1)imagesavealpha($dim, true);
  217. return $dim;
  218. }
  219. return false;
  220. }
  221. //$im转成字符串流
  222. function getsrc($im, $mode = 0){
  223. if($mode === 0){
  224. $tmp = explode(" ", microtime());
  225. $tmp[0] = $tmp[0] * 10000000;
  226. $tmp = $tmp[0] + $tmp[1];
  227. imagegif($im, $tmp);
  228. $src = file_get_contents($tmp);
  229. @unlink($tmp);
  230. }else{
  231. ob_start();
  232. imagegif($im);
  233. $src = ob_get_clean();
  234. ob_end_clean();
  235. }
  236. return $src;
  237. }
  238. function getcolor(&$im, $color = "#000000"){
  239. if($color[0] == '#')$color = substr($color, 1);
  240. if(strlen($color) == 6)list($r, $g, $b) = array($color[0].$color[1], $color[2].$color[3], $color[4].$color[5]);
  241. elseif(strlen($color) == 3)list($r, $g, $b) = array($color[0].$color[0], $color[1].$color[1], $color[2].$color[2]);
  242. else return false;
  243. return imagecolorallocate($im, hexdec($r), hexdec($g), hexdec($b));
  244. }
  245. function getheader(){
  246. if(!isset($this->IMGS["frames"][0]["byteOffset(Begin)"]))return "";
  247. $pos = $this->IMGS["frames"][0]["byteOffset(Begin)"];
  248. return substr($this->BUF, 0, $pos);
  249. }
  250. function savegif($src, $path = "", $mode = "w+"){
  251. if(empty($src))return false;
  252. $fso = @fopen($path, $mode);
  253. @fwrite($fso, $src);
  254. @fclose($fso);
  255. return true;
  256. }
  257. function DoBitwise($lFlags, $lMask){
  258. if($lMask > 0){
  259. $result = ($lFlags & $lMask);
  260. while(($lMask & 1) == 0){
  261. $lMask = floor($lMask / 2);
  262. $result = floor($result / 2);
  263. }
  264. }
  265. return $result;
  266. }
  267. function ColorFromTable($seekIdx, &$tIndex, $nrColors) {
  268. if($tIndex < 0)return ;
  269. if($tIndex * 3 > (2 << ($nrColors * 3)) - 2){
  270. $tIndex = 0;
  271. return ;
  272. }
  273. $tIndex = ord(substr($this->BUF, $seekIdx + $tIndex * 3, 3));
  274. $tIndex = $tIndex | ( $tIndex << 8 ) | ( $tIndex << 16 );
  275. //$tIndex = dechex($tIndex);
  276. }
  277. }
  278. ?>