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