PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/ThinkPHP/ThinkPHP/Library/Think/Image/Driver/GIF.class.php

https://github.com/guodont/easycart
PHP | 570 lines | 316 code | 36 blank | 218 comment | 70 complexity | 9860818db9a91cce33504da38a370971 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | TOPThink [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2010 http://topthink.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
  10. // +----------------------------------------------------------------------
  11. // | GIF.class.php 2013-03-09
  12. // +----------------------------------------------------------------------
  13. namespace Think\Image\Driver;
  14. class GIF{
  15. /**
  16. * GIF帧列表
  17. * @var array
  18. */
  19. private $frames = array();
  20. /**
  21. * 每帧等待时间列表
  22. * @var array
  23. */
  24. private $delays = array();
  25. /**
  26. * 构造方法,用于解码GIF图片
  27. * @param string $src GIF图片数据
  28. * @param string $mod 图片数据类型
  29. */
  30. public function __construct($src = null, $mod = 'url') {
  31. if(!is_null($src)){
  32. if('url' == $mod && is_file($src)){
  33. $src = file_get_contents($src);
  34. }
  35. /* 解码GIF图片 */
  36. try{
  37. $de = new GIFDecoder($src);
  38. $this->frames = $de->GIFGetFrames();
  39. $this->delays = $de->GIFGetDelays();
  40. } catch(Exception $e){
  41. E("解码GIF图片出错");
  42. }
  43. }
  44. }
  45. /**
  46. * 设置或获取当前帧的数据
  47. * @param string $stream 二进制数据流
  48. * @return boolean 获取到的数据
  49. */
  50. public function image($stream = null){
  51. if(is_null($stream)){
  52. $current = current($this->frames);
  53. return false === $current ? reset($this->frames) : $current;
  54. } else {
  55. $this->frames[key($this->frames)] = $stream;
  56. }
  57. }
  58. /**
  59. * 将当前帧移动到下一帧
  60. * @return string 当前帧数据
  61. */
  62. public function nextImage(){
  63. return next($this->frames);
  64. }
  65. /**
  66. * 编码并保存当前GIF图片
  67. * @param string $gifname 图片名称
  68. */
  69. public function save($gifname){
  70. $gif = new GIFEncoder($this->frames, $this->delays, 0, 2, 0, 0, 0, 'bin');
  71. file_put_contents($gifname, $gif->GetAnimation());
  72. }
  73. }
  74. /*
  75. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  76. ::
  77. :: GIFEncoder Version 2.0 by László Zsidi, http://gifs.hu
  78. ::
  79. :: This class is a rewritten 'GifMerge.class.php' version.
  80. ::
  81. :: Modification:
  82. :: - Simplified and easy code,
  83. :: - Ultra fast encoding,
  84. :: - Built-in errors,
  85. :: - Stable working
  86. ::
  87. ::
  88. :: Updated at 2007. 02. 13. '00.05.AM'
  89. ::
  90. ::
  91. ::
  92. :: Try on-line GIFBuilder Form demo based on GIFEncoder.
  93. ::
  94. :: http://gifs.hu/phpclasses/demos/GifBuilder/
  95. ::
  96. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  97. */
  98. Class GIFEncoder {
  99. var $GIF = "GIF89a"; /* GIF header 6 bytes */
  100. var $VER = "GIFEncoder V2.05"; /* Encoder version */
  101. var $BUF = Array ( );
  102. var $LOP = 0;
  103. var $DIS = 2;
  104. var $COL = -1;
  105. var $IMG = -1;
  106. var $ERR = Array (
  107. 'ERR00'=>"Does not supported function for only one image!",
  108. 'ERR01'=>"Source is not a GIF image!",
  109. 'ERR02'=>"Unintelligible flag ",
  110. 'ERR03'=>"Does not make animation from animated GIF source",
  111. );
  112. /*
  113. :::::::::::::::::::::::::::::::::::::::::::::::::::
  114. ::
  115. :: GIFEncoder...
  116. ::
  117. */
  118. function GIFEncoder (
  119. $GIF_src, $GIF_dly, $GIF_lop, $GIF_dis,
  120. $GIF_red, $GIF_grn, $GIF_blu, $GIF_mod
  121. ) {
  122. if ( ! is_array ( $GIF_src ) && ! is_array ( $GIF_dly ) ) {
  123. printf ( "%s: %s", $this->VER, $this->ERR [ 'ERR00' ] );
  124. exit ( 0 );
  125. }
  126. $this->LOP = ( $GIF_lop > -1 ) ? $GIF_lop : 0;
  127. $this->DIS = ( $GIF_dis > -1 ) ? ( ( $GIF_dis < 3 ) ? $GIF_dis : 3 ) : 2;
  128. $this->COL = ( $GIF_red > -1 && $GIF_grn > -1 && $GIF_blu > -1 ) ?
  129. ( $GIF_red | ( $GIF_grn << 8 ) | ( $GIF_blu << 16 ) ) : -1;
  130. for ( $i = 0; $i < count ( $GIF_src ); $i++ ) {
  131. if ( strToLower ( $GIF_mod ) == "url" ) {
  132. $this->BUF [ ] = fread ( fopen ( $GIF_src [ $i ], "rb" ), filesize ( $GIF_src [ $i ] ) );
  133. }
  134. else if ( strToLower ( $GIF_mod ) == "bin" ) {
  135. $this->BUF [ ] = $GIF_src [ $i ];
  136. }
  137. else {
  138. printf ( "%s: %s ( %s )!", $this->VER, $this->ERR [ 'ERR02' ], $GIF_mod );
  139. exit ( 0 );
  140. }
  141. if ( substr ( $this->BUF [ $i ], 0, 6 ) != "GIF87a" && substr ( $this->BUF [ $i ], 0, 6 ) != "GIF89a" ) {
  142. printf ( "%s: %d %s", $this->VER, $i, $this->ERR [ 'ERR01' ] );
  143. exit ( 0 );
  144. }
  145. for ( $j = ( 13 + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ) ), $k = TRUE; $k; $j++ ) {
  146. switch ( $this->BUF [ $i ] { $j } ) {
  147. case "!":
  148. if ( ( substr ( $this->BUF [ $i ], ( $j + 3 ), 8 ) ) == "NETSCAPE" ) {
  149. printf ( "%s: %s ( %s source )!", $this->VER, $this->ERR [ 'ERR03' ], ( $i + 1 ) );
  150. exit ( 0 );
  151. }
  152. break;
  153. case ";":
  154. $k = FALSE;
  155. break;
  156. }
  157. }
  158. }
  159. GIFEncoder::GIFAddHeader ( );
  160. for ( $i = 0; $i < count ( $this->BUF ); $i++ ) {
  161. GIFEncoder::GIFAddFrames ( $i, $GIF_dly [ $i ] );
  162. }
  163. GIFEncoder::GIFAddFooter ( );
  164. }
  165. /*
  166. :::::::::::::::::::::::::::::::::::::::::::::::::::
  167. ::
  168. :: GIFAddHeader...
  169. ::
  170. */
  171. function GIFAddHeader ( ) {
  172. $cmap = 0;
  173. if ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x80 ) {
  174. $cmap = 3 * ( 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ) );
  175. $this->GIF .= substr ( $this->BUF [ 0 ], 6, 7 );
  176. $this->GIF .= substr ( $this->BUF [ 0 ], 13, $cmap );
  177. $this->GIF .= "!\377\13NETSCAPE2.0\3\1" . GIFEncoder::GIFWord ( $this->LOP ) . "\0";
  178. }
  179. }
  180. /*
  181. :::::::::::::::::::::::::::::::::::::::::::::::::::
  182. ::
  183. :: GIFAddFrames...
  184. ::
  185. */
  186. function GIFAddFrames ( $i, $d ) {
  187. $Locals_str = 13 + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) );
  188. $Locals_end = strlen ( $this->BUF [ $i ] ) - $Locals_str - 1;
  189. $Locals_tmp = substr ( $this->BUF [ $i ], $Locals_str, $Locals_end );
  190. $Global_len = 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 );
  191. $Locals_len = 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 );
  192. $Global_rgb = substr ( $this->BUF [ 0 ], 13,
  193. 3 * ( 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ) ) );
  194. $Locals_rgb = substr ( $this->BUF [ $i ], 13,
  195. 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ) );
  196. $Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 0 ) .
  197. chr ( ( $d >> 0 ) & 0xFF ) . chr ( ( $d >> 8 ) & 0xFF ) . "\x0\x0";
  198. if ( $this->COL > -1 && ord ( $this->BUF [ $i ] { 10 } ) & 0x80 ) {
  199. for ( $j = 0; $j < ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ); $j++ ) {
  200. if (
  201. ord ( $Locals_rgb { 3 * $j + 0 } ) == ( ( $this->COL >> 16 ) & 0xFF ) &&
  202. ord ( $Locals_rgb { 3 * $j + 1 } ) == ( ( $this->COL >> 8 ) & 0xFF ) &&
  203. ord ( $Locals_rgb { 3 * $j + 2 } ) == ( ( $this->COL >> 0 ) & 0xFF )
  204. ) {
  205. $Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 1 ) .
  206. chr ( ( $d >> 0 ) & 0xFF ) . chr ( ( $d >> 8 ) & 0xFF ) . chr ( $j ) . "\x0";
  207. break;
  208. }
  209. }
  210. }
  211. switch ( $Locals_tmp { 0 } ) {
  212. case "!":
  213. $Locals_img = substr ( $Locals_tmp, 8, 10 );
  214. $Locals_tmp = substr ( $Locals_tmp, 18, strlen ( $Locals_tmp ) - 18 );
  215. break;
  216. case ",":
  217. $Locals_img = substr ( $Locals_tmp, 0, 10 );
  218. $Locals_tmp = substr ( $Locals_tmp, 10, strlen ( $Locals_tmp ) - 10 );
  219. break;
  220. }
  221. if ( ord ( $this->BUF [ $i ] { 10 } ) & 0x80 && $this->IMG > -1 ) {
  222. if ( $Global_len == $Locals_len ) {
  223. if ( GIFEncoder::GIFBlockCompare ( $Global_rgb, $Locals_rgb, $Global_len ) ) {
  224. $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_tmp );
  225. }
  226. else {
  227. $byte = ord ( $Locals_img { 9 } );
  228. $byte |= 0x80;
  229. $byte &= 0xF8;
  230. $byte |= ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 );
  231. $Locals_img { 9 } = chr ( $byte );
  232. $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp );
  233. }
  234. }
  235. else {
  236. $byte = ord ( $Locals_img { 9 } );
  237. $byte |= 0x80;
  238. $byte &= 0xF8;
  239. $byte |= ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 );
  240. $Locals_img { 9 } = chr ( $byte );
  241. $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp );
  242. }
  243. }
  244. else {
  245. $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_tmp );
  246. }
  247. $this->IMG = 1;
  248. }
  249. /*
  250. :::::::::::::::::::::::::::::::::::::::::::::::::::
  251. ::
  252. :: GIFAddFooter...
  253. ::
  254. */
  255. function GIFAddFooter ( ) {
  256. $this->GIF .= ";";
  257. }
  258. /*
  259. :::::::::::::::::::::::::::::::::::::::::::::::::::
  260. ::
  261. :: GIFBlockCompare...
  262. ::
  263. */
  264. function GIFBlockCompare ( $GlobalBlock, $LocalBlock, $Len ) {
  265. for ( $i = 0; $i < $Len; $i++ ) {
  266. if (
  267. $GlobalBlock { 3 * $i + 0 } != $LocalBlock { 3 * $i + 0 } ||
  268. $GlobalBlock { 3 * $i + 1 } != $LocalBlock { 3 * $i + 1 } ||
  269. $GlobalBlock { 3 * $i + 2 } != $LocalBlock { 3 * $i + 2 }
  270. ) {
  271. return ( 0 );
  272. }
  273. }
  274. return ( 1 );
  275. }
  276. /*
  277. :::::::::::::::::::::::::::::::::::::::::::::::::::
  278. ::
  279. :: GIFWord...
  280. ::
  281. */
  282. function GIFWord ( $int ) {
  283. return ( chr ( $int & 0xFF ) . chr ( ( $int >> 8 ) & 0xFF ) );
  284. }
  285. /*
  286. :::::::::::::::::::::::::::::::::::::::::::::::::::
  287. ::
  288. :: GetAnimation...
  289. ::
  290. */
  291. function GetAnimation ( ) {
  292. return ( $this->GIF );
  293. }
  294. }
  295. /*
  296. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  297. ::
  298. :: GIFDecoder Version 2.0 by László Zsidi, http://gifs.hu
  299. ::
  300. :: Created at 2007. 02. 01. '07.47.AM'
  301. ::
  302. ::
  303. ::
  304. ::
  305. :: Try on-line GIFBuilder Form demo based on GIFDecoder.
  306. ::
  307. :: http://gifs.hu/phpclasses/demos/GifBuilder/
  308. ::
  309. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  310. */
  311. Class GIFDecoder {
  312. var $GIF_buffer = Array ( );
  313. var $GIF_arrays = Array ( );
  314. var $GIF_delays = Array ( );
  315. var $GIF_stream = "";
  316. var $GIF_string = "";
  317. var $GIF_bfseek = 0;
  318. var $GIF_screen = Array ( );
  319. var $GIF_global = Array ( );
  320. var $GIF_sorted;
  321. var $GIF_colorS;
  322. var $GIF_colorC;
  323. var $GIF_colorF;
  324. /*
  325. :::::::::::::::::::::::::::::::::::::::::::::::::::
  326. ::
  327. :: GIFDecoder ( $GIF_pointer )
  328. ::
  329. */
  330. function GIFDecoder ( $GIF_pointer ) {
  331. $this->GIF_stream = $GIF_pointer;
  332. GIFDecoder::GIFGetByte ( 6 ); // GIF89a
  333. GIFDecoder::GIFGetByte ( 7 ); // Logical Screen Descriptor
  334. $this->GIF_screen = $this->GIF_buffer;
  335. $this->GIF_colorF = $this->GIF_buffer [ 4 ] & 0x80 ? 1 : 0;
  336. $this->GIF_sorted = $this->GIF_buffer [ 4 ] & 0x08 ? 1 : 0;
  337. $this->GIF_colorC = $this->GIF_buffer [ 4 ] & 0x07;
  338. $this->GIF_colorS = 2 << $this->GIF_colorC;
  339. if ( $this->GIF_colorF == 1 ) {
  340. GIFDecoder::GIFGetByte ( 3 * $this->GIF_colorS );
  341. $this->GIF_global = $this->GIF_buffer;
  342. }
  343. /*
  344. *
  345. * 05.06.2007.
  346. * Made a little modification
  347. *
  348. *
  349. - for ( $cycle = 1; $cycle; ) {
  350. + if ( GIFDecoder::GIFGetByte ( 1 ) ) {
  351. - switch ( $this->GIF_buffer [ 0 ] ) {
  352. - case 0x21:
  353. - GIFDecoder::GIFReadExtensions ( );
  354. - break;
  355. - case 0x2C:
  356. - GIFDecoder::GIFReadDescriptor ( );
  357. - break;
  358. - case 0x3B:
  359. - $cycle = 0;
  360. - break;
  361. - }
  362. - }
  363. + else {
  364. + $cycle = 0;
  365. + }
  366. - }
  367. */
  368. for ( $cycle = 1; $cycle; ) {
  369. if ( GIFDecoder::GIFGetByte ( 1 ) ) {
  370. switch ( $this->GIF_buffer [ 0 ] ) {
  371. case 0x21:
  372. GIFDecoder::GIFReadExtensions ( );
  373. break;
  374. case 0x2C:
  375. GIFDecoder::GIFReadDescriptor ( );
  376. break;
  377. case 0x3B:
  378. $cycle = 0;
  379. break;
  380. }
  381. }
  382. else {
  383. $cycle = 0;
  384. }
  385. }
  386. }
  387. /*
  388. :::::::::::::::::::::::::::::::::::::::::::::::::::
  389. ::
  390. :: GIFReadExtension ( )
  391. ::
  392. */
  393. function GIFReadExtensions ( ) {
  394. GIFDecoder::GIFGetByte ( 1 );
  395. for ( ; ; ) {
  396. GIFDecoder::GIFGetByte ( 1 );
  397. if ( ( $u = $this->GIF_buffer [ 0 ] ) == 0x00 ) {
  398. break;
  399. }
  400. GIFDecoder::GIFGetByte ( $u );
  401. /*
  402. * 07.05.2007.
  403. * Implemented a new line for a new function
  404. * to determine the originaly delays between
  405. * frames.
  406. *
  407. */
  408. if ( $u == 4 ) {
  409. $this->GIF_delays [ ] = ( $this->GIF_buffer [ 1 ] | $this->GIF_buffer [ 2 ] << 8 );
  410. }
  411. }
  412. }
  413. /*
  414. :::::::::::::::::::::::::::::::::::::::::::::::::::
  415. ::
  416. :: GIFReadExtension ( )
  417. ::
  418. */
  419. function GIFReadDescriptor ( ) {
  420. $GIF_screen = Array ( );
  421. GIFDecoder::GIFGetByte ( 9 );
  422. $GIF_screen = $this->GIF_buffer;
  423. $GIF_colorF = $this->GIF_buffer [ 8 ] & 0x80 ? 1 : 0;
  424. if ( $GIF_colorF ) {
  425. $GIF_code = $this->GIF_buffer [ 8 ] & 0x07;
  426. $GIF_sort = $this->GIF_buffer [ 8 ] & 0x20 ? 1 : 0;
  427. }
  428. else {
  429. $GIF_code = $this->GIF_colorC;
  430. $GIF_sort = $this->GIF_sorted;
  431. }
  432. $GIF_size = 2 << $GIF_code;
  433. $this->GIF_screen [ 4 ] &= 0x70;
  434. $this->GIF_screen [ 4 ] |= 0x80;
  435. $this->GIF_screen [ 4 ] |= $GIF_code;
  436. if ( $GIF_sort ) {
  437. $this->GIF_screen [ 4 ] |= 0x08;
  438. }
  439. $this->GIF_string = "GIF87a";
  440. GIFDecoder::GIFPutByte ( $this->GIF_screen );
  441. if ( $GIF_colorF == 1 ) {
  442. GIFDecoder::GIFGetByte ( 3 * $GIF_size );
  443. GIFDecoder::GIFPutByte ( $this->GIF_buffer );
  444. }
  445. else {
  446. GIFDecoder::GIFPutByte ( $this->GIF_global );
  447. }
  448. $this->GIF_string .= chr ( 0x2C );
  449. $GIF_screen [ 8 ] &= 0x40;
  450. GIFDecoder::GIFPutByte ( $GIF_screen );
  451. GIFDecoder::GIFGetByte ( 1 );
  452. GIFDecoder::GIFPutByte ( $this->GIF_buffer );
  453. for ( ; ; ) {
  454. GIFDecoder::GIFGetByte ( 1 );
  455. GIFDecoder::GIFPutByte ( $this->GIF_buffer );
  456. if ( ( $u = $this->GIF_buffer [ 0 ] ) == 0x00 ) {
  457. break;
  458. }
  459. GIFDecoder::GIFGetByte ( $u );
  460. GIFDecoder::GIFPutByte ( $this->GIF_buffer );
  461. }
  462. $this->GIF_string .= chr ( 0x3B );
  463. /*
  464. Add frames into $GIF_stream array...
  465. */
  466. $this->GIF_arrays [ ] = $this->GIF_string;
  467. }
  468. /*
  469. :::::::::::::::::::::::::::::::::::::::::::::::::::
  470. ::
  471. :: GIFGetByte ( $len )
  472. ::
  473. */
  474. /*
  475. *
  476. * 05.06.2007.
  477. * Made a little modification
  478. *
  479. *
  480. - function GIFGetByte ( $len ) {
  481. - $this->GIF_buffer = Array ( );
  482. -
  483. - for ( $i = 0; $i < $len; $i++ ) {
  484. + if ( $this->GIF_bfseek > strlen ( $this->GIF_stream ) ) {
  485. + return 0;
  486. + }
  487. - $this->GIF_buffer [ ] = ord ( $this->GIF_stream { $this->GIF_bfseek++ } );
  488. - }
  489. + return 1;
  490. - }
  491. */
  492. function GIFGetByte ( $len ) {
  493. $this->GIF_buffer = Array ( );
  494. for ( $i = 0; $i < $len; $i++ ) {
  495. if ( $this->GIF_bfseek > strlen ( $this->GIF_stream ) ) {
  496. return 0;
  497. }
  498. $this->GIF_buffer [ ] = ord ( $this->GIF_stream { $this->GIF_bfseek++ } );
  499. }
  500. return 1;
  501. }
  502. /*
  503. :::::::::::::::::::::::::::::::::::::::::::::::::::
  504. ::
  505. :: GIFPutByte ( $bytes )
  506. ::
  507. */
  508. function GIFPutByte ( $bytes ) {
  509. for ( $i = 0; $i < count ( $bytes ); $i++ ) {
  510. $this->GIF_string .= chr ( $bytes [ $i ] );
  511. }
  512. }
  513. /*
  514. :::::::::::::::::::::::::::::::::::::::::::::::::::
  515. ::
  516. :: PUBLIC FUNCTIONS
  517. ::
  518. ::
  519. :: GIFGetFrames ( )
  520. ::
  521. */
  522. function GIFGetFrames ( ) {
  523. return ( $this->GIF_arrays );
  524. }
  525. /*
  526. :::::::::::::::::::::::::::::::::::::::::::::::::::
  527. ::
  528. :: GIFGetDelays ( )
  529. ::
  530. */
  531. function GIFGetDelays ( ) {
  532. return ( $this->GIF_delays );
  533. }
  534. }