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