annotate forum/Sources/Class-Graphics.php @ 76:e3e11437ecea website

Add forum code
author Chris Cannam
date Sun, 07 Jul 2013 11:25:48 +0200
parents
children
rev   line source
Chris@76 1 <?php
Chris@76 2
Chris@76 3 /**
Chris@76 4 * Simple Machines Forum (SMF)
Chris@76 5 *
Chris@76 6 * @package SMF
Chris@76 7 * @author Simple Machines http://www.simplemachines.org
Chris@76 8 * @copyright 2011 Simple Machines
Chris@76 9 * @license http://www.simplemachines.org/about/smf/license.php BSD
Chris@76 10 *
Chris@76 11 * @version 2.0
Chris@76 12 */
Chris@76 13
Chris@76 14 /* Gif Util copyright 2003 by Yamasoft (S/C). All rights reserved.
Chris@76 15 Do not remove this portion of the header, or use these functions except
Chris@76 16 from the original author. To get it, please navigate to:
Chris@76 17 http://www.yamasoft.com/php-gif.zip
Chris@76 18 */
Chris@76 19
Chris@76 20 if (!defined('SMF'))
Chris@76 21 die('Hacking attempt...');
Chris@76 22
Chris@76 23 /* Classes used for reading gif files (in case PHP's GD doesn't provide the
Chris@76 24 proper gif-functions).
Chris@76 25 */
Chris@76 26
Chris@76 27 class gif_lzw_compression
Chris@76 28 {
Chris@76 29 public $MAX_LZW_BITS;
Chris@76 30 public $Fresh, $CodeSize, $SetCodeSize, $MaxCode, $MaxCodeSize, $FirstCode, $OldCode;
Chris@76 31 public $ClearCode, $EndCode, $Next, $Vals, $Stack, $sp, $Buf, $CurBit, $LastBit, $Done, $LastByte;
Chris@76 32
Chris@76 33 public function __construct()
Chris@76 34 {
Chris@76 35 $this->MAX_LZW_BITS = 12;
Chris@76 36 unset($this->Next, $this->Vals, $this->Stack, $this->Buf);
Chris@76 37
Chris@76 38 $this->Next = range(0, (1 << $this->MAX_LZW_BITS) - 1);
Chris@76 39 $this->Vals = range(0, (1 << $this->MAX_LZW_BITS) - 1);
Chris@76 40 $this->Stack = range(0, (1 << ($this->MAX_LZW_BITS + 1)) - 1);
Chris@76 41 $this->Buf = range(0, 279);
Chris@76 42 }
Chris@76 43
Chris@76 44 public function decompress($data, &$datLen)
Chris@76 45 {
Chris@76 46 $stLen = strlen($data);
Chris@76 47 $datLen = 0;
Chris@76 48 $ret = '';
Chris@76 49
Chris@76 50 $this->LZWCommand($data, true);
Chris@76 51
Chris@76 52 while (($iIndex = $this->LZWCommand($data, false)) >= 0)
Chris@76 53 $ret .= chr($iIndex);
Chris@76 54
Chris@76 55 $datLen = $stLen - strlen($data);
Chris@76 56
Chris@76 57 if ($iIndex != -2)
Chris@76 58 return false;
Chris@76 59
Chris@76 60 return $ret;
Chris@76 61 }
Chris@76 62
Chris@76 63 public function LZWCommand(&$data, $bInit)
Chris@76 64 {
Chris@76 65 if ($bInit)
Chris@76 66 {
Chris@76 67 $this->SetCodeSize = ord($data[0]);
Chris@76 68 $data = substr($data, 1);
Chris@76 69
Chris@76 70 $this->CodeSize = $this->SetCodeSize + 1;
Chris@76 71 $this->ClearCode = 1 << $this->SetCodeSize;
Chris@76 72 $this->EndCode = $this->ClearCode + 1;
Chris@76 73 $this->MaxCode = $this->ClearCode + 2;
Chris@76 74 $this->MaxCodeSize = $this->ClearCode << 1;
Chris@76 75
Chris@76 76 $this->GetCode($data, $bInit);
Chris@76 77
Chris@76 78 $this->Fresh = 1;
Chris@76 79 for ($i = 0; $i < $this->ClearCode; $i++)
Chris@76 80 {
Chris@76 81 $this->Next[$i] = 0;
Chris@76 82 $this->Vals[$i] = $i;
Chris@76 83 }
Chris@76 84
Chris@76 85 for (; $i < (1 << $this->MAX_LZW_BITS); $i++)
Chris@76 86 {
Chris@76 87 $this->Next[$i] = 0;
Chris@76 88 $this->Vals[$i] = 0;
Chris@76 89 }
Chris@76 90
Chris@76 91 $this->sp = 0;
Chris@76 92 return 1;
Chris@76 93 }
Chris@76 94
Chris@76 95 if ($this->Fresh)
Chris@76 96 {
Chris@76 97 $this->Fresh = 0;
Chris@76 98 do
Chris@76 99 {
Chris@76 100 $this->FirstCode = $this->GetCode($data, $bInit);
Chris@76 101 $this->OldCode = $this->FirstCode;
Chris@76 102 }
Chris@76 103 while ($this->FirstCode == $this->ClearCode);
Chris@76 104
Chris@76 105 return $this->FirstCode;
Chris@76 106 }
Chris@76 107
Chris@76 108 if ($this->sp > 0)
Chris@76 109 {
Chris@76 110 $this->sp--;
Chris@76 111 return $this->Stack[$this->sp];
Chris@76 112 }
Chris@76 113
Chris@76 114 while (($Code = $this->GetCode($data, $bInit)) >= 0)
Chris@76 115 {
Chris@76 116 if ($Code == $this->ClearCode)
Chris@76 117 {
Chris@76 118 for ($i = 0; $i < $this->ClearCode; $i++)
Chris@76 119 {
Chris@76 120 $this->Next[$i] = 0;
Chris@76 121 $this->Vals[$i] = $i;
Chris@76 122 }
Chris@76 123
Chris@76 124 for (; $i < (1 << $this->MAX_LZW_BITS); $i++)
Chris@76 125 {
Chris@76 126 $this->Next[$i] = 0;
Chris@76 127 $this->Vals[$i] = 0;
Chris@76 128 }
Chris@76 129
Chris@76 130 $this->CodeSize = $this->SetCodeSize + 1;
Chris@76 131 $this->MaxCodeSize = $this->ClearCode << 1;
Chris@76 132 $this->MaxCode = $this->ClearCode + 2;
Chris@76 133 $this->sp = 0;
Chris@76 134 $this->FirstCode = $this->GetCode($data, $bInit);
Chris@76 135 $this->OldCode = $this->FirstCode;
Chris@76 136
Chris@76 137 return $this->FirstCode;
Chris@76 138 }
Chris@76 139
Chris@76 140 if ($Code == $this->EndCode)
Chris@76 141 return -2;
Chris@76 142
Chris@76 143 $InCode = $Code;
Chris@76 144 if ($Code >= $this->MaxCode)
Chris@76 145 {
Chris@76 146 $this->Stack[$this->sp] = $this->FirstCode;
Chris@76 147 $this->sp++;
Chris@76 148 $Code = $this->OldCode;
Chris@76 149 }
Chris@76 150
Chris@76 151 while ($Code >= $this->ClearCode)
Chris@76 152 {
Chris@76 153 $this->Stack[$this->sp] = $this->Vals[$Code];
Chris@76 154 $this->sp++;
Chris@76 155
Chris@76 156 if ($Code == $this->Next[$Code]) // Circular table entry, big GIF Error!
Chris@76 157 return -1;
Chris@76 158
Chris@76 159 $Code = $this->Next[$Code];
Chris@76 160 }
Chris@76 161
Chris@76 162 $this->FirstCode = $this->Vals[$Code];
Chris@76 163 $this->Stack[$this->sp] = $this->FirstCode;
Chris@76 164 $this->sp++;
Chris@76 165
Chris@76 166 if (($Code = $this->MaxCode) < (1 << $this->MAX_LZW_BITS))
Chris@76 167 {
Chris@76 168 $this->Next[$Code] = $this->OldCode;
Chris@76 169 $this->Vals[$Code] = $this->FirstCode;
Chris@76 170 $this->MaxCode++;
Chris@76 171
Chris@76 172 if (($this->MaxCode >= $this->MaxCodeSize) && ($this->MaxCodeSize < (1 << $this->MAX_LZW_BITS)))
Chris@76 173 {
Chris@76 174 $this->MaxCodeSize *= 2;
Chris@76 175 $this->CodeSize++;
Chris@76 176 }
Chris@76 177 }
Chris@76 178
Chris@76 179 $this->OldCode = $InCode;
Chris@76 180 if ($this->sp > 0)
Chris@76 181 {
Chris@76 182 $this->sp--;
Chris@76 183 return $this->Stack[$this->sp];
Chris@76 184 }
Chris@76 185 }
Chris@76 186
Chris@76 187 return $Code;
Chris@76 188 }
Chris@76 189
Chris@76 190 public function GetCode(&$data, $bInit)
Chris@76 191 {
Chris@76 192 if ($bInit)
Chris@76 193 {
Chris@76 194 $this->CurBit = 0;
Chris@76 195 $this->LastBit = 0;
Chris@76 196 $this->Done = 0;
Chris@76 197 $this->LastByte = 2;
Chris@76 198
Chris@76 199 return 1;
Chris@76 200 }
Chris@76 201
Chris@76 202 if (($this->CurBit + $this->CodeSize) >= $this->LastBit)
Chris@76 203 {
Chris@76 204 if ($this->Done)
Chris@76 205 {
Chris@76 206 // Ran off the end of my bits...
Chris@76 207 if ($this->CurBit >= $this->LastBit)
Chris@76 208 return 0;
Chris@76 209
Chris@76 210 return -1;
Chris@76 211 }
Chris@76 212
Chris@76 213 $this->Buf[0] = $this->Buf[$this->LastByte - 2];
Chris@76 214 $this->Buf[1] = $this->Buf[$this->LastByte - 1];
Chris@76 215
Chris@76 216 $count = ord($data[0]);
Chris@76 217 $data = substr($data, 1);
Chris@76 218
Chris@76 219 if ($count)
Chris@76 220 {
Chris@76 221 for ($i = 0; $i < $count; $i++)
Chris@76 222 $this->Buf[2 + $i] = ord($data{$i});
Chris@76 223
Chris@76 224 $data = substr($data, $count);
Chris@76 225 }
Chris@76 226 else
Chris@76 227 $this->Done = 1;
Chris@76 228
Chris@76 229 $this->LastByte = 2 + $count;
Chris@76 230 $this->CurBit = ($this->CurBit - $this->LastBit) + 16;
Chris@76 231 $this->LastBit = (2 + $count) << 3;
Chris@76 232 }
Chris@76 233
Chris@76 234 $iRet = 0;
Chris@76 235 for ($i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++)
Chris@76 236 $iRet |= (($this->Buf[intval($i / 8)] & (1 << ($i % 8))) != 0) << $j;
Chris@76 237
Chris@76 238 $this->CurBit += $this->CodeSize;
Chris@76 239 return $iRet;
Chris@76 240 }
Chris@76 241 }
Chris@76 242
Chris@76 243 class gif_color_table
Chris@76 244 {
Chris@76 245 public $m_nColors;
Chris@76 246 public $m_arColors;
Chris@76 247
Chris@76 248 public function __construct()
Chris@76 249 {
Chris@76 250 unset($this->m_nColors, $this->m_arColors);
Chris@76 251 }
Chris@76 252
Chris@76 253 public function load($lpData, $num)
Chris@76 254 {
Chris@76 255 $this->m_nColors = 0;
Chris@76 256 $this->m_arColors = array();
Chris@76 257
Chris@76 258 for ($i = 0; $i < $num; $i++)
Chris@76 259 {
Chris@76 260 $rgb = substr($lpData, $i * 3, 3);
Chris@76 261 if (strlen($rgb) < 3)
Chris@76 262 return false;
Chris@76 263
Chris@76 264 $this->m_arColors[] = (ord($rgb[2]) << 16) + (ord($rgb[1]) << 8) + ord($rgb[0]);
Chris@76 265 $this->m_nColors++;
Chris@76 266 }
Chris@76 267
Chris@76 268 return true;
Chris@76 269 }
Chris@76 270
Chris@76 271 public function toString()
Chris@76 272 {
Chris@76 273 $ret = '';
Chris@76 274
Chris@76 275 for ($i = 0; $i < $this->m_nColors; $i++)
Chris@76 276 {
Chris@76 277 $ret .=
Chris@76 278 chr(($this->m_arColors[$i] & 0x000000FF)) . // R
Chris@76 279 chr(($this->m_arColors[$i] & 0x0000FF00) >> 8) . // G
Chris@76 280 chr(($this->m_arColors[$i] & 0x00FF0000) >> 16); // B
Chris@76 281 }
Chris@76 282
Chris@76 283 return $ret;
Chris@76 284 }
Chris@76 285
Chris@76 286 public function colorIndex($rgb)
Chris@76 287 {
Chris@76 288 $rgb = intval($rgb) & 0xFFFFFF;
Chris@76 289 $r1 = ($rgb & 0x0000FF);
Chris@76 290 $g1 = ($rgb & 0x00FF00) >> 8;
Chris@76 291 $b1 = ($rgb & 0xFF0000) >> 16;
Chris@76 292 $idx = -1;
Chris@76 293
Chris@76 294 for ($i = 0; $i < $this->m_nColors; $i++)
Chris@76 295 {
Chris@76 296 $r2 = ($this->m_arColors[$i] & 0x000000FF);
Chris@76 297 $g2 = ($this->m_arColors[$i] & 0x0000FF00) >> 8;
Chris@76 298 $b2 = ($this->m_arColors[$i] & 0x00FF0000) >> 16;
Chris@76 299 $d = abs($r2 - $r1) + abs($g2 - $g1) + abs($b2 - $b1);
Chris@76 300
Chris@76 301 if (($idx == -1) || ($d < $dif))
Chris@76 302 {
Chris@76 303 $idx = $i;
Chris@76 304 $dif = $d;
Chris@76 305 }
Chris@76 306 }
Chris@76 307
Chris@76 308 return $idx;
Chris@76 309 }
Chris@76 310 }
Chris@76 311
Chris@76 312 class gif_file_header
Chris@76 313 {
Chris@76 314 public $m_lpVer, $m_nWidth, $m_nHeight, $m_bGlobalClr, $m_nColorRes;
Chris@76 315 public $m_bSorted, $m_nTableSize, $m_nBgColor, $m_nPixelRatio;
Chris@76 316 public $m_colorTable;
Chris@76 317
Chris@76 318 public function __construct()
Chris@76 319 {
Chris@76 320 unset($this->m_lpVer, $this->m_nWidth, $this->m_nHeight, $this->m_bGlobalClr, $this->m_nColorRes);
Chris@76 321 unset($this->m_bSorted, $this->m_nTableSize, $this->m_nBgColor, $this->m_nPixelRatio, $this->m_colorTable);
Chris@76 322 }
Chris@76 323
Chris@76 324 public function load($lpData, &$hdrLen)
Chris@76 325 {
Chris@76 326 $hdrLen = 0;
Chris@76 327
Chris@76 328 $this->m_lpVer = substr($lpData, 0, 6);
Chris@76 329 if (($this->m_lpVer != 'GIF87a') && ($this->m_lpVer != 'GIF89a'))
Chris@76 330 return false;
Chris@76 331
Chris@76 332 list ($this->m_nWidth, $this->m_nHeight) = array_values(unpack('v2', substr($lpData, 6, 4)));
Chris@76 333
Chris@76 334 if (!$this->m_nWidth || !$this->m_nHeight)
Chris@76 335 return false;
Chris@76 336
Chris@76 337 $b = ord(substr($lpData, 10, 1));
Chris@76 338 $this->m_bGlobalClr = ($b & 0x80) ? true : false;
Chris@76 339 $this->m_nColorRes = ($b & 0x70) >> 4;
Chris@76 340 $this->m_bSorted = ($b & 0x08) ? true : false;
Chris@76 341 $this->m_nTableSize = 2 << ($b & 0x07);
Chris@76 342 $this->m_nBgColor = ord(substr($lpData, 11, 1));
Chris@76 343 $this->m_nPixelRatio = ord(substr($lpData, 12, 1));
Chris@76 344 $hdrLen = 13;
Chris@76 345
Chris@76 346 if ($this->m_bGlobalClr)
Chris@76 347 {
Chris@76 348 $this->m_colorTable = new gif_color_table();
Chris@76 349 if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize))
Chris@76 350 return false;
Chris@76 351
Chris@76 352 $hdrLen += 3 * $this->m_nTableSize;
Chris@76 353 }
Chris@76 354
Chris@76 355 return true;
Chris@76 356 }
Chris@76 357 }
Chris@76 358
Chris@76 359 class gif_image_header
Chris@76 360 {
Chris@76 361 public $m_nLeft, $m_nTop, $m_nWidth, $m_nHeight, $m_bLocalClr;
Chris@76 362 public $m_bInterlace, $m_bSorted, $m_nTableSize, $m_colorTable;
Chris@76 363
Chris@76 364 public function __construct()
Chris@76 365 {
Chris@76 366 unset($this->m_nLeft, $this->m_nTop, $this->m_nWidth, $this->m_nHeight, $this->m_bLocalClr);
Chris@76 367 unset($this->m_bInterlace, $this->m_bSorted, $this->m_nTableSize, $this->m_colorTable);
Chris@76 368 }
Chris@76 369
Chris@76 370 public function load($lpData, &$hdrLen)
Chris@76 371 {
Chris@76 372 $hdrLen = 0;
Chris@76 373
Chris@76 374 // Get the width/height/etc. from the header.
Chris@76 375 list ($this->m_nLeft, $this->m_nTop, $this->m_nWidth, $this->m_nHeight) = array_values(unpack('v4', substr($lpData, 0, 8)));
Chris@76 376
Chris@76 377 if (!$this->m_nWidth || !$this->m_nHeight)
Chris@76 378 return false;
Chris@76 379
Chris@76 380 $b = ord($lpData[8]);
Chris@76 381 $this->m_bLocalClr = ($b & 0x80) ? true : false;
Chris@76 382 $this->m_bInterlace = ($b & 0x40) ? true : false;
Chris@76 383 $this->m_bSorted = ($b & 0x20) ? true : false;
Chris@76 384 $this->m_nTableSize = 2 << ($b & 0x07);
Chris@76 385 $hdrLen = 9;
Chris@76 386
Chris@76 387 if ($this->m_bLocalClr)
Chris@76 388 {
Chris@76 389 $this->m_colorTable = new gif_color_table();
Chris@76 390 if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize))
Chris@76 391 return false;
Chris@76 392
Chris@76 393 $hdrLen += 3 * $this->m_nTableSize;
Chris@76 394 }
Chris@76 395
Chris@76 396 return true;
Chris@76 397 }
Chris@76 398 }
Chris@76 399
Chris@76 400 class gif_image
Chris@76 401 {
Chris@76 402 public $m_disp, $m_bUser, $m_bTrans, $m_nDelay, $m_nTrans, $m_lpComm;
Chris@76 403 public $m_gih, $m_data, $m_lzw;
Chris@76 404
Chris@76 405 public function __construct()
Chris@76 406 {
Chris@76 407 unset($this->m_disp, $this->m_bUser, $this->m_nDelay, $this->m_nTrans, $this->m_lpComm, $this->m_data);
Chris@76 408 $this->m_gih = new gif_image_header();
Chris@76 409 $this->m_lzw = new gif_lzw_compression();
Chris@76 410 }
Chris@76 411
Chris@76 412 public function load($data, &$datLen)
Chris@76 413 {
Chris@76 414 $datLen = 0;
Chris@76 415
Chris@76 416 while (true)
Chris@76 417 {
Chris@76 418 $b = ord($data[0]);
Chris@76 419 $data = substr($data, 1);
Chris@76 420 $datLen++;
Chris@76 421
Chris@76 422 switch ($b)
Chris@76 423 {
Chris@76 424 // Extension...
Chris@76 425 case 0x21:
Chris@76 426 $len = 0;
Chris@76 427 if (!$this->skipExt($data, $len))
Chris@76 428 return false;
Chris@76 429
Chris@76 430 $datLen += $len;
Chris@76 431 break;
Chris@76 432
Chris@76 433 // Image...
Chris@76 434 case 0x2C:
Chris@76 435 // Load the header and color table.
Chris@76 436 $len = 0;
Chris@76 437 if (!$this->m_gih->load($data, $len))
Chris@76 438 return false;
Chris@76 439
Chris@76 440 $data = substr($data, $len);
Chris@76 441 $datLen += $len;
Chris@76 442
Chris@76 443 // Decompress the data, and ride on home ;).
Chris@76 444 $len = 0;
Chris@76 445 if (!($this->m_data = $this->m_lzw->decompress($data, $len)))
Chris@76 446 return false;
Chris@76 447
Chris@76 448 $data = substr($data, $len);
Chris@76 449 $datLen += $len;
Chris@76 450
Chris@76 451 if ($this->m_gih->m_bInterlace)
Chris@76 452 $this->deInterlace();
Chris@76 453
Chris@76 454 return true;
Chris@76 455
Chris@76 456 case 0x3B: // EOF
Chris@76 457 default:
Chris@76 458 return false;
Chris@76 459 }
Chris@76 460 }
Chris@76 461 return false;
Chris@76 462 }
Chris@76 463
Chris@76 464 public function skipExt(&$data, &$extLen)
Chris@76 465 {
Chris@76 466 $extLen = 0;
Chris@76 467
Chris@76 468 $b = ord($data[0]);
Chris@76 469 $data = substr($data, 1);
Chris@76 470 $extLen++;
Chris@76 471
Chris@76 472 switch ($b)
Chris@76 473 {
Chris@76 474 // Graphic Control...
Chris@76 475 case 0xF9:
Chris@76 476 $b = ord($data[1]);
Chris@76 477 $this->m_disp = ($b & 0x1C) >> 2;
Chris@76 478 $this->m_bUser = ($b & 0x02) ? true : false;
Chris@76 479 $this->m_bTrans = ($b & 0x01) ? true : false;
Chris@76 480 list ($this->m_nDelay) = array_values(unpack('v', substr($data, 2, 2)));
Chris@76 481 $this->m_nTrans = ord($data[4]);
Chris@76 482 break;
Chris@76 483
Chris@76 484 // Comment...
Chris@76 485 case 0xFE:
Chris@76 486 $this->m_lpComm = substr($data, 1, ord($data[0]));
Chris@76 487 break;
Chris@76 488
Chris@76 489 // Plain text...
Chris@76 490 case 0x01:
Chris@76 491 break;
Chris@76 492
Chris@76 493 // Application...
Chris@76 494 case 0xFF:
Chris@76 495 break;
Chris@76 496 }
Chris@76 497
Chris@76 498 // Skip default as defs may change.
Chris@76 499 $b = ord($data[0]);
Chris@76 500 $data = substr($data, 1);
Chris@76 501 $extLen++;
Chris@76 502 while ($b > 0)
Chris@76 503 {
Chris@76 504 $data = substr($data, $b);
Chris@76 505 $extLen += $b;
Chris@76 506 $b = ord($data[0]);
Chris@76 507 $data = substr($data, 1);
Chris@76 508 $extLen++;
Chris@76 509 }
Chris@76 510 return true;
Chris@76 511 }
Chris@76 512
Chris@76 513 public function deInterlace()
Chris@76 514 {
Chris@76 515 $data = $this->m_data;
Chris@76 516
Chris@76 517 for ($i = 0; $i < 4; $i++)
Chris@76 518 {
Chris@76 519 switch ($i)
Chris@76 520 {
Chris@76 521 case 0:
Chris@76 522 $s = 8;
Chris@76 523 $y = 0;
Chris@76 524 break;
Chris@76 525
Chris@76 526 case 1:
Chris@76 527 $s = 8;
Chris@76 528 $y = 4;
Chris@76 529 break;
Chris@76 530
Chris@76 531 case 2:
Chris@76 532 $s = 4;
Chris@76 533 $y = 2;
Chris@76 534 break;
Chris@76 535
Chris@76 536 case 3:
Chris@76 537 $s = 2;
Chris@76 538 $y = 1;
Chris@76 539 break;
Chris@76 540 }
Chris@76 541
Chris@76 542 for (; $y < $this->m_gih->m_nHeight; $y += $s)
Chris@76 543 {
Chris@76 544 $lne = substr($this->m_data, 0, $this->m_gih->m_nWidth);
Chris@76 545 $this->m_data = substr($this->m_data, $this->m_gih->m_nWidth);
Chris@76 546
Chris@76 547 $data =
Chris@76 548 substr($data, 0, $y * $this->m_gih->m_nWidth) .
Chris@76 549 $lne .
Chris@76 550 substr($data, ($y + 1) * $this->m_gih->m_nWidth);
Chris@76 551 }
Chris@76 552 }
Chris@76 553
Chris@76 554 $this->m_data = $data;
Chris@76 555 }
Chris@76 556 }
Chris@76 557
Chris@76 558 class gif_file
Chris@76 559 {
Chris@76 560 public $header, $image, $data, $loaded;
Chris@76 561
Chris@76 562 public function __construct()
Chris@76 563 {
Chris@76 564 $this->data = '';
Chris@76 565 $this->loaded = false;
Chris@76 566 $this->header = new gif_file_header();
Chris@76 567 $this->image = new gif_image();
Chris@76 568 }
Chris@76 569
Chris@76 570 public function loadFile($filename, $iIndex)
Chris@76 571 {
Chris@76 572 if ($iIndex < 0)
Chris@76 573 return false;
Chris@76 574
Chris@76 575 $this->data = @file_get_contents($filename);
Chris@76 576 if ($this->data === false)
Chris@76 577 return false;
Chris@76 578
Chris@76 579 // Tell the header to load up....
Chris@76 580 $len = 0;
Chris@76 581 if (!$this->header->load($this->data, $len))
Chris@76 582 return false;
Chris@76 583
Chris@76 584 $this->data = substr($this->data, $len);
Chris@76 585
Chris@76 586 // Keep reading (at least once) so we get to the actual image we're looking for.
Chris@76 587 for ($j = 0; $j <= $iIndex; $j++)
Chris@76 588 {
Chris@76 589 $imgLen = 0;
Chris@76 590 if (!$this->image->load($this->data, $imgLen))
Chris@76 591 return false;
Chris@76 592
Chris@76 593 $this->data = substr($this->data, $imgLen);
Chris@76 594 }
Chris@76 595
Chris@76 596 $this->loaded = true;
Chris@76 597 return true;
Chris@76 598 }
Chris@76 599
Chris@76 600 public function get_png_data($background_color)
Chris@76 601 {
Chris@76 602 if (!$this->loaded)
Chris@76 603 return false;
Chris@76 604
Chris@76 605 // Prepare the color table.
Chris@76 606 if ($this->image->m_gih->m_bLocalClr)
Chris@76 607 {
Chris@76 608 $colors = $this->image->m_gih->m_nTableSize;
Chris@76 609 $pal = $this->image->m_gih->m_colorTable->toString();
Chris@76 610
Chris@76 611 if ($background_color != -1)
Chris@76 612 $background_color = $this->image->m_gih->m_colorTable->colorIndex($background_color);
Chris@76 613 }
Chris@76 614 elseif ($this->header->m_bGlobalClr)
Chris@76 615 {
Chris@76 616 $colors = $this->header->m_nTableSize;
Chris@76 617 $pal = $this->header->m_colorTable->toString();
Chris@76 618
Chris@76 619 if ($background_color != -1)
Chris@76 620 $background_color = $this->header->m_colorTable->colorIndex($background_color);
Chris@76 621 }
Chris@76 622 else
Chris@76 623 {
Chris@76 624 $colors = 0;
Chris@76 625 $background_color = -1;
Chris@76 626 }
Chris@76 627
Chris@76 628 if ($background_color == -1)
Chris@76 629 $background_color = $this->header->m_nBgColor;
Chris@76 630
Chris@76 631 $data = &$this->image->m_data;
Chris@76 632 $header = &$this->image->m_gih;
Chris@76 633
Chris@76 634 $i = 0;
Chris@76 635 $bmp = '';
Chris@76 636
Chris@76 637 // Prepare the bitmap itself.
Chris@76 638 for ($y = 0; $y < $this->header->m_nHeight; $y++)
Chris@76 639 {
Chris@76 640 $bmp .= "\x00";
Chris@76 641
Chris@76 642 for ($x = 0; $x < $this->header->m_nWidth; $x++, $i++)
Chris@76 643 {
Chris@76 644 // Is this in the proper range? If so, get the specific pixel data...
Chris@76 645 if ($x >= $header->m_nLeft && $y >= $header->m_nTop && $x < ($header->m_nLeft + $header->m_nWidth) && $y < ($header->m_nTop + $header->m_nHeight))
Chris@76 646 $bmp .= $data{$i};
Chris@76 647 // Otherwise, this is background...
Chris@76 648 else
Chris@76 649 $bmp .= chr($background_color);
Chris@76 650 }
Chris@76 651 }
Chris@76 652
Chris@76 653 $bmp = gzcompress($bmp, 9);
Chris@76 654
Chris@76 655 // Output the basic signature first of all.
Chris@76 656 $out = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
Chris@76 657
Chris@76 658 // Now, we want the header...
Chris@76 659 $out .= "\x00\x00\x00\x0D";
Chris@76 660 $tmp = 'IHDR' . pack('N', (int) $this->header->m_nWidth) . pack('N', (int) $this->header->m_nHeight) . "\x08\x03\x00\x00\x00";
Chris@76 661 $out .= $tmp . pack('N', smf_crc32($tmp));
Chris@76 662
Chris@76 663 // The palette, assuming we have one to speak of...
Chris@76 664 if ($colors > 0)
Chris@76 665 {
Chris@76 666 $out .= pack('N', (int) $colors * 3);
Chris@76 667 $tmp = 'PLTE' . $pal;
Chris@76 668 $out .= $tmp . pack('N', smf_crc32($tmp));
Chris@76 669 }
Chris@76 670
Chris@76 671 // Do we have any transparency we want to make available?
Chris@76 672 if ($this->image->m_bTrans && $colors > 0)
Chris@76 673 {
Chris@76 674 $out .= pack('N', (int) $colors);
Chris@76 675 $tmp = 'tRNS';
Chris@76 676
Chris@76 677 // Stick each color on - full transparency or none.
Chris@76 678 for ($i = 0; $i < $colors; $i++)
Chris@76 679 $tmp .= $i == $this->image->m_nTrans ? "\x00" : "\xFF";
Chris@76 680
Chris@76 681 $out .= $tmp . pack('N', smf_crc32($tmp));
Chris@76 682 }
Chris@76 683
Chris@76 684 // Here's the data itself!
Chris@76 685 $out .= pack('N', strlen($bmp));
Chris@76 686 $tmp = 'IDAT' . $bmp;
Chris@76 687 $out .= $tmp . pack('N', smf_crc32($tmp));
Chris@76 688
Chris@76 689 // EOF marker...
Chris@76 690 $out .= "\x00\x00\x00\x00" . 'IEND' . "\xAE\x42\x60\x82";
Chris@76 691
Chris@76 692 return $out;
Chris@76 693 }
Chris@76 694 }
Chris@76 695
Chris@76 696 // crc32 doesn't work as expected on 64-bit functions - make our own.
Chris@76 697 // http://www.php.net/crc32#79567
Chris@76 698 if (!function_exists('smf_crc32'))
Chris@76 699 {
Chris@76 700 function smf_crc32($number)
Chris@76 701 {
Chris@76 702 $crc = crc32($number);
Chris@76 703
Chris@76 704 if ($crc & 0x80000000)
Chris@76 705 {
Chris@76 706 $crc ^= 0xffffffff;
Chris@76 707 $crc += 1;
Chris@76 708 $crc = -$crc;
Chris@76 709 }
Chris@76 710
Chris@76 711 return $crc;
Chris@76 712 }
Chris@76 713 }
Chris@76 714
Chris@76 715 ?>