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