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