phpthumb.gif.php 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  1. <?php
  2. ///////////////////////////////////////////////////////////////////////////////////////////////////
  3. // GIF Util - (C) 2003 Yamasoft (S/C)
  4. // http://www.yamasoft.com
  5. // All Rights Reserved
  6. // This file can be freely copied, distributed, modified, updated by anyone under the only
  7. // condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header.
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////
  9. // <gif> = gif_loadFile(filename, [index])
  10. // <bool> = gif_getSize(<gif> or filename, &width, &height)
  11. // <bool> = gif_outputAsPng(<gif>, filename, [bgColor])
  12. // <bool> = gif_outputAsBmp(<gif>, filename, [bgcolor])
  13. // <bool> = gif_outputAsJpeg(<gif>, filename, [bgcolor]) - use cjpeg if available otherwise uses GD
  14. ///////////////////////////////////////////////////////////////////////////////////////////////////
  15. // Original code by Fabien Ezber
  16. // Modified by James Heinrich <info@silisoftware.com> for use in phpThumb() - December 10, 2003
  17. // * Added function gif_loadFileToGDimageResource() - this returns a GD image resource
  18. // * Modified gif_outputAsJpeg() to check if it's running under Windows, or if cjpeg is not
  19. // available, in which case it will attempt to output JPEG using GD functions
  20. // * added @ error-suppression to two lines where it checks: if ($this->m_img->m_bTrans)
  21. // otherwise warnings are generated if error_reporting == E_ALL
  22. ///////////////////////////////////////////////////////////////////////////////////////////////////
  23. function gif_loadFile($lpszFileName, $iIndex = 0)
  24. {
  25. $gif = new CGIF();
  26. if ($gif->loadFile($lpszFileName, $iIndex)) {
  27. return $gif;
  28. }
  29. return false;
  30. }
  31. ///////////////////////////////////////////////////////////////////////////////////////////////////
  32. // Added by James Heinrich <info@silisoftware.com> - December 10, 2003
  33. function gif_loadFileToGDimageResource($gifFilename, $bgColor = -1)
  34. {
  35. if ($gif = gif_loadFile($gifFilename)) {
  36. if (!phpthumb_functions::FunctionIsDisabled('set_time_limit')) {
  37. // shouldn't take nearly this long
  38. set_time_limit(120);
  39. }
  40. // general strategy: convert raw data to PNG then convert PNG data to GD image resource
  41. $PNGdata = $gif->getPng($bgColor);
  42. if ($img = @imagecreatefromstring($PNGdata)) {
  43. // excellent - PNG image data successfully converted to GD image
  44. return $img;
  45. } elseif ($img = $gif->getGD_PixelPlotterVersion()) {
  46. // problem: imagecreatefromstring() didn't like the PNG image data.
  47. // This has been known to happen in PHP v4.0.6
  48. // solution: take the raw image data and create a new GD image and plot
  49. // pixel-by-pixel on the GD image. This is extremely slow, but it does
  50. // work and a slow solution is better than no solution, right? :)
  51. return $img;
  52. }
  53. }
  54. return false;
  55. }
  56. ///////////////////////////////////////////////////////////////////////////////////////////////////
  57. function gif_outputAsBmp($gif, $lpszFileName, $bgColor = -1)
  58. {
  59. if (!isset($gif) || (@get_class($gif) <> 'cgif') || !$gif->loaded() || ($lpszFileName == '')) {
  60. return false;
  61. }
  62. $fd = $gif->getBmp($bgColor);
  63. if (strlen($fd) <= 0) {
  64. return false;
  65. }
  66. if (!($fh = @fopen($lpszFileName, 'wb'))) {
  67. return false;
  68. }
  69. @fwrite($fh, $fd, strlen($fd));
  70. @fflush($fh);
  71. @fclose($fh);
  72. return true;
  73. }
  74. ///////////////////////////////////////////////////////////////////////////////////////////////////
  75. function gif_outputAsPng($gif, $lpszFileName, $bgColor = -1)
  76. {
  77. if (!isSet($gif) || (@get_class($gif) <> 'cgif') || !$gif->loaded() || ($lpszFileName == '')) {
  78. return false;
  79. }
  80. $fd = $gif->getPng($bgColor);
  81. if (strlen($fd) <= 0) {
  82. return false;
  83. }
  84. if (!($fh = @fopen($lpszFileName, 'wb'))) {
  85. return false;
  86. }
  87. @fwrite($fh, $fd, strlen($fd));
  88. @fflush($fh);
  89. @fclose($fh);
  90. return true;
  91. }
  92. ///////////////////////////////////////////////////////////////////////////////////////////////////
  93. function gif_outputAsJpeg($gif, $lpszFileName, $bgColor = -1)
  94. {
  95. // JPEG output that does not require cjpeg added by James Heinrich <info@silisoftware.com> - December 10, 2003
  96. if ((strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') && (file_exists('/usr/local/bin/cjpeg') || shell_exec('which cjpeg'))) {
  97. if (gif_outputAsBmp($gif, $lpszFileName.'.bmp', $bgColor)) {
  98. exec('cjpeg '.$lpszFileName.'.bmp >'.$lpszFileName.' 2>/dev/null');
  99. @unlink($lpszFileName.'.bmp');
  100. if (@file_exists($lpszFileName)) {
  101. if (@filesize($lpszFileName) > 0) {
  102. return true;
  103. }
  104. @unlink($lpszFileName);
  105. }
  106. }
  107. } else {
  108. // either Windows, or cjpeg not found in path
  109. if ($img = @imagecreatefromstring($gif->getPng($bgColor))) {
  110. if (@imagejpeg($img, $lpszFileName)) {
  111. return true;
  112. }
  113. }
  114. }
  115. return false;
  116. }
  117. ///////////////////////////////////////////////////////////////////////////////////////////////////
  118. function gif_getSize($gif, &$width, &$height)
  119. {
  120. if (isSet($gif) && (@get_class($gif) == 'cgif') && $gif->loaded()) {
  121. $width = $gif->width();
  122. $height = $gif->height();
  123. } elseif (@file_exists($gif)) {
  124. $myGIF = new CGIF();
  125. if (!$myGIF->getSize($gif, $width, $height)) {
  126. return false;
  127. }
  128. } else {
  129. return false;
  130. }
  131. return true;
  132. }
  133. ///////////////////////////////////////////////////////////////////////////////////////////////////
  134. class CGIFLZW
  135. {
  136. public $MAX_LZW_BITS;
  137. public $Fresh, $CodeSize, $SetCodeSize, $MaxCode, $MaxCodeSize, $FirstCode, $OldCode;
  138. public $ClearCode, $EndCode, $Next, $Vals, $Stack, $sp, $Buf, $CurBit, $LastBit, $Done, $LastByte;
  139. ///////////////////////////////////////////////////////////////////////////
  140. // CONSTRUCTOR
  141. public function __construct()
  142. {
  143. $this->MAX_LZW_BITS = 12;
  144. unSet($this->Next);
  145. unSet($this->Vals);
  146. unSet($this->Stack);
  147. unSet($this->Buf);
  148. $this->Next = range(0, (1 << $this->MAX_LZW_BITS) - 1);
  149. $this->Vals = range(0, (1 << $this->MAX_LZW_BITS) - 1);
  150. $this->Stack = range(0, (1 << ($this->MAX_LZW_BITS + 1)) - 1);
  151. $this->Buf = range(0, 279);
  152. }
  153. ///////////////////////////////////////////////////////////////////////////
  154. public function deCompress($data, &$datLen)
  155. {
  156. $stLen = strlen($data);
  157. $datLen = 0;
  158. $ret = '';
  159. // INITIALIZATION
  160. $this->LZWCommand($data, true);
  161. while (($iIndex = $this->LZWCommand($data, false)) >= 0) {
  162. $ret .= chr($iIndex);
  163. }
  164. $datLen = $stLen - strlen($data);
  165. if ($iIndex != -2) {
  166. return false;
  167. }
  168. return $ret;
  169. }
  170. ///////////////////////////////////////////////////////////////////////////
  171. public function LZWCommand(&$data, $bInit)
  172. {
  173. if ($bInit) {
  174. $this->SetCodeSize = ord($data{0});
  175. $data = substr($data, 1);
  176. $this->CodeSize = $this->SetCodeSize + 1;
  177. $this->ClearCode = 1 << $this->SetCodeSize;
  178. $this->EndCode = $this->ClearCode + 1;
  179. $this->MaxCode = $this->ClearCode + 2;
  180. $this->MaxCodeSize = $this->ClearCode << 1;
  181. $this->GetCode($data, $bInit);
  182. $this->Fresh = 1;
  183. for ($i = 0; $i < $this->ClearCode; $i++) {
  184. $this->Next[$i] = 0;
  185. $this->Vals[$i] = $i;
  186. }
  187. for (; $i < (1 << $this->MAX_LZW_BITS); $i++) {
  188. $this->Next[$i] = 0;
  189. $this->Vals[$i] = 0;
  190. }
  191. $this->sp = 0;
  192. return 1;
  193. }
  194. if ($this->Fresh) {
  195. $this->Fresh = 0;
  196. do {
  197. $this->FirstCode = $this->GetCode($data, $bInit);
  198. $this->OldCode = $this->FirstCode;
  199. }
  200. while ($this->FirstCode == $this->ClearCode);
  201. return $this->FirstCode;
  202. }
  203. if ($this->sp > 0) {
  204. $this->sp--;
  205. return $this->Stack[$this->sp];
  206. }
  207. while (($Code = $this->GetCode($data, $bInit)) >= 0) {
  208. if ($Code == $this->ClearCode) {
  209. for ($i = 0; $i < $this->ClearCode; $i++) {
  210. $this->Next[$i] = 0;
  211. $this->Vals[$i] = $i;
  212. }
  213. for (; $i < (1 << $this->MAX_LZW_BITS); $i++) {
  214. $this->Next[$i] = 0;
  215. $this->Vals[$i] = 0;
  216. }
  217. $this->CodeSize = $this->SetCodeSize + 1;
  218. $this->MaxCodeSize = $this->ClearCode << 1;
  219. $this->MaxCode = $this->ClearCode + 2;
  220. $this->sp = 0;
  221. $this->FirstCode = $this->GetCode($data, $bInit);
  222. $this->OldCode = $this->FirstCode;
  223. return $this->FirstCode;
  224. }
  225. if ($Code == $this->EndCode) {
  226. return -2;
  227. }
  228. $InCode = $Code;
  229. if ($Code >= $this->MaxCode) {
  230. $this->Stack[$this->sp] = $this->FirstCode;
  231. $this->sp++;
  232. $Code = $this->OldCode;
  233. }
  234. while ($Code >= $this->ClearCode) {
  235. $this->Stack[$this->sp] = $this->Vals[$Code];
  236. $this->sp++;
  237. if ($Code == $this->Next[$Code]) // Circular table entry, big GIF Error!
  238. return -1;
  239. $Code = $this->Next[$Code];
  240. }
  241. $this->FirstCode = $this->Vals[$Code];
  242. $this->Stack[$this->sp] = $this->FirstCode;
  243. $this->sp++;
  244. if (($Code = $this->MaxCode) < (1 << $this->MAX_LZW_BITS)) {
  245. $this->Next[$Code] = $this->OldCode;
  246. $this->Vals[$Code] = $this->FirstCode;
  247. $this->MaxCode++;
  248. if (($this->MaxCode >= $this->MaxCodeSize) && ($this->MaxCodeSize < (1 << $this->MAX_LZW_BITS))) {
  249. $this->MaxCodeSize *= 2;
  250. $this->CodeSize++;
  251. }
  252. }
  253. $this->OldCode = $InCode;
  254. if ($this->sp > 0) {
  255. $this->sp--;
  256. return $this->Stack[$this->sp];
  257. }
  258. }
  259. return $Code;
  260. }
  261. ///////////////////////////////////////////////////////////////////////////
  262. public function GetCode(&$data, $bInit)
  263. {
  264. if ($bInit) {
  265. $this->CurBit = 0;
  266. $this->LastBit = 0;
  267. $this->Done = 0;
  268. $this->LastByte = 2;
  269. return 1;
  270. }
  271. if (($this->CurBit + $this->CodeSize) >= $this->LastBit) {
  272. if ($this->Done) {
  273. if ($this->CurBit >= $this->LastBit) {
  274. // Ran off the end of my bits
  275. return 0;
  276. }
  277. return -1;
  278. }
  279. $this->Buf[0] = $this->Buf[$this->LastByte - 2];
  280. $this->Buf[1] = $this->Buf[$this->LastByte - 1];
  281. $Count = ord($data{0});
  282. $data = substr($data, 1);
  283. if ($Count) {
  284. for ($i = 0; $i < $Count; $i++) {
  285. $this->Buf[2 + $i] = ord($data{$i});
  286. }
  287. $data = substr($data, $Count);
  288. } else {
  289. $this->Done = 1;
  290. }
  291. $this->LastByte = 2 + $Count;
  292. $this->CurBit = ($this->CurBit - $this->LastBit) + 16;
  293. $this->LastBit = (2 + $Count) << 3;
  294. }
  295. $iRet = 0;
  296. for ($i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++) {
  297. $iRet |= (($this->Buf[ (int) ($i / 8) ] & (1 << ($i % 8))) != 0) << $j;
  298. }
  299. $this->CurBit += $this->CodeSize;
  300. return $iRet;
  301. }
  302. }
  303. ///////////////////////////////////////////////////////////////////////////////////////////////////
  304. class CGIFCOLORTABLE
  305. {
  306. public $m_nColors;
  307. public $m_arColors;
  308. ///////////////////////////////////////////////////////////////////////////
  309. // CONSTRUCTOR
  310. public function __construct()
  311. {
  312. unSet($this->m_nColors);
  313. unSet($this->m_arColors);
  314. }
  315. ///////////////////////////////////////////////////////////////////////////
  316. public function load($lpData, $num)
  317. {
  318. $this->m_nColors = 0;
  319. $this->m_arColors = array();
  320. for ($i = 0; $i < $num; $i++) {
  321. $rgb = substr($lpData, $i * 3, 3);
  322. if (strlen($rgb) < 3) {
  323. return false;
  324. }
  325. $this->m_arColors[] = (ord($rgb{2}) << 16) + (ord($rgb{1}) << 8) + ord($rgb{0});
  326. $this->m_nColors++;
  327. }
  328. return true;
  329. }
  330. ///////////////////////////////////////////////////////////////////////////
  331. public function toString()
  332. {
  333. $ret = '';
  334. for ($i = 0; $i < $this->m_nColors; $i++) {
  335. $ret .=
  336. chr($this->m_arColors[ $i] & 0x000000FF) . // R
  337. chr(($this->m_arColors[$i] & 0x0000FF00) >> 8) . // G
  338. chr(($this->m_arColors[$i] & 0x00FF0000) >> 16); // B
  339. }
  340. return $ret;
  341. }
  342. ///////////////////////////////////////////////////////////////////////////
  343. public function toRGBQuad()
  344. {
  345. $ret = '';
  346. for ($i = 0; $i < $this->m_nColors; $i++) {
  347. $ret .=
  348. chr(($this->m_arColors[$i] & 0x00FF0000) >> 16) . // B
  349. chr(($this->m_arColors[$i] & 0x0000FF00) >> 8) . // G
  350. chr($this->m_arColors[ $i] & 0x000000FF) . // R
  351. "\x00";
  352. }
  353. return $ret;
  354. }
  355. ///////////////////////////////////////////////////////////////////////////
  356. public function colorIndex($rgb)
  357. {
  358. $rgb = (int) $rgb & 0xFFFFFF;
  359. $r1 = ($rgb & 0x0000FF);
  360. $g1 = ($rgb & 0x00FF00) >> 8;
  361. $b1 = ($rgb & 0xFF0000) >> 16;
  362. $idx = -1;
  363. $dif = 0;
  364. for ($i = 0; $i < $this->m_nColors; $i++) {
  365. $r2 = ($this->m_arColors[$i] & 0x000000FF);
  366. $g2 = ($this->m_arColors[$i] & 0x0000FF00) >> 8;
  367. $b2 = ($this->m_arColors[$i] & 0x00FF0000) >> 16;
  368. $d = abs($r2 - $r1) + abs($g2 - $g1) + abs($b2 - $b1);
  369. if (($idx == -1) || ($d < $dif)) {
  370. $idx = $i;
  371. $dif = $d;
  372. }
  373. }
  374. return $idx;
  375. }
  376. }
  377. ///////////////////////////////////////////////////////////////////////////////////////////////////
  378. class CGIFFILEHEADER
  379. {
  380. public $m_lpVer;
  381. public $m_nWidth;
  382. public $m_nHeight;
  383. public $m_bGlobalClr;
  384. public $m_nColorRes;
  385. public $m_bSorted;
  386. public $m_nTableSize;
  387. public $m_nBgColor;
  388. public $m_nPixelRatio;
  389. public $m_colorTable;
  390. ///////////////////////////////////////////////////////////////////////////
  391. // CONSTRUCTOR
  392. public function __construct()
  393. {
  394. unSet($this->m_lpVer);
  395. unSet($this->m_nWidth);
  396. unSet($this->m_nHeight);
  397. unSet($this->m_bGlobalClr);
  398. unSet($this->m_nColorRes);
  399. unSet($this->m_bSorted);
  400. unSet($this->m_nTableSize);
  401. unSet($this->m_nBgColor);
  402. unSet($this->m_nPixelRatio);
  403. unSet($this->m_colorTable);
  404. }
  405. ///////////////////////////////////////////////////////////////////////////
  406. public function load($lpData, &$hdrLen)
  407. {
  408. $hdrLen = 0;
  409. $this->m_lpVer = substr($lpData, 0, 6);
  410. if (($this->m_lpVer <> 'GIF87a') && ($this->m_lpVer <> 'GIF89a')) {
  411. return false;
  412. }
  413. $this->m_nWidth = $this->w2i(substr($lpData, 6, 2));
  414. $this->m_nHeight = $this->w2i(substr($lpData, 8, 2));
  415. if (!$this->m_nWidth || !$this->m_nHeight) {
  416. return false;
  417. }
  418. $b = ord($lpData[ 10 ]);
  419. $this->m_bGlobalClr = ($b & 0x80) ? true : false;
  420. $this->m_nColorRes = ($b & 0x70) >> 4;
  421. $this->m_bSorted = ($b & 0x08) ? true : false;
  422. $this->m_nTableSize = 2 << ($b & 0x07);
  423. $this->m_nBgColor = ord($lpData[ 11 ]);
  424. $this->m_nPixelRatio = ord($lpData[ 12 ]);
  425. $hdrLen = 13;
  426. if ($this->m_bGlobalClr) {
  427. $this->m_colorTable = new CGIFCOLORTABLE();
  428. if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) {
  429. return false;
  430. }
  431. $hdrLen += 3 * $this->m_nTableSize;
  432. }
  433. return true;
  434. }
  435. ///////////////////////////////////////////////////////////////////////////
  436. public function w2i($str)
  437. {
  438. return ord($str[ 0 ]) + (ord($str[ 1 ]) << 8);
  439. }
  440. }
  441. ///////////////////////////////////////////////////////////////////////////////////////////////////
  442. class CGIFIMAGEHEADER
  443. {
  444. public $m_nLeft;
  445. public $m_nTop;
  446. public $m_nWidth;
  447. public $m_nHeight;
  448. public $m_bLocalClr;
  449. public $m_bInterlace;
  450. public $m_bSorted;
  451. public $m_nTableSize;
  452. public $m_colorTable;
  453. ///////////////////////////////////////////////////////////////////////////
  454. // CONSTRUCTOR
  455. public function __construct()
  456. {
  457. unSet($this->m_nLeft);
  458. unSet($this->m_nTop);
  459. unSet($this->m_nWidth);
  460. unSet($this->m_nHeight);
  461. unSet($this->m_bLocalClr);
  462. unSet($this->m_bInterlace);
  463. unSet($this->m_bSorted);
  464. unSet($this->m_nTableSize);
  465. unSet($this->m_colorTable);
  466. }
  467. ///////////////////////////////////////////////////////////////////////////
  468. public function load($lpData, &$hdrLen)
  469. {
  470. $hdrLen = 0;
  471. $this->m_nLeft = $this->w2i(substr($lpData, 0, 2));
  472. $this->m_nTop = $this->w2i(substr($lpData, 2, 2));
  473. $this->m_nWidth = $this->w2i(substr($lpData, 4, 2));
  474. $this->m_nHeight = $this->w2i(substr($lpData, 6, 2));
  475. if (!$this->m_nWidth || !$this->m_nHeight) {
  476. return false;
  477. }
  478. $b = ord($lpData{8});
  479. $this->m_bLocalClr = ($b & 0x80) ? true : false;
  480. $this->m_bInterlace = ($b & 0x40) ? true : false;
  481. $this->m_bSorted = ($b & 0x20) ? true : false;
  482. $this->m_nTableSize = 2 << ($b & 0x07);
  483. $hdrLen = 9;
  484. if ($this->m_bLocalClr) {
  485. $this->m_colorTable = new CGIFCOLORTABLE();
  486. if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) {
  487. return false;
  488. }
  489. $hdrLen += 3 * $this->m_nTableSize;
  490. }
  491. return true;
  492. }
  493. ///////////////////////////////////////////////////////////////////////////
  494. public function w2i($str)
  495. {
  496. return ord($str[ 0 ]) + (ord($str[ 1 ]) << 8);
  497. }
  498. }
  499. ///////////////////////////////////////////////////////////////////////////////////////////////////
  500. class CGIFIMAGE
  501. {
  502. public $m_disp;
  503. public $m_bUser;
  504. public $m_bTrans;
  505. public $m_nDelay;
  506. public $m_nTrans;
  507. public $m_lpComm;
  508. public $m_gih;
  509. public $m_data;
  510. public $m_lzw;
  511. ///////////////////////////////////////////////////////////////////////////
  512. public function __construct()
  513. {
  514. unSet($this->m_disp);
  515. unSet($this->m_bUser);
  516. unSet($this->m_bTrans);
  517. unSet($this->m_nDelay);
  518. unSet($this->m_nTrans);
  519. unSet($this->m_lpComm);
  520. unSet($this->m_data);
  521. $this->m_gih = new CGIFIMAGEHEADER();
  522. $this->m_lzw = new CGIFLZW();
  523. }
  524. ///////////////////////////////////////////////////////////////////////////
  525. public function load($data, &$datLen)
  526. {
  527. $datLen = 0;
  528. while (true) {
  529. $b = ord($data{0});
  530. $data = substr($data, 1);
  531. $datLen++;
  532. switch($b) {
  533. case 0x21: // Extension
  534. if (!$this->skipExt($data, $len = 0)) {
  535. return false;
  536. }
  537. $datLen += $len;
  538. break;
  539. case 0x2C: // Image
  540. // LOAD HEADER & COLOR TABLE
  541. if (!$this->m_gih->load($data, $len = 0)) {
  542. return false;
  543. }
  544. $data = substr($data, $len);
  545. $datLen += $len;
  546. // ALLOC BUFFER
  547. if (!($this->m_data = $this->m_lzw->deCompress($data, $len = 0))) {
  548. return false;
  549. }
  550. $data = substr($data, $len);
  551. $datLen += $len;
  552. if ($this->m_gih->m_bInterlace) {
  553. $this->deInterlace();
  554. }
  555. return true;
  556. case 0x3B: // EOF
  557. default:
  558. return false;
  559. }
  560. }
  561. return false;
  562. }
  563. ///////////////////////////////////////////////////////////////////////////
  564. public function skipExt(&$data, &$extLen)
  565. {
  566. $extLen = 0;
  567. $b = ord($data{0});
  568. $data = substr($data, 1);
  569. $extLen++;
  570. switch($b) {
  571. case 0xF9: // Graphic Control
  572. $b = ord($data{1});
  573. $this->m_disp = ($b & 0x1C) >> 2;
  574. $this->m_bUser = ($b & 0x02) ? true : false;
  575. $this->m_bTrans = ($b & 0x01) ? true : false;
  576. $this->m_nDelay = $this->w2i(substr($data, 2, 2));
  577. $this->m_nTrans = ord($data{4});
  578. break;
  579. case 0xFE: // Comment
  580. $this->m_lpComm = substr($data, 1, ord($data{0}));
  581. break;
  582. case 0x01: // Plain text
  583. break;
  584. case 0xFF: // Application
  585. break;
  586. }
  587. // SKIP DEFAULT AS DEFS MAY CHANGE
  588. $b = ord($data{0});
  589. $data = substr($data, 1);
  590. $extLen++;
  591. while ($b > 0) {
  592. $data = substr($data, $b);
  593. $extLen += $b;
  594. $b = ord($data{0});
  595. $data = substr($data, 1);
  596. $extLen++;
  597. }
  598. return true;
  599. }
  600. ///////////////////////////////////////////////////////////////////////////
  601. public function w2i($str)
  602. {
  603. return ord($str[ 0 ]) + (ord($str[ 1 ]) << 8);
  604. }
  605. ///////////////////////////////////////////////////////////////////////////
  606. public function deInterlace()
  607. {
  608. $data = $this->m_data;
  609. $s = 0;
  610. $y = 0;
  611. for ($i = 0; $i < 4; $i++) {
  612. switch($i) {
  613. case 0:
  614. $s = 8;
  615. $y = 0;
  616. break;
  617. case 1:
  618. $s = 8;
  619. $y = 4;
  620. break;
  621. case 2:
  622. $s = 4;
  623. $y = 2;
  624. break;
  625. case 3:
  626. $s = 2;
  627. $y = 1;
  628. break;
  629. }
  630. for (; $y < $this->m_gih->m_nHeight; $y += $s) {
  631. $lne = substr($this->m_data, 0, $this->m_gih->m_nWidth);
  632. $this->m_data = substr($this->m_data, $this->m_gih->m_nWidth);
  633. $data =
  634. substr($data, 0, $y * $this->m_gih->m_nWidth) .
  635. $lne .
  636. substr($data, ($y + 1) * $this->m_gih->m_nWidth);
  637. }
  638. }
  639. $this->m_data = $data;
  640. }
  641. }
  642. ///////////////////////////////////////////////////////////////////////////////////////////////////
  643. class CGIF
  644. {
  645. public $m_gfh;
  646. public $m_lpData;
  647. public $m_img;
  648. public $m_bLoaded;
  649. ///////////////////////////////////////////////////////////////////////////
  650. // CONSTRUCTOR
  651. public function __construct()
  652. {
  653. $this->m_gfh = new CGIFFILEHEADER();
  654. $this->m_img = new CGIFIMAGE();
  655. $this->m_lpData = '';
  656. $this->m_bLoaded = false;
  657. }
  658. ///////////////////////////////////////////////////////////////////////////
  659. public function loadFile($lpszFileName, $iIndex)
  660. {
  661. if ($iIndex < 0) {
  662. return false;
  663. }
  664. // READ FILE
  665. if (!($fh = @fopen($lpszFileName, 'rb'))) {
  666. return false;
  667. }
  668. $this->m_lpData = @fread($fh, @filesize($lpszFileName));
  669. fclose($fh);
  670. // GET FILE HEADER
  671. if (!$this->m_gfh->load($this->m_lpData, $len = 0)) {
  672. return false;
  673. }
  674. $this->m_lpData = substr($this->m_lpData, $len);
  675. do {
  676. if (!$this->m_img->load($this->m_lpData, $imgLen = 0)) {
  677. return false;
  678. }
  679. $this->m_lpData = substr($this->m_lpData, $imgLen);
  680. }
  681. while ($iIndex-- > 0);
  682. $this->m_bLoaded = true;
  683. return true;
  684. }
  685. ///////////////////////////////////////////////////////////////////////////
  686. public function getSize($lpszFileName, &$width, &$height)
  687. {
  688. if (!($fh = @fopen($lpszFileName, 'rb'))) {
  689. return false;
  690. }
  691. $data = @fread($fh, @filesize($lpszFileName));
  692. @fclose($fh);
  693. $gfh = new CGIFFILEHEADER();
  694. if (!$gfh->load($data, $len = 0)) {
  695. return false;
  696. }
  697. $width = $gfh->m_nWidth;
  698. $height = $gfh->m_nHeight;
  699. return true;
  700. }
  701. ///////////////////////////////////////////////////////////////////////////
  702. public function getBmp($bgColor)
  703. {
  704. $out = '';
  705. if (!$this->m_bLoaded) {
  706. return false;
  707. }
  708. // PREPARE COLOR TABLE (RGBQUADs)
  709. if ($this->m_img->m_gih->m_bLocalClr) {
  710. $nColors = $this->m_img->m_gih->m_nTableSize;
  711. $rgbq = $this->m_img->m_gih->m_colorTable->toRGBQuad();
  712. if ($bgColor != -1) {
  713. $bgColor = $this->m_img->m_gih->m_colorTable->colorIndex($bgColor);
  714. }
  715. } elseif ($this->m_gfh->m_bGlobalClr) {
  716. $nColors = $this->m_gfh->m_nTableSize;
  717. $rgbq = $this->m_gfh->m_colorTable->toRGBQuad();
  718. if ($bgColor != -1) {
  719. $bgColor = $this->m_gfh->m_colorTable->colorIndex($bgColor);
  720. }
  721. } else {
  722. $nColors = 0;
  723. $rgbq = '';
  724. $bgColor = -1;
  725. }
  726. // PREPARE BITMAP BITS
  727. $data = $this->m_img->m_data;
  728. $nPxl = ($this->m_gfh->m_nHeight - 1) * $this->m_gfh->m_nWidth;
  729. $bmp = '';
  730. $nPad = ($this->m_gfh->m_nWidth % 4) ? 4 - ($this->m_gfh->m_nWidth % 4) : 0;
  731. for ($y = 0; $y < $this->m_gfh->m_nHeight; $y++) {
  732. for ($x = 0; $x < $this->m_gfh->m_nWidth; $x++, $nPxl++) {
  733. if (
  734. ($x >= $this->m_img->m_gih->m_nLeft) &&
  735. ($y >= $this->m_img->m_gih->m_nTop) &&
  736. ($x < ($this->m_img->m_gih->m_nLeft + $this->m_img->m_gih->m_nWidth)) &&
  737. ($y < ($this->m_img->m_gih->m_nTop + $this->m_img->m_gih->m_nHeight))) {
  738. // PART OF IMAGE
  739. if (@$this->m_img->m_bTrans && (ord($data{$nPxl}) == $this->m_img->m_nTrans)) {
  740. // TRANSPARENT -> BACKGROUND
  741. if ($bgColor == -1) {
  742. $bmp .= chr($this->m_gfh->m_nBgColor);
  743. } else {
  744. $bmp .= chr($bgColor);
  745. }
  746. } else {
  747. $bmp .= $data{$nPxl};
  748. }
  749. } else {
  750. // BACKGROUND
  751. if ($bgColor == -1) {
  752. $bmp .= chr($this->m_gfh->m_nBgColor);
  753. } else {
  754. $bmp .= chr($bgColor);
  755. }
  756. }
  757. }
  758. $nPxl -= $this->m_gfh->m_nWidth << 1;
  759. // ADD PADDING
  760. for ($x = 0; $x < $nPad; $x++) {
  761. $bmp .= "\x00";
  762. }
  763. }
  764. // BITMAPFILEHEADER
  765. $out .= 'BM';
  766. $out .= $this->dword(14 + 40 + ($nColors << 2) + strlen($bmp));
  767. $out .= "\x00\x00";
  768. $out .= "\x00\x00";
  769. $out .= $this->dword(14 + 40 + ($nColors << 2));
  770. // BITMAPINFOHEADER
  771. $out .= $this->dword(40);
  772. $out .= $this->dword($this->m_gfh->m_nWidth);
  773. $out .= $this->dword($this->m_gfh->m_nHeight);
  774. $out .= "\x01\x00";
  775. $out .= "\x08\x00";
  776. $out .= "\x00\x00\x00\x00";
  777. $out .= "\x00\x00\x00\x00";
  778. $out .= "\x12\x0B\x00\x00";
  779. $out .= "\x12\x0B\x00\x00";
  780. $out .= $this->dword($nColors % 256);
  781. $out .= "\x00\x00\x00\x00";
  782. // COLOR TABLE
  783. if ($nColors > 0) {
  784. $out .= $rgbq;
  785. }
  786. // DATA
  787. $out .= $bmp;
  788. return $out;
  789. }
  790. ///////////////////////////////////////////////////////////////////////////
  791. public function getPng($bgColor)
  792. {
  793. $out = '';
  794. if (!$this->m_bLoaded) {
  795. return false;
  796. }
  797. // PREPARE COLOR TABLE (RGBQUADs)
  798. if ($this->m_img->m_gih->m_bLocalClr) {
  799. $nColors = $this->m_img->m_gih->m_nTableSize;
  800. $pal = $this->m_img->m_gih->m_colorTable->toString();
  801. if ($bgColor != -1) {
  802. $bgColor = $this->m_img->m_gih->m_colorTable->colorIndex($bgColor);
  803. }
  804. } elseif ($this->m_gfh->m_bGlobalClr) {
  805. $nColors = $this->m_gfh->m_nTableSize;
  806. $pal = $this->m_gfh->m_colorTable->toString();
  807. if ($bgColor != -1) {
  808. $bgColor = $this->m_gfh->m_colorTable->colorIndex($bgColor);
  809. }
  810. } else {
  811. $nColors = 0;
  812. $pal = '';
  813. $bgColor = -1;
  814. }
  815. // PREPARE BITMAP BITS
  816. $data = $this->m_img->m_data;
  817. $nPxl = 0;
  818. $bmp = '';
  819. for ($y = 0; $y < $this->m_gfh->m_nHeight; $y++) {
  820. $bmp .= "\x00";
  821. for ($x = 0; $x < $this->m_gfh->m_nWidth; $x++, $nPxl++) {
  822. if (
  823. ($x >= $this->m_img->m_gih->m_nLeft) &&
  824. ($y >= $this->m_img->m_gih->m_nTop) &&
  825. ($x < ($this->m_img->m_gih->m_nLeft + $this->m_img->m_gih->m_nWidth)) &&
  826. ($y < ($this->m_img->m_gih->m_nTop + $this->m_img->m_gih->m_nHeight))) {
  827. // PART OF IMAGE
  828. $bmp .= $data{$nPxl};
  829. } else {
  830. // BACKGROUND
  831. if ($bgColor == -1) {
  832. $bmp .= chr($this->m_gfh->m_nBgColor);
  833. } else {
  834. $bmp .= chr($bgColor);
  835. }
  836. }
  837. }
  838. }
  839. $bmp = gzcompress($bmp, 9);
  840. ///////////////////////////////////////////////////////////////////////
  841. // SIGNATURE
  842. $out .= "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
  843. ///////////////////////////////////////////////////////////////////////
  844. // HEADER
  845. $out .= "\x00\x00\x00\x0D";
  846. $tmp = 'IHDR';
  847. $tmp .= $this->ndword($this->m_gfh->m_nWidth);
  848. $tmp .= $this->ndword($this->m_gfh->m_nHeight);
  849. $tmp .= "\x08\x03\x00\x00\x00";
  850. $out .= $tmp;
  851. $out .= $this->ndword(crc32($tmp));
  852. ///////////////////////////////////////////////////////////////////////
  853. // PALETTE
  854. if ($nColors > 0) {
  855. $out .= $this->ndword($nColors * 3);
  856. $tmp = 'PLTE';
  857. $tmp .= $pal;
  858. $out .= $tmp;
  859. $out .= $this->ndword(crc32($tmp));
  860. }
  861. ///////////////////////////////////////////////////////////////////////
  862. // TRANSPARENCY
  863. if (@$this->m_img->m_bTrans && ($nColors > 0)) {
  864. $out .= $this->ndword($nColors);
  865. $tmp = 'tRNS';
  866. for ($i = 0; $i < $nColors; $i++) {
  867. $tmp .= ($i == $this->m_img->m_nTrans) ? "\x00" : "\xFF";
  868. }
  869. $out .= $tmp;
  870. $out .= $this->ndword(crc32($tmp));
  871. }
  872. ///////////////////////////////////////////////////////////////////////
  873. // DATA BITS
  874. $out .= $this->ndword(strlen($bmp));
  875. $tmp = 'IDAT';
  876. $tmp .= $bmp;
  877. $out .= $tmp;
  878. $out .= $this->ndword(crc32($tmp));
  879. ///////////////////////////////////////////////////////////////////////
  880. // END OF FILE
  881. $out .= "\x00\x00\x00\x00IEND\xAE\x42\x60\x82";
  882. return $out;
  883. }
  884. ///////////////////////////////////////////////////////////////////////////
  885. // Added by James Heinrich <info@silisoftware.com> - January 5, 2003
  886. // Takes raw image data and plots it pixel-by-pixel on a new GD image and returns that
  887. // It's extremely slow, but the only solution when imagecreatefromstring() fails
  888. public function getGD_PixelPlotterVersion()
  889. {
  890. if (!$this->m_bLoaded) {
  891. return false;
  892. }
  893. // PREPARE COLOR TABLE (RGBQUADs)
  894. if ($this->m_img->m_gih->m_bLocalClr) {
  895. $pal = $this->m_img->m_gih->m_colorTable->toString();
  896. } elseif ($this->m_gfh->m_bGlobalClr) {
  897. $pal = $this->m_gfh->m_colorTable->toString();
  898. } else {
  899. die('No color table available in getGD_PixelPlotterVersion()');
  900. }
  901. $PlottingIMG = imagecreate($this->m_gfh->m_nWidth, $this->m_gfh->m_nHeight);
  902. $NumColorsInPal = floor(strlen($pal) / 3);
  903. $ThisImageColor = array();
  904. for ($i = 0; $i < $NumColorsInPal; $i++) {
  905. $ThisImageColor[$i] = imagecolorallocate(
  906. $PlottingIMG,
  907. ord($pal{($i * 3) + 0}),
  908. ord($pal{($i * 3) + 1}),
  909. ord($pal{($i * 3) + 2}));
  910. }
  911. // PREPARE BITMAP BITS
  912. $data = $this->m_img->m_data;
  913. $nPxl = ($this->m_gfh->m_nHeight - 1) * $this->m_gfh->m_nWidth;
  914. for ($y = 0; $y < $this->m_gfh->m_nHeight; $y++) {
  915. if (!phpthumb_functions::FunctionIsDisabled('set_time_limit')) {
  916. set_time_limit(30);
  917. }
  918. for ($x = 0; $x < $this->m_gfh->m_nWidth; $x++, $nPxl++) {
  919. if (
  920. ($x >= $this->m_img->m_gih->m_nLeft) &&
  921. ($y >= $this->m_img->m_gih->m_nTop) &&
  922. ($x < ($this->m_img->m_gih->m_nLeft + $this->m_img->m_gih->m_nWidth)) &&
  923. ($y < ($this->m_img->m_gih->m_nTop + $this->m_img->m_gih->m_nHeight))) {
  924. // PART OF IMAGE
  925. if (@$this->m_img->m_bTrans && (ord($data{$nPxl}) == $this->m_img->m_nTrans)) {
  926. imagesetpixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[$this->m_gfh->m_nBgColor]);
  927. } else {
  928. imagesetpixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[ord($data{$nPxl})]);
  929. }
  930. } else {
  931. // BACKGROUND
  932. imagesetpixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[$this->m_gfh->m_nBgColor]);
  933. }
  934. }
  935. $nPxl -= $this->m_gfh->m_nWidth << 1;
  936. }
  937. return $PlottingIMG;
  938. }
  939. ///////////////////////////////////////////////////////////////////////////
  940. public function dword($val)
  941. {
  942. $val = (int) $val;
  943. return chr($val & 0xFF).chr(($val & 0xFF00) >> 8).chr(($val & 0xFF0000) >> 16).chr(($val & 0xFF000000) >> 24);
  944. }
  945. ///////////////////////////////////////////////////////////////////////////
  946. public function ndword($val)
  947. {
  948. $val = (int) $val;
  949. return chr(($val & 0xFF000000) >> 24).chr(($val & 0xFF0000) >> 16).chr(($val & 0xFF00) >> 8).chr($val & 0xFF);
  950. }
  951. ///////////////////////////////////////////////////////////////////////////
  952. public function width()
  953. {
  954. return $this->m_gfh->m_nWidth;
  955. }
  956. ///////////////////////////////////////////////////////////////////////////
  957. public function height()
  958. {
  959. return $this->m_gfh->m_nHeight;
  960. }
  961. ///////////////////////////////////////////////////////////////////////////
  962. public function comment()
  963. {
  964. return $this->m_img->m_lpComm;
  965. }
  966. ///////////////////////////////////////////////////////////////////////////
  967. public function loaded()
  968. {
  969. return $this->m_bLoaded;
  970. }
  971. }