Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
103 - 1
<?php
2
///////////////////////////////////////////////////////////////////////////////////////////////////
3
// 2009-12-22 Adapted for mPDF 4.2
4
///////////////////////////////////////////////////////////////////////////////////////////////////
5
// GIF Util - (C) 2003 Yamasoft (S/C)
6
// http://www.yamasoft.com
7
// All Rights Reserved
8
// This file can be freely copied, distributed, modified, updated by anyone under the only
9
// condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header.
10
///////////////////////////////////////////////////////////////////////////////////////////////////
11
///////////////////////////////////////////////////////////////////////////////////////////////////
12
// 2009-12-22 Adapted INB
13
// Functions calling functionname($x, $len = 0) were not working on PHP5.1.5 as pass by reference
14
// All edited to $len = 0; then call function.
15
///////////////////////////////////////////////////////////////////////////////////////////////////
16
 
17
 
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19
 
20
class CGIFLZW
21
{
22
	var $MAX_LZW_BITS;
23
	var $Fresh, $CodeSize, $SetCodeSize, $MaxCode, $MaxCodeSize, $FirstCode, $OldCode;
24
	var $ClearCode, $EndCode, $Next, $Vals, $Stack, $sp, $Buf, $CurBit, $LastBit, $Done, $LastByte;
25
 
26
	///////////////////////////////////////////////////////////////////////////
27
 
28
	// CONSTRUCTOR
29
	function CGIFLZW()
30
	{
31
		$this->MAX_LZW_BITS = 12;
32
		unSet($this->Next);
33
		unSet($this->Vals);
34
		unSet($this->Stack);
35
		unSet($this->Buf);
36
 
37
		$this->Next  = range(0, (1 << $this->MAX_LZW_BITS)       - 1);
38
		$this->Vals  = range(0, (1 << $this->MAX_LZW_BITS)       - 1);
39
		$this->Stack = range(0, (1 << ($this->MAX_LZW_BITS + 1)) - 1);
40
		$this->Buf   = range(0, 279);
41
	}
42
 
43
	///////////////////////////////////////////////////////////////////////////
44
 
45
	function deCompress($data, &$datLen)
46
	{
47
		$stLen  = strlen($data);
48
		$datLen = 0;
49
		$ret    = "";
50
		$dp = 0; 	// data pointer
51
 
52
		// INITIALIZATION
53
		$this->LZWCommandInit($data, $dp);
54
 
55
		while(($iIndex = $this->LZWCommand($data, $dp)) >= 0) {
56
			$ret .= chr($iIndex);
57
		}
58
 
59
		$datLen = $dp;
60
 
61
		if($iIndex != -2) {
62
			return false;
63
		}
64
 
65
		return $ret;
66
	}
67
 
68
	///////////////////////////////////////////////////////////////////////////
69
	function LZWCommandInit(&$data, &$dp)
70
	{
71
			$this->SetCodeSize = ord($data[0]);
72
			$dp += 1;
73
 
74
			$this->CodeSize    = $this->SetCodeSize + 1;
75
			$this->ClearCode   = 1 << $this->SetCodeSize;
76
			$this->EndCode     = $this->ClearCode + 1;
77
			$this->MaxCode     = $this->ClearCode + 2;
78
			$this->MaxCodeSize = $this->ClearCode << 1;
79
 
80
			$this->GetCodeInit($data, $dp);
81
 
82
			$this->Fresh = 1;
83
			for($i = 0; $i < $this->ClearCode; $i++) {
84
				$this->Next[$i] = 0;
85
				$this->Vals[$i] = $i;
86
			}
87
 
88
			for(; $i < (1 << $this->MAX_LZW_BITS); $i++) {
89
				$this->Next[$i] = 0;
90
				$this->Vals[$i] = 0;
91
			}
92
 
93
			$this->sp = 0;
94
			return 1;
95
	}
96
 
97
	function LZWCommand(&$data, &$dp)
98
	{
99
		if($this->Fresh) {
100
			$this->Fresh = 0;
101
			do {
102
				$this->FirstCode = $this->GetCode($data, $dp);
103
				$this->OldCode   = $this->FirstCode;
104
			}
105
			while($this->FirstCode == $this->ClearCode);
106
 
107
			return $this->FirstCode;
108
		}
109
 
110
		if($this->sp > 0) {
111
			$this->sp--;
112
			return $this->Stack[$this->sp];
113
		}
114
 
115
		while(($Code = $this->GetCode($data, $dp)) >= 0) {
116
			if($Code == $this->ClearCode) {
117
				for($i = 0; $i < $this->ClearCode; $i++) {
118
					$this->Next[$i] = 0;
119
					$this->Vals[$i] = $i;
120
				}
121
 
122
				for(; $i < (1 << $this->MAX_LZW_BITS); $i++) {
123
					$this->Next[$i] = 0;
124
					$this->Vals[$i] = 0;
125
				}
126
 
127
				$this->CodeSize    = $this->SetCodeSize + 1;
128
				$this->MaxCodeSize = $this->ClearCode << 1;
129
				$this->MaxCode     = $this->ClearCode + 2;
130
				$this->sp          = 0;
131
				$this->FirstCode   = $this->GetCode($data, $dp);
132
				$this->OldCode     = $this->FirstCode;
133
 
134
				return $this->FirstCode;
135
			}
136
 
137
			if($Code == $this->EndCode) {
138
				return -2;
139
			}
140
 
141
			$InCode = $Code;
142
			if($Code >= $this->MaxCode) {
143
				$this->Stack[$this->sp++] = $this->FirstCode;
144
				$Code = $this->OldCode;
145
			}
146
 
147
			while($Code >= $this->ClearCode) {
148
				$this->Stack[$this->sp++] = $this->Vals[$Code];
149
 
150
				if($Code == $this->Next[$Code]) // Circular table entry, big GIF Error!
151
					return -1;
152
 
153
				$Code = $this->Next[$Code];
154
			}
155
 
156
			$this->FirstCode = $this->Vals[$Code];
157
			$this->Stack[$this->sp++] = $this->FirstCode;
158
 
159
			if(($Code = $this->MaxCode) < (1 << $this->MAX_LZW_BITS)) {
160
				$this->Next[$Code] = $this->OldCode;
161
				$this->Vals[$Code] = $this->FirstCode;
162
				$this->MaxCode++;
163
 
164
				if(($this->MaxCode >= $this->MaxCodeSize) && ($this->MaxCodeSize < (1 << $this->MAX_LZW_BITS))) {
165
					$this->MaxCodeSize *= 2;
166
					$this->CodeSize++;
167
				}
168
			}
169
 
170
			$this->OldCode = $InCode;
171
			if($this->sp > 0) {
172
				$this->sp--;
173
				return $this->Stack[$this->sp];
174
			}
175
		}
176
 
177
		return $Code;
178
	}
179
 
180
	///////////////////////////////////////////////////////////////////////////
181
 
182
	function GetCodeInit(&$data, &$dp)
183
	{
184
			$this->CurBit   = 0;
185
			$this->LastBit  = 0;
186
			$this->Done     = 0;
187
			$this->LastByte = 2;
188
			return 1;
189
	}
190
 
191
	function GetCode(&$data, &$dp)
192
	{
193
		if(($this->CurBit + $this->CodeSize) >= $this->LastBit) {
194
			if($this->Done) {
195
				if($this->CurBit >= $this->LastBit) {
196
					// Ran off the end of my bits
197
					return 0;
198
				}
199
				return -1;
200
			}
201
 
202
			$this->Buf[0] = $this->Buf[$this->LastByte - 2];
203
			$this->Buf[1] = $this->Buf[$this->LastByte - 1];
204
 
205
			$Count = ord($data[$dp]);
206
			$dp += 1;
207
 
208
			if($Count) {
209
				for($i = 0; $i < $Count; $i++) {
210
					$this->Buf[2 + $i] = ord($data[$dp+$i]);
211
				}
212
				$dp += $Count;
213
			}
214
			else {
215
				$this->Done = 1;
216
			}
217
 
218
			$this->LastByte = 2 + $Count;
219
			$this->CurBit   = ($this->CurBit - $this->LastBit) + 16;
220
			$this->LastBit  = (2 + $Count) << 3;
221
		}
222
 
223
		$iRet = 0;
224
		for($i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++) {
225
			$iRet |= (($this->Buf[intval($i / 8)] & (1 << ($i % 8))) != 0) << $j;
226
		}
227
 
228
		$this->CurBit += $this->CodeSize;
229
		return $iRet;
230
	}
231
}
232
 
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234
 
235
class CGIFCOLORTABLE
236
{
237
	var $m_nColors;
238
	var $m_arColors;
239
 
240
	///////////////////////////////////////////////////////////////////////////
241
 
242
	// CONSTRUCTOR
243
	function CGIFCOLORTABLE()
244
	{
245
		unSet($this->m_nColors);
246
		unSet($this->m_arColors);
247
	}
248
 
249
	///////////////////////////////////////////////////////////////////////////
250
 
251
	function load($lpData, $num)
252
	{
253
		$this->m_nColors  = 0;
254
		$this->m_arColors = array();
255
 
256
		for($i = 0; $i < $num; $i++) {
257
			$rgb = substr($lpData, $i * 3, 3);
258
			if(strlen($rgb) < 3) {
259
				return false;
260
			}
261
 
262
			$this->m_arColors[] = (ord($rgb[2]) << 16) + (ord($rgb[1]) << 8) + ord($rgb[0]);
263
			$this->m_nColors++;
264
		}
265
 
266
		return true;
267
	}
268
 
269
	///////////////////////////////////////////////////////////////////////////
270
 
271
	function toString()
272
	{
273
		$ret = "";
274
 
275
		for($i = 0; $i < $this->m_nColors; $i++) {
276
			$ret .=
277
				chr(($this->m_arColors[$i] & 0x000000FF))       . // R
278
				chr(($this->m_arColors[$i] & 0x0000FF00) >>  8) . // G
279
				chr(($this->m_arColors[$i] & 0x00FF0000) >> 16);  // B
280
		}
281
 
282
		return $ret;
283
	}
284
 
285
 
286
	///////////////////////////////////////////////////////////////////////////
287
 
288
	function colorIndex($rgb)
289
	{
290
		$rgb  = intval($rgb) & 0xFFFFFF;
291
		$r1   = ($rgb & 0x0000FF);
292
		$g1   = ($rgb & 0x00FF00) >>  8;
293
		$b1   = ($rgb & 0xFF0000) >> 16;
294
		$idx  = -1;
295
 
296
		for($i = 0; $i < $this->m_nColors; $i++) {
297
			$r2 = ($this->m_arColors[$i] & 0x000000FF);
298
			$g2 = ($this->m_arColors[$i] & 0x0000FF00) >>  8;
299
			$b2 = ($this->m_arColors[$i] & 0x00FF0000) >> 16;
300
			$d  = abs($r2 - $r1) + abs($g2 - $g1) + abs($b2 - $b1);
301
 
302
			if(($idx == -1) || ($d < $dif)) {
303
				$idx = $i;
304
				$dif = $d;
305
			}
306
		}
307
 
308
		return $idx;
309
	}
310
}
311
 
312
///////////////////////////////////////////////////////////////////////////////////////////////////
313
 
314
class CGIFFILEHEADER
315
{
316
	var $m_lpVer;
317
	var $m_nWidth;
318
	var $m_nHeight;
319
	var $m_bGlobalClr;
320
	var $m_nColorRes;
321
	var $m_bSorted;
322
	var $m_nTableSize;
323
	var $m_nBgColor;
324
	var $m_nPixelRatio;
325
	var $m_colorTable;
326
 
327
	///////////////////////////////////////////////////////////////////////////
328
 
329
	// CONSTRUCTOR
330
	function CGIFFILEHEADER()
331
	{
332
		unSet($this->m_lpVer);
333
		unSet($this->m_nWidth);
334
		unSet($this->m_nHeight);
335
		unSet($this->m_bGlobalClr);
336
		unSet($this->m_nColorRes);
337
		unSet($this->m_bSorted);
338
		unSet($this->m_nTableSize);
339
		unSet($this->m_nBgColor);
340
		unSet($this->m_nPixelRatio);
341
		unSet($this->m_colorTable);
342
	}
343
 
344
	///////////////////////////////////////////////////////////////////////////
345
 
346
	function load($lpData, &$hdrLen)
347
	{
348
		$hdrLen = 0;
349
 
350
		$this->m_lpVer = substr($lpData, 0, 6);
351
		if(($this->m_lpVer <> "GIF87a") && ($this->m_lpVer <> "GIF89a")) {
352
			return false;
353
		}
354
 
355
		$this->m_nWidth  = $this->w2i(substr($lpData, 6, 2));
356
		$this->m_nHeight = $this->w2i(substr($lpData, 8, 2));
357
		if(!$this->m_nWidth || !$this->m_nHeight) {
358
			return false;
359
		}
360
 
361
		$b = ord(substr($lpData, 10, 1));
362
		$this->m_bGlobalClr  = ($b & 0x80) ? true : false;
363
		$this->m_nColorRes   = ($b & 0x70) >> 4;
364
		$this->m_bSorted     = ($b & 0x08) ? true : false;
365
		$this->m_nTableSize  = 2 << ($b & 0x07);
366
		$this->m_nBgColor    = ord(substr($lpData, 11, 1));
367
		$this->m_nPixelRatio = ord(substr($lpData, 12, 1));
368
		$hdrLen = 13;
369
 
370
		if($this->m_bGlobalClr) {
371
			$this->m_colorTable = new CGIFCOLORTABLE();
372
			if(!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) {
373
				return false;
374
			}
375
			$hdrLen += 3 * $this->m_nTableSize;
376
		}
377
 
378
		return true;
379
	}
380
 
381
	///////////////////////////////////////////////////////////////////////////
382
 
383
	function w2i($str)
384
	{
385
		return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
386
	}
387
}
388
 
389
///////////////////////////////////////////////////////////////////////////////////////////////////
390
 
391
class CGIFIMAGEHEADER
392
{
393
	var $m_nLeft;
394
	var $m_nTop;
395
	var $m_nWidth;
396
	var $m_nHeight;
397
	var $m_bLocalClr;
398
	var $m_bInterlace;
399
	var $m_bSorted;
400
	var $m_nTableSize;
401
	var $m_colorTable;
402
 
403
	///////////////////////////////////////////////////////////////////////////
404
 
405
	// CONSTRUCTOR
406
	function CGIFIMAGEHEADER()
407
	{
408
		unSet($this->m_nLeft);
409
		unSet($this->m_nTop);
410
		unSet($this->m_nWidth);
411
		unSet($this->m_nHeight);
412
		unSet($this->m_bLocalClr);
413
		unSet($this->m_bInterlace);
414
		unSet($this->m_bSorted);
415
		unSet($this->m_nTableSize);
416
		unSet($this->m_colorTable);
417
	}
418
 
419
	///////////////////////////////////////////////////////////////////////////
420
 
421
	function load($lpData, &$hdrLen)
422
	{
423
		$hdrLen = 0;
424
 
425
		$this->m_nLeft   = $this->w2i(substr($lpData, 0, 2));
426
		$this->m_nTop    = $this->w2i(substr($lpData, 2, 2));
427
		$this->m_nWidth  = $this->w2i(substr($lpData, 4, 2));
428
		$this->m_nHeight = $this->w2i(substr($lpData, 6, 2));
429
 
430
		if(!$this->m_nWidth || !$this->m_nHeight) {
431
			return false;
432
		}
433
 
434
		$b = ord($lpData{8});
435
		$this->m_bLocalClr  = ($b & 0x80) ? true : false;
436
		$this->m_bInterlace = ($b & 0x40) ? true : false;
437
		$this->m_bSorted    = ($b & 0x20) ? true : false;
438
		$this->m_nTableSize = 2 << ($b & 0x07);
439
		$hdrLen = 9;
440
 
441
		if($this->m_bLocalClr) {
442
			$this->m_colorTable = new CGIFCOLORTABLE();
443
			if(!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) {
444
				return false;
445
			}
446
			$hdrLen += 3 * $this->m_nTableSize;
447
		}
448
 
449
		return true;
450
	}
451
 
452
	///////////////////////////////////////////////////////////////////////////
453
 
454
	function w2i($str)
455
	{
456
		return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
457
	}
458
}
459
 
460
///////////////////////////////////////////////////////////////////////////////////////////////////
461
 
462
class CGIFIMAGE
463
{
464
	var $m_disp;
465
	var $m_bUser;
466
	var $m_bTrans;
467
	var $m_nDelay;
468
	var $m_nTrans;
469
	var $m_lpComm;
470
	var $m_gih;
471
	var $m_data;
472
	var $m_lzw;
473
 
474
	///////////////////////////////////////////////////////////////////////////
475
 
476
	function CGIFIMAGE()
477
	{
478
		unSet($this->m_disp);
479
		unSet($this->m_bUser);
480
		unSet($this->m_bTrans);
481
		unSet($this->m_nDelay);
482
		unSet($this->m_nTrans);
483
		unSet($this->m_lpComm);
484
		unSet($this->m_data);
485
		$this->m_gih = new CGIFIMAGEHEADER();
486
		$this->m_lzw = new CGIFLZW();
487
	}
488
 
489
	///////////////////////////////////////////////////////////////////////////
490
 
491
	function load($data, &$datLen)
492
	{
493
		$datLen = 0;
494
 
495
		while(true) {
496
			$b = ord($data[0]);
497
			$data = substr($data, 1);
498
			$datLen++;
499
 
500
			switch($b) {
501
			case 0x21: // Extension
502
				$len = 0;
503
				if(!$this->skipExt($data, $len)) {
504
					return false;
505
				}
506
				$datLen += $len;
507
				break;
508
 
509
			case 0x2C: // Image
510
				// LOAD HEADER & COLOR TABLE
511
				$len = 0;
512
				if(!$this->m_gih->load($data, $len)) {
513
					return false;
514
				}
515
				$data = substr($data, $len);
516
				$datLen += $len;
517
 
518
				// ALLOC BUFFER
519
				$len = 0;
520
 
521
				if(!($this->m_data = $this->m_lzw->deCompress($data, $len))) {
522
					return false;
523
				}
524
 
525
				$data = substr($data, $len);
526
				$datLen += $len;
527
 
528
				if($this->m_gih->m_bInterlace) {
529
					$this->deInterlace();
530
				}
531
 
532
				return true;
533
 
534
			case 0x3B: // EOF
535
			default:
536
				return false;
537
			}
538
		}
539
		return false;
540
	}
541
 
542
	///////////////////////////////////////////////////////////////////////////
543
 
544
	function skipExt(&$data, &$extLen)
545
	{
546
		$extLen = 0;
547
 
548
		$b = ord($data[0]);
549
		$data = substr($data, 1);
550
		$extLen++;
551
 
552
		switch($b) {
553
		case 0xF9: // Graphic Control
554
			$b = ord($data[1]);
555
			$this->m_disp   = ($b & 0x1C) >> 2;
556
			$this->m_bUser  = ($b & 0x02) ? true : false;
557
			$this->m_bTrans = ($b & 0x01) ? true : false;
558
			$this->m_nDelay = $this->w2i(substr($data, 2, 2));
559
			$this->m_nTrans = ord($data[4]);
560
			break;
561
 
562
		case 0xFE: // Comment
563
			$this->m_lpComm = substr($data, 1, ord($data[0]));
564
			break;
565
 
566
		case 0x01: // Plain text
567
			break;
568
 
569
		case 0xFF: // Application
570
			break;
571
		}
572
 
573
		// SKIP DEFAULT AS DEFS MAY CHANGE
574
		$b = ord($data[0]);
575
		$data = substr($data, 1);
576
		$extLen++;
577
		while($b > 0) {
578
			$data = substr($data, $b);
579
			$extLen += $b;
580
			$b    = ord($data[0]);
581
			$data = substr($data, 1);
582
			$extLen++;
583
		}
584
		return true;
585
	}
586
 
587
	///////////////////////////////////////////////////////////////////////////
588
 
589
	function w2i($str)
590
	{
591
		return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
592
	}
593
 
594
	///////////////////////////////////////////////////////////////////////////
595
 
596
	function deInterlace()
597
	{
598
		$data = $this->m_data;
599
 
600
		for($i = 0; $i < 4; $i++) {
601
			switch($i) {
602
			case 0:
603
				$s = 8;
604
				$y = 0;
605
				break;
606
 
607
			case 1:
608
				$s = 8;
609
				$y = 4;
610
				break;
611
 
612
			case 2:
613
				$s = 4;
614
				$y = 2;
615
				break;
616
 
617
			case 3:
618
				$s = 2;
619
				$y = 1;
620
				break;
621
			}
622
 
623
			for(; $y < $this->m_gih->m_nHeight; $y += $s) {
624
				$lne = substr($this->m_data, 0, $this->m_gih->m_nWidth);
625
				$this->m_data = substr($this->m_data, $this->m_gih->m_nWidth);
626
 
627
				$data =
628
					substr($data, 0, $y * $this->m_gih->m_nWidth) .
629
					$lne .
630
					substr($data, ($y + 1) * $this->m_gih->m_nWidth);
631
			}
632
		}
633
 
634
		$this->m_data = $data;
635
	}
636
}
637
 
638
///////////////////////////////////////////////////////////////////////////////////////////////////
639
 
640
class CGIF
641
{
642
	var $m_gfh;
643
	var $m_lpData;
644
	var $m_img;
645
	var $m_bLoaded;
646
 
647
	///////////////////////////////////////////////////////////////////////////
648
 
649
	// CONSTRUCTOR
650
	function CGIF()
651
	{
652
		$this->m_gfh     = new CGIFFILEHEADER();
653
		$this->m_img     = new CGIFIMAGE();
654
		$this->m_lpData  = "";
655
		$this->m_bLoaded = false;
656
	}
657
 
658
	///////////////////////////////////////////////////////////////////////////
659
	function ClearData() {
660
		$this->m_lpData = '';
661
		unSet($this->m_img->m_data);
662
		unSet($this->m_img->m_lzw->Next);
663
		unSet($this->m_img->m_lzw->Vals);
664
		unSet($this->m_img->m_lzw->Stack);
665
		unSet($this->m_img->m_lzw->Buf);
666
	}
667
 
668
	function loadFile(&$data, $iIndex)
669
	{
670
		if($iIndex < 0) {
671
			return false;
672
		}
673
		$this->m_lpData = $data;
674
 
675
		// GET FILE HEADER
676
		$len = 0;
677
		if(!$this->m_gfh->load($this->m_lpData, $len)) {
678
			return false;
679
		}
680
 
681
		$this->m_lpData = substr($this->m_lpData, $len);
682
 
683
		do {
684
			$imgLen = 0;
685
			if(!$this->m_img->load($this->m_lpData, $imgLen)) {
686
				return false;
687
			}
688
			$this->m_lpData = substr($this->m_lpData, $imgLen);
689
		}
690
		while($iIndex-- > 0);
691
 
692
		$this->m_bLoaded = true;
693
		return true;
694
	}
695
 
696
}
697
 
698
///////////////////////////////////////////////////////////////////////////////////////////////////
699
 
700
?>