PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/ThinkPHP/Extend/Library/ORG/Util/Image/Driver/GIF.class.php

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