Passed
Push — master ( 005d4f...8b5e26 )
by Michael
06:49
created

CGIF   F

Complexity

Total Complexity 67

Size/Duplication

Total Lines 405
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 198
c 3
b 0
f 0
dl 0
loc 405
rs 3.04
wmc 67

12 Methods

Rating   Name   Duplication   Size   Complexity  
A ndword() 0 5 1
A dword() 0 5 1
D getPng() 0 96 18
A loaded() 0 3 1
C getGD_PixelPlotterVersion() 0 49 14
A comment() 0 3 1
A __construct() 0 6 1
F getBmp() 0 95 19
A height() 0 3 1
A width() 0 3 1
A getSize() 0 17 3
A loadFile() 0 29 6

How to fix   Complexity   

Complex Class

Complex classes like CGIF often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CGIF, and based on these observations, apply Extract Interface, too.

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 <[email protected]> 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
/**
25
 * @param     $lpszFileName
26
 * @param int $iIndex
27
 * @return bool|\CGIF
28
 */
29
function gif_loadFile($lpszFileName, $iIndex = 0)
30
{
31
    $gif = new CGIF();
32
    if ($gif->loadFile($lpszFileName, $iIndex)) {
33
        return $gif;
34
    }
35
36
    return false;
37
}
38
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40
41
// Added by James Heinrich <[email protected]> - December 10, 2003
42
/**
43
 * @param     $gifFilename
44
 * @param int $bgColor
45
 * @return bool|resource
46
 */
47
function gif_loadFileToGDimageResource($gifFilename, $bgColor = -1)
48
{
49
    if ($gif = gif_loadFile($gifFilename)) {
50
        if (!phpthumb_functions::FunctionIsDisabled('set_time_limit')) {
51
            // shouldn't take nearly this long
52
            set_time_limit(120);
53
        }
54
        // general strategy: convert raw data to PNG then convert PNG data to GD image resource
55
        $PNGdata = $gif->getPng($bgColor);
56
        if ($img = @imagecreatefromstring($PNGdata)) {
57
58
            // excellent - PNG image data successfully converted to GD image
59
            return $img;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $img also could return the type GdImage which is incompatible with the documented return type boolean|resource.
Loading history...
60
        } elseif ($img = $gif->getGD_PixelPlotterVersion()) {
61
62
            // problem: imagecreatefromstring() didn't like the PNG image data.
63
            //   This has been known to happen in PHP v4.0.6
64
            // solution: take the raw image data and create a new GD image and plot
65
            //   pixel-by-pixel on the GD image. This is extremely slow, but it does
66
            //   work and a slow solution is better than no solution, right? :)
67
            return $img;
68
        }
69
    }
70
71
    return false;
72
}
73
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75
76
/**
77
 * @param     $gif
78
 * @param     $lpszFileName
79
 * @param int $bgColor
80
 * @return bool
81
 */
82
function gif_outputAsBmp($gif, $lpszFileName, $bgColor = -1)
83
{
84
    if (!isset($gif) || ('cgif' !== @get_class($gif)) || !$gif->loaded() || ('' == $lpszFileName)) {
85
        return false;
86
    }
87
88
    $fd = $gif->getBmp($bgColor);
89
    if (strlen($fd) <= 0) {
90
        return false;
91
    }
92
93
    if (!($fh = @fopen($lpszFileName, 'wb'))) {
94
        return false;
95
    }
96
    @fwrite($fh, $fd, strlen($fd));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fwrite(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

96
    /** @scrutinizer ignore-unhandled */ @fwrite($fh, $fd, strlen($fd));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
97
    @fflush($fh);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fflush(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

97
    /** @scrutinizer ignore-unhandled */ @fflush($fh);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
98
    @fclose($fh);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fclose(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

98
    /** @scrutinizer ignore-unhandled */ @fclose($fh);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
99
100
    return true;
101
}
102
103
///////////////////////////////////////////////////////////////////////////////////////////////////
104
105
/**
106
 * @param     $gif
107
 * @param     $lpszFileName
108
 * @param int $bgColor
109
 * @return bool
110
 */
111
function gif_outputAsPng($gif, $lpszFileName, $bgColor = -1)
112
{
113
    if (!isset($gif) || ('cgif' !== @get_class($gif)) || !$gif->loaded() || ('' == $lpszFileName)) {
114
        return false;
115
    }
116
117
    $fd = $gif->getPng($bgColor);
118
    if (strlen($fd) <= 0) {
119
        return false;
120
    }
121
122
    if (!($fh = @fopen($lpszFileName, 'wb'))) {
123
        return false;
124
    }
125
    @fwrite($fh, $fd, strlen($fd));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fwrite(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

125
    /** @scrutinizer ignore-unhandled */ @fwrite($fh, $fd, strlen($fd));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
126
    @fflush($fh);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fflush(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

126
    /** @scrutinizer ignore-unhandled */ @fflush($fh);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
127
    @fclose($fh);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fclose(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

127
    /** @scrutinizer ignore-unhandled */ @fclose($fh);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
128
129
    return true;
130
}
131
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133
134
/**
135
 * @param     $gif
136
 * @param     $lpszFileName
137
 * @param int $bgColor
138
 * @return bool
139
 */
140
function gif_outputAsJpeg($gif, $lpszFileName, $bgColor = -1)
141
{
142
    // JPEG output that does not require cjpeg added by James Heinrich <[email protected]> - December 10, 2003
143
    if (('WIN' !== strtoupper(substr(PHP_OS, 0, 3))) && (file_exists('/usr/local/bin/cjpeg') || shell_exec('which cjpeg'))) {
144
        if (gif_outputAsBmp($gif, $lpszFileName . '.bmp', $bgColor)) {
145
            exec('cjpeg ' . $lpszFileName . '.bmp >' . $lpszFileName . ' 2>/dev/null');
146
            @unlink($lpszFileName . '.bmp');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

146
            /** @scrutinizer ignore-unhandled */ @unlink($lpszFileName . '.bmp');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
147
148
            if (@file_exists($lpszFileName)) {
149
                if (@filesize($lpszFileName) > 0) {
150
                    return true;
151
                }
152
153
                @unlink($lpszFileName);
154
            }
155
        }
156
    } else {
157
158
        // either Windows, or cjpeg not found in path
159
        if ($img = @imagecreatefromstring($gif->getPng($bgColor))) {
160
            if (@imagejpeg($img, $lpszFileName)) {
161
                return true;
162
            }
163
        }
164
    }
165
166
    return false;
167
}
168
169
///////////////////////////////////////////////////////////////////////////////////////////////////
170
171
/**
172
 * @param $gif
173
 * @param $width
174
 * @param $height
175
 * @return bool
176
 */
177
function gif_getSize($gif, &$width, &$height)
178
{
179
    if (isset($gif) && ('cgif' === @get_class($gif)) && $gif->loaded()) {
180
        $width  = $gif->width();
181
        $height = $gif->height();
182
    } elseif (@file_exists($gif)) {
183
        $myGIF = new CGIF();
184
        if (!$myGIF->getSize($gif, $width, $height)) {
185
            return false;
186
        }
187
    } else {
188
        return false;
189
    }
190
191
    return true;
192
}
193
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195
196
/**
197
 * Class CGIFLZW
198
 */
199
class CGIFLZW
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
200
{
201
    public $MAX_LZW_BITS;
202
    public $Fresh;
203
    public $CodeSize;
204
    public $SetCodeSize;
205
    public $MaxCode;
206
    public $MaxCodeSize;
207
    public $FirstCode;
208
    public $OldCode;
209
    public $ClearCode;
210
    public $EndCode;
211
    public $Next;
212
    public $Vals;
213
    public $Stack;
214
    public $sp;
215
    public $Buf;
216
    public $CurBit;
217
    public $LastBit;
218
    public $Done;
219
    public $LastByte;
220
221
    ///////////////////////////////////////////////////////////////////////////
222
223
    // CONSTRUCTOR
224
    public function __construct()
225
    {
226
        $this->MAX_LZW_BITS = 12;
227
        unset($this->Next);
228
        unset($this->Vals);
229
        unset($this->Stack);
230
        unset($this->Buf);
231
232
        $this->Next  = range(0, (1 << $this->MAX_LZW_BITS) - 1);
233
        $this->Vals  = range(0, (1 << $this->MAX_LZW_BITS) - 1);
234
        $this->Stack = range(0, (1 << ($this->MAX_LZW_BITS + 1)) - 1);
235
        $this->Buf   = range(0, 279);
236
    }
237
238
    ///////////////////////////////////////////////////////////////////////////
239
240
    /**
241
     * @param $data
242
     * @param $datLen
243
     * @return bool|string
244
     */
245
    public function deCompress($data, &$datLen)
246
    {
247
        $stLen  = strlen($data);
248
        $datLen = 0;
249
        $ret    = '';
250
251
        // INITIALIZATION
252
        $this->LZWCommand($data, true);
253
254
        while (($iIndex = $this->LZWCommand($data, false)) >= 0) {
255
            $ret .= chr($iIndex);
256
        }
257
258
        $datLen = $stLen - strlen($data);
259
260
        if (-2 != $iIndex) {
261
            return false;
262
        }
263
264
        return $ret;
265
    }
266
267
    ///////////////////////////////////////////////////////////////////////////
268
269
    /**
270
     * @param $data
271
     * @param $bInit
272
     * @return int
273
     */
274
    public function LZWCommand(&$data, $bInit)
275
    {
276
        if ($bInit) {
277
            $this->SetCodeSize = ord($data{0});
278
            $data              = substr($data, 1);
279
280
            $this->CodeSize    = $this->SetCodeSize + 1;
281
            $this->ClearCode   = 1 << $this->SetCodeSize;
282
            $this->EndCode     = $this->ClearCode + 1;
283
            $this->MaxCode     = $this->ClearCode + 2;
284
            $this->MaxCodeSize = $this->ClearCode << 1;
285
286
            $this->GetCode($data, $bInit);
287
288
            $this->Fresh = 1;
289
            for ($i = 0; $i < $this->ClearCode; $i++) {
290
                $this->Next[$i] = 0;
291
                $this->Vals[$i] = $i;
292
            }
293
294
            for (; $i < (1 << $this->MAX_LZW_BITS); $i++) {
295
                $this->Next[$i] = 0;
296
                $this->Vals[$i] = 0;
297
            }
298
299
            $this->sp = 0;
300
301
            return 1;
302
        }
303
304
        if ($this->Fresh) {
305
            $this->Fresh = 0;
306
            do {
307
                $this->FirstCode = $this->GetCode($data, $bInit);
308
                $this->OldCode   = $this->FirstCode;
309
            } while ($this->FirstCode == $this->ClearCode);
310
311
            return $this->FirstCode;
312
        }
313
314
        if ($this->sp > 0) {
315
            $this->sp--;
316
317
            return $this->Stack[$this->sp];
318
        }
319
320
        while (($Code = $this->GetCode($data, $bInit)) >= 0) {
321
            if ($Code == $this->ClearCode) {
322
                for ($i = 0; $i < $this->ClearCode; $i++) {
323
                    $this->Next[$i] = 0;
324
                    $this->Vals[$i] = $i;
325
                }
326
327
                for (; $i < (1 << $this->MAX_LZW_BITS); $i++) {
328
                    $this->Next[$i] = 0;
329
                    $this->Vals[$i] = 0;
330
                }
331
332
                $this->CodeSize    = $this->SetCodeSize + 1;
333
                $this->MaxCodeSize = $this->ClearCode << 1;
334
                $this->MaxCode     = $this->ClearCode + 2;
335
                $this->sp          = 0;
336
                $this->FirstCode   = $this->GetCode($data, $bInit);
337
                $this->OldCode     = $this->FirstCode;
338
339
                return $this->FirstCode;
340
            }
341
342
            if ($Code == $this->EndCode) {
343
                return -2;
344
            }
345
346
            $InCode = $Code;
347
            if ($Code >= $this->MaxCode) {
348
                $this->Stack[$this->sp] = $this->FirstCode;
349
                $this->sp++;
350
                $Code = $this->OldCode;
351
            }
352
353
            while ($Code >= $this->ClearCode) {
354
                $this->Stack[$this->sp] = $this->Vals[$Code];
355
                $this->sp++;
356
357
                if ($Code == $this->Next[$Code]) { // Circular table entry, big GIF Error!
358
                    return -1;
359
                }
360
361
                $Code = $this->Next[$Code];
362
            }
363
364
            $this->FirstCode        = $this->Vals[$Code];
365
            $this->Stack[$this->sp] = $this->FirstCode;
366
            $this->sp++;
367
368
            if (($Code = $this->MaxCode) < (1 << $this->MAX_LZW_BITS)) {
369
                $this->Next[$Code] = $this->OldCode;
370
                $this->Vals[$Code] = $this->FirstCode;
371
                $this->MaxCode++;
372
373
                if (($this->MaxCode >= $this->MaxCodeSize) && ($this->MaxCodeSize < (1 << $this->MAX_LZW_BITS))) {
374
                    $this->MaxCodeSize *= 2;
375
                    $this->CodeSize++;
376
                }
377
            }
378
379
            $this->OldCode = $InCode;
380
            if ($this->sp > 0) {
381
                $this->sp--;
382
383
                return $this->Stack[$this->sp];
384
            }
385
        }
386
387
        return $Code;
388
    }
389
390
    ///////////////////////////////////////////////////////////////////////////
391
392
    /**
393
     * @param $data
394
     * @param $bInit
395
     * @return int
396
     */
397
    public function GetCode(&$data, $bInit)
398
    {
399
        if ($bInit) {
400
            $this->CurBit   = 0;
401
            $this->LastBit  = 0;
402
            $this->Done     = 0;
403
            $this->LastByte = 2;
404
405
            return 1;
406
        }
407
408
        if (($this->CurBit + $this->CodeSize) >= $this->LastBit) {
409
            if ($this->Done) {
410
                if ($this->CurBit >= $this->LastBit) {
411
                    // Ran off the end of my bits
412
                    return 0;
413
                }
414
415
                return -1;
416
            }
417
418
            $this->Buf[0] = $this->Buf[$this->LastByte - 2];
419
            $this->Buf[1] = $this->Buf[$this->LastByte - 1];
420
421
            $Count = ord($data{0});
422
            $data  = substr($data, 1);
423
424
            if ($Count) {
425
                for ($i = 0; $i < $Count; $i++) {
426
                    $this->Buf[2 + $i] = ord($data{$i});
427
                }
428
                $data = substr($data, $Count);
429
            } else {
430
                $this->Done = 1;
431
            }
432
433
            $this->LastByte = 2 + $Count;
434
            $this->CurBit   = ($this->CurBit - $this->LastBit) + 16;
435
            $this->LastBit  = (2 + $Count) << 3;
436
        }
437
438
        $iRet = 0;
439
        for ($i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++) {
440
            $iRet |= (0 != ($this->Buf[(int)($i / 8)] & (1 << ($i % 8)))) << $j;
441
        }
442
443
        $this->CurBit += $this->CodeSize;
444
445
        return $iRet;
446
    }
447
}
448
449
///////////////////////////////////////////////////////////////////////////////////////////////////
450
451
/**
452
 * Class CGIFCOLORTABLE
453
 */
454
class CGIFCOLORTABLE
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
455
{
456
    public $m_nColors;
457
    public $m_arColors;
458
459
    ///////////////////////////////////////////////////////////////////////////
460
461
    // CONSTRUCTOR
462
    public function __construct()
463
    {
464
        unset($this->m_nColors);
465
        unset($this->m_arColors);
466
    }
467
468
    ///////////////////////////////////////////////////////////////////////////
469
470
    /**
471
     * @param $lpData
472
     * @param $num
473
     * @return bool
474
     */
475
    public function load($lpData, $num)
476
    {
477
        $this->m_nColors  = 0;
478
        $this->m_arColors = [];
479
480
        for ($i = 0; $i < $num; $i++) {
481
            $rgb = substr($lpData, $i * 3, 3);
482
            if (strlen($rgb) < 3) {
483
                return false;
484
            }
485
486
            $this->m_arColors[] = (ord($rgb{2}) << 16) + (ord($rgb{1}) << 8) + ord($rgb{0});
487
            $this->m_nColors++;
488
        }
489
490
        return true;
491
    }
492
493
    ///////////////////////////////////////////////////////////////////////////
494
495
    /**
496
     * @return string
497
     */
498
    public function toString()
499
    {
500
        $ret = '';
501
502
        for ($i = 0; $i < $this->m_nColors; $i++) {
503
            $ret .= chr($this->m_arColors[$i] & 0x000000FF) . // R
504
                    chr(($this->m_arColors[$i] & 0x0000FF00) >> 8) . // G
505
                    chr(($this->m_arColors[$i] & 0x00FF0000) >> 16);  // B
506
        }
507
508
        return $ret;
509
    }
510
511
    ///////////////////////////////////////////////////////////////////////////
512
513
    /**
514
     * @return string
515
     */
516
    public function toRGBQuad()
517
    {
518
        $ret = '';
519
520
        for ($i = 0; $i < $this->m_nColors; $i++) {
521
            $ret .= chr(($this->m_arColors[$i] & 0x00FF0000) >> 16) . // B
522
                    chr(($this->m_arColors[$i] & 0x0000FF00) >> 8) . // G
523
                    chr($this->m_arColors[$i] & 0x000000FF) . // R
524
                    "\x00";
525
        }
526
527
        return $ret;
528
    }
529
530
    ///////////////////////////////////////////////////////////////////////////
531
532
    /**
533
     * @param $rgb
534
     * @return int
535
     */
536
    public function colorIndex($rgb)
537
    {
538
        $rgb = (int)$rgb & 0xFFFFFF;
539
        $r1  = ($rgb & 0x0000FF);
540
        $g1  = ($rgb & 0x00FF00) >> 8;
541
        $b1  = ($rgb & 0xFF0000) >> 16;
542
        $idx = -1;
543
        $dif = 0;
544
545
        for ($i = 0; $i < $this->m_nColors; $i++) {
546
            $r2 = ($this->m_arColors[$i] & 0x000000FF);
547
            $g2 = ($this->m_arColors[$i] & 0x0000FF00) >> 8;
548
            $b2 = ($this->m_arColors[$i] & 0x00FF0000) >> 16;
549
            $d  = abs($r2 - $r1) + abs($g2 - $g1) + abs($b2 - $b1);
550
551
            if ((-1 == $idx) || ($d < $dif)) {
552
                $idx = $i;
553
                $dif = $d;
554
            }
555
        }
556
557
        return $idx;
558
    }
559
}
560
561
///////////////////////////////////////////////////////////////////////////////////////////////////
562
563
/**
564
 * Class CGIFFILEHEADER
565
 */
566
class CGIFFILEHEADER
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
567
{
568
    public $m_lpVer;
569
    public $m_nWidth;
570
    public $m_nHeight;
571
    public $m_bGlobalClr;
572
    public $m_nColorRes;
573
    public $m_bSorted;
574
    public $m_nTableSize;
575
    public $m_nBgColor;
576
    public $m_nPixelRatio;
577
    public $m_colorTable;
578
579
    ///////////////////////////////////////////////////////////////////////////
580
581
    // CONSTRUCTOR
582
    public function __construct()
583
    {
584
        unset($this->m_lpVer);
585
        unset($this->m_nWidth);
586
        unset($this->m_nHeight);
587
        unset($this->m_bGlobalClr);
588
        unset($this->m_nColorRes);
589
        unset($this->m_bSorted);
590
        unset($this->m_nTableSize);
591
        unset($this->m_nBgColor);
592
        unset($this->m_nPixelRatio);
593
        unset($this->m_colorTable);
594
    }
595
596
    ///////////////////////////////////////////////////////////////////////////
597
598
    /**
599
     * @param $lpData
600
     * @param $hdrLen
601
     * @return bool
602
     */
603
    public function load($lpData, &$hdrLen)
604
    {
605
        $hdrLen = 0;
606
607
        $this->m_lpVer = substr($lpData, 0, 6);
608
        if (('GIF87a' !== $this->m_lpVer) && ('GIF89a' !== $this->m_lpVer)) {
609
            return false;
610
        }
611
612
        $this->m_nWidth  = $this->w2i(substr($lpData, 6, 2));
613
        $this->m_nHeight = $this->w2i(substr($lpData, 8, 2));
614
        if (!$this->m_nWidth || !$this->m_nHeight) {
615
            return false;
616
        }
617
618
        $b                   = ord(substr($lpData, 10, 1));
619
        $this->m_bGlobalClr  = ($b & 0x80) ? true : false;
620
        $this->m_nColorRes   = ($b & 0x70) >> 4;
621
        $this->m_bSorted     = ($b & 0x08) ? true : false;
622
        $this->m_nTableSize  = 2 << ($b & 0x07);
623
        $this->m_nBgColor    = ord(substr($lpData, 11, 1));
624
        $this->m_nPixelRatio = ord(substr($lpData, 12, 1));
625
        $hdrLen              = 13;
626
627
        if ($this->m_bGlobalClr) {
628
            $this->m_colorTable = new CGIFCOLORTABLE();
629
            if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) {
630
                return false;
631
            }
632
            $hdrLen += 3 * $this->m_nTableSize;
633
        }
634
635
        return true;
636
    }
637
638
    ///////////////////////////////////////////////////////////////////////////
639
640
    /**
641
     * @param $str
642
     * @return int
643
     */
644
    public function w2i($str)
645
    {
646
        return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
647
    }
648
}
649
650
///////////////////////////////////////////////////////////////////////////////////////////////////
651
652
/**
653
 * Class CGIFIMAGEHEADER
654
 */
655
class CGIFIMAGEHEADER
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
656
{
657
    public $m_nLeft;
658
    public $m_nTop;
659
    public $m_nWidth;
660
    public $m_nHeight;
661
    public $m_bLocalClr;
662
    public $m_bInterlace;
663
    public $m_bSorted;
664
    public $m_nTableSize;
665
    public $m_colorTable;
666
667
    ///////////////////////////////////////////////////////////////////////////
668
669
    // CONSTRUCTOR
670
    public function __construct()
671
    {
672
        unset($this->m_nLeft);
673
        unset($this->m_nTop);
674
        unset($this->m_nWidth);
675
        unset($this->m_nHeight);
676
        unset($this->m_bLocalClr);
677
        unset($this->m_bInterlace);
678
        unset($this->m_bSorted);
679
        unset($this->m_nTableSize);
680
        unset($this->m_colorTable);
681
    }
682
683
    ///////////////////////////////////////////////////////////////////////////
684
685
    /**
686
     * @param $lpData
687
     * @param $hdrLen
688
     * @return bool
689
     */
690
    public function load($lpData, &$hdrLen)
691
    {
692
        $hdrLen = 0;
693
694
        $this->m_nLeft   = $this->w2i(substr($lpData, 0, 2));
695
        $this->m_nTop    = $this->w2i(substr($lpData, 2, 2));
696
        $this->m_nWidth  = $this->w2i(substr($lpData, 4, 2));
697
        $this->m_nHeight = $this->w2i(substr($lpData, 6, 2));
698
699
        if (!$this->m_nWidth || !$this->m_nHeight) {
700
            return false;
701
        }
702
703
        $b                  = ord($lpData{8});
704
        $this->m_bLocalClr  = ($b & 0x80) ? true : false;
705
        $this->m_bInterlace = ($b & 0x40) ? true : false;
706
        $this->m_bSorted    = ($b & 0x20) ? true : false;
707
        $this->m_nTableSize = 2 << ($b & 0x07);
708
        $hdrLen             = 9;
709
710
        if ($this->m_bLocalClr) {
711
            $this->m_colorTable = new CGIFCOLORTABLE();
712
            if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) {
713
                return false;
714
            }
715
            $hdrLen += 3 * $this->m_nTableSize;
716
        }
717
718
        return true;
719
    }
720
721
    ///////////////////////////////////////////////////////////////////////////
722
723
    /**
724
     * @param $str
725
     * @return int
726
     */
727
    public function w2i($str)
728
    {
729
        return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
730
    }
731
}
732
733
///////////////////////////////////////////////////////////////////////////////////////////////////
734
735
/**
736
 * Class CGIFIMAGE
737
 */
738
class CGIFIMAGE
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
739
{
740
    public $m_disp;
741
    public $m_bUser;
742
    public $m_bTrans;
743
    public $m_nDelay;
744
    public $m_nTrans;
745
    public $m_lpComm;
746
    public $m_gih;
747
    public $m_data;
748
    public $m_lzw;
749
750
    ///////////////////////////////////////////////////////////////////////////
751
752
    public function __construct()
753
    {
754
        unset($this->m_disp);
755
        unset($this->m_bUser);
756
        unset($this->m_bTrans);
757
        unset($this->m_nDelay);
758
        unset($this->m_nTrans);
759
        unset($this->m_lpComm);
760
        unset($this->m_data);
761
        $this->m_gih = new CGIFIMAGEHEADER();
762
        $this->m_lzw = new CGIFLZW();
763
    }
764
765
    ///////////////////////////////////////////////////////////////////////////
766
767
    /**
768
     * @param $data
769
     * @param $datLen
770
     * @return bool
771
     */
772
    public function load($data, &$datLen)
773
    {
774
        $datLen = 0;
775
776
        while (true) {
777
            $b    = ord($data{0});
778
            $data = substr($data, 1);
779
            $datLen++;
780
781
            switch ($b) {
782
                case 0x21: // Extension
783
                    if (!$this->skipExt($data, $len = 0)) {
0 ignored issues
show
Bug introduced by
$len = 0 cannot be passed to CGIFIMAGE::skipExt() as the parameter $extLen expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

783
                    if (!$this->skipExt($data, /** @scrutinizer ignore-type */ $len = 0)) {
Loading history...
784
                        return false;
785
                    }
786
                    $datLen += $len;
787
                    break;
788
789
                case 0x2C: // Image
790
                    // LOAD HEADER & COLOR TABLE
791
                    if (!$this->m_gih->load($data, $len = 0)) {
0 ignored issues
show
Bug introduced by
$len = 0 cannot be passed to CGIFIMAGEHEADER::load() as the parameter $hdrLen expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

791
                    if (!$this->m_gih->load($data, /** @scrutinizer ignore-type */ $len = 0)) {
Loading history...
792
                        return false;
793
                    }
794
                    $data   = substr($data, $len);
795
                    $datLen += $len;
796
797
                    // ALLOC BUFFER
798
                    if (!($this->m_data = $this->m_lzw->deCompress($data, $len = 0))) {
0 ignored issues
show
Bug introduced by
$len = 0 cannot be passed to CGIFLZW::deCompress() as the parameter $datLen expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

798
                    if (!($this->m_data = $this->m_lzw->deCompress($data, /** @scrutinizer ignore-type */ $len = 0))) {
Loading history...
799
                        return false;
800
                    }
801
                    $data   = substr($data, $len);
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
802
                    $datLen += $len;
803
804
                    if ($this->m_gih->m_bInterlace) {
805
                        $this->deInterlace();
806
                    }
807
808
                    return true;
809
810
                case 0x3B: // EOF
811
                default:
812
                    return false;
813
            }
814
        }
815
816
        return false;
817
    }
818
819
    ///////////////////////////////////////////////////////////////////////////
820
821
    /**
822
     * @param $data
823
     * @param $extLen
824
     * @return bool
825
     */
826
    public function skipExt(&$data, &$extLen)
827
    {
828
        $extLen = 0;
829
830
        $b    = ord($data{0});
831
        $data = substr($data, 1);
832
        $extLen++;
833
834
        switch ($b) {
835
            case 0xF9: // Graphic Control
836
                $b              = ord($data{1});
837
                $this->m_disp   = ($b & 0x1C) >> 2;
838
                $this->m_bUser  = ($b & 0x02) ? true : false;
839
                $this->m_bTrans = ($b & 0x01) ? true : false;
840
                $this->m_nDelay = $this->w2i(substr($data, 2, 2));
841
                $this->m_nTrans = ord($data{4});
842
                break;
843
844
            case 0xFE: // Comment
845
                $this->m_lpComm = substr($data, 1, ord($data{0}));
846
                break;
847
848
            case 0x01: // Plain text
849
                break;
850
851
            case 0xFF: // Application
852
                break;
853
        }
854
855
        // SKIP DEFAULT AS DEFS MAY CHANGE
856
        $b    = ord($data{0});
857
        $data = substr($data, 1);
858
        $extLen++;
859
        while ($b > 0) {
860
            $data   = substr($data, $b);
861
            $extLen += $b;
862
            $b      = ord($data{0});
863
            $data   = substr($data, 1);
864
            $extLen++;
865
        }
866
867
        return true;
868
    }
869
870
    ///////////////////////////////////////////////////////////////////////////
871
872
    /**
873
     * @param $str
874
     * @return int
875
     */
876
    public function w2i($str)
877
    {
878
        return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
879
    }
880
881
    ///////////////////////////////////////////////////////////////////////////
882
883
    public function deInterlace()
884
    {
885
        $data = $this->m_data;
886
        $s    = 0;
887
        $y    = 0;
888
889
        for ($i = 0; $i < 4; $i++) {
890
            switch ($i) {
891
                case 0:
892
                    $s = 8;
893
                    $y = 0;
894
                    break;
895
896
                case 1:
897
                    $s = 8;
898
                    $y = 4;
899
                    break;
900
901
                case 2:
902
                    $s = 4;
903
                    $y = 2;
904
                    break;
905
906
                case 3:
907
                    $s = 2;
908
                    $y = 1;
909
                    break;
910
            }
911
912
            for (; $y < $this->m_gih->m_nHeight; $y += $s) {
913
                $lne          = substr($this->m_data, 0, $this->m_gih->m_nWidth);
914
                $this->m_data = substr($this->m_data, $this->m_gih->m_nWidth);
915
916
                $data = substr($data, 0, $y * $this->m_gih->m_nWidth) . $lne . substr($data, ($y + 1) * $this->m_gih->m_nWidth);
917
            }
918
        }
919
920
        $this->m_data = $data;
921
    }
922
}
923
924
///////////////////////////////////////////////////////////////////////////////////////////////////
925
926
/**
927
 * Class CGIF
928
 */
929
class CGIF
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
930
{
931
    public $m_gfh;
932
    public $m_lpData;
933
    public $m_img;
934
    public $m_bLoaded;
935
936
    ///////////////////////////////////////////////////////////////////////////
937
938
    // CONSTRUCTOR
939
    public function __construct()
940
    {
941
        $this->m_gfh     = new CGIFFILEHEADER();
942
        $this->m_img     = new CGIFIMAGE();
943
        $this->m_lpData  = '';
944
        $this->m_bLoaded = false;
945
    }
946
947
    ///////////////////////////////////////////////////////////////////////////
948
949
    /**
950
     * @param $lpszFileName
951
     * @param $iIndex
952
     * @return bool
953
     */
954
    public function loadFile($lpszFileName, $iIndex)
955
    {
956
        if ($iIndex < 0) {
957
            return false;
958
        }
959
960
        // READ FILE
961
        if (!($fh = @fopen($lpszFileName, 'rb'))) {
962
            return false;
963
        }
964
        $this->m_lpData = @fread($fh, @filesize($lpszFileName));
0 ignored issues
show
Bug introduced by
It seems like @filesize($lpszFileName) can also be of type false; however, parameter $length of fread() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

964
        $this->m_lpData = @fread($fh, /** @scrutinizer ignore-type */ @filesize($lpszFileName));
Loading history...
965
        fclose($fh);
966
967
        // GET FILE HEADER
968
        if (!$this->m_gfh->load($this->m_lpData, $len = 0)) {
0 ignored issues
show
Bug introduced by
$len = 0 cannot be passed to CGIFFILEHEADER::load() as the parameter $hdrLen expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

968
        if (!$this->m_gfh->load($this->m_lpData, /** @scrutinizer ignore-type */ $len = 0)) {
Loading history...
969
            return false;
970
        }
971
        $this->m_lpData = substr($this->m_lpData, $len);
0 ignored issues
show
Bug introduced by
It seems like $this->m_lpData can also be of type false; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

971
        $this->m_lpData = substr(/** @scrutinizer ignore-type */ $this->m_lpData, $len);
Loading history...
972
973
        do {
974
            if (!$this->m_img->load($this->m_lpData, $imgLen = 0)) {
0 ignored issues
show
Bug introduced by
$imgLen = 0 cannot be passed to CGIFIMAGE::load() as the parameter $datLen expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

974
            if (!$this->m_img->load($this->m_lpData, /** @scrutinizer ignore-type */ $imgLen = 0)) {
Loading history...
975
                return false;
976
            }
977
            $this->m_lpData = substr($this->m_lpData, $imgLen);
978
        } while ($iIndex-- > 0);
979
980
        $this->m_bLoaded = true;
981
982
        return true;
983
    }
984
985
    ///////////////////////////////////////////////////////////////////////////
986
987
    /**
988
     * @param $lpszFileName
989
     * @param $width
990
     * @param $height
991
     * @return bool
992
     */
993
    public function getSize($lpszFileName, &$width, &$height)
994
    {
995
        if (!($fh = @fopen($lpszFileName, 'rb'))) {
996
            return false;
997
        }
998
        $data = @fread($fh, @filesize($lpszFileName));
0 ignored issues
show
Bug introduced by
It seems like @filesize($lpszFileName) can also be of type false; however, parameter $length of fread() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

998
        $data = @fread($fh, /** @scrutinizer ignore-type */ @filesize($lpszFileName));
Loading history...
999
        @fclose($fh);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fclose(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

999
        /** @scrutinizer ignore-unhandled */ @fclose($fh);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1000
1001
        $gfh = new CGIFFILEHEADER();
1002
        if (!$gfh->load($data, $len = 0)) {
0 ignored issues
show
Bug introduced by
$len = 0 cannot be passed to CGIFFILEHEADER::load() as the parameter $hdrLen expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1002
        if (!$gfh->load($data, /** @scrutinizer ignore-type */ $len = 0)) {
Loading history...
1003
            return false;
1004
        }
1005
1006
        $width  = $gfh->m_nWidth;
1007
        $height = $gfh->m_nHeight;
1008
1009
        return true;
1010
    }
1011
1012
    ///////////////////////////////////////////////////////////////////////////
1013
1014
    /**
1015
     * @param $bgColor
1016
     * @return string
1017
     */
1018
    public function getBmp($bgColor)
1019
    {
1020
        $out = '';
1021
1022
        if (!$this->m_bLoaded) {
1023
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
1024
        }
1025
1026
        // PREPARE COLOR TABLE (RGBQUADs)
1027
        if ($this->m_img->m_gih->m_bLocalClr) {
1028
            $nColors = $this->m_img->m_gih->m_nTableSize;
1029
            $rgbq    = $this->m_img->m_gih->m_colorTable->toRGBQuad();
1030
            if (-1 != $bgColor) {
1031
                $bgColor = $this->m_img->m_gih->m_colorTable->colorIndex($bgColor);
1032
            }
1033
        } elseif ($this->m_gfh->m_bGlobalClr) {
1034
            $nColors = $this->m_gfh->m_nTableSize;
1035
            $rgbq    = $this->m_gfh->m_colorTable->toRGBQuad();
1036
            if (-1 != $bgColor) {
1037
                $bgColor = $this->m_gfh->m_colorTable->colorIndex($bgColor);
1038
            }
1039
        } else {
1040
            $nColors = 0;
1041
            $rgbq    = '';
1042
            $bgColor = -1;
1043
        }
1044
1045
        // PREPARE BITMAP BITS
1046
        $data = $this->m_img->m_data;
1047
        $nPxl = ($this->m_gfh->m_nHeight - 1) * $this->m_gfh->m_nWidth;
1048
        $bmp  = '';
1049
        $nPad = ($this->m_gfh->m_nWidth % 4) ? 4 - ($this->m_gfh->m_nWidth % 4) : 0;
1050
        for ($y = 0; $y < $this->m_gfh->m_nHeight; $y++) {
1051
            for ($x = 0; $x < $this->m_gfh->m_nWidth; $x++, $nPxl++) {
1052
                if (($x >= $this->m_img->m_gih->m_nLeft)
1053
                    && ($y >= $this->m_img->m_gih->m_nTop)
1054
                    && ($x < ($this->m_img->m_gih->m_nLeft + $this->m_img->m_gih->m_nWidth))
1055
                    && ($y < ($this->m_img->m_gih->m_nTop + $this->m_img->m_gih->m_nHeight))) {
1056
                    // PART OF IMAGE
1057
                    if (@$this->m_img->m_bTrans && (ord($data{$nPxl}) == $this->m_img->m_nTrans)) {
1058
                        // TRANSPARENT -> BACKGROUND
1059
                        if (-1 == $bgColor) {
1060
                            $bmp .= chr($this->m_gfh->m_nBgColor);
1061
                        } else {
1062
                            $bmp .= chr($bgColor);
1063
                        }
1064
                    } else {
1065
                        $bmp .= $data{$nPxl};
1066
                    }
1067
                } else {
1068
                    // BACKGROUND
1069
                    if (-1 == $bgColor) {
1070
                        $bmp .= chr($this->m_gfh->m_nBgColor);
1071
                    } else {
1072
                        $bmp .= chr($bgColor);
1073
                    }
1074
                }
1075
            }
1076
            $nPxl -= $this->m_gfh->m_nWidth << 1;
1077
1078
            // ADD PADDING
1079
            for ($x = 0; $x < $nPad; $x++) {
1080
                $bmp .= "\x00";
1081
            }
1082
        }
1083
1084
        // BITMAPFILEHEADER
1085
        $out .= 'BM';
1086
        $out .= $this->dword(14 + 40 + ($nColors << 2) + strlen($bmp));
1087
        $out .= "\x00\x00";
1088
        $out .= "\x00\x00";
1089
        $out .= $this->dword(14 + 40 + ($nColors << 2));
1090
1091
        // BITMAPINFOHEADER
1092
        $out .= $this->dword(40);
1093
        $out .= $this->dword($this->m_gfh->m_nWidth);
1094
        $out .= $this->dword($this->m_gfh->m_nHeight);
1095
        $out .= "\x01\x00";
1096
        $out .= "\x08\x00";
1097
        $out .= "\x00\x00\x00\x00";
1098
        $out .= "\x00\x00\x00\x00";
1099
        $out .= "\x12\x0B\x00\x00";
1100
        $out .= "\x12\x0B\x00\x00";
1101
        $out .= $this->dword($nColors % 256);
1102
        $out .= "\x00\x00\x00\x00";
1103
1104
        // COLOR TABLE
1105
        if ($nColors > 0) {
1106
            $out .= $rgbq;
1107
        }
1108
1109
        // DATA
1110
        $out .= $bmp;
1111
1112
        return $out;
1113
    }
1114
1115
    ///////////////////////////////////////////////////////////////////////////
1116
1117
    /**
1118
     * @param $bgColor
1119
     * @return string
1120
     */
1121
    public function getPng($bgColor)
1122
    {
1123
        $out = '';
1124
1125
        if (!$this->m_bLoaded) {
1126
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
1127
        }
1128
1129
        // PREPARE COLOR TABLE (RGBQUADs)
1130
        if ($this->m_img->m_gih->m_bLocalClr) {
1131
            $nColors = $this->m_img->m_gih->m_nTableSize;
1132
            $pal     = $this->m_img->m_gih->m_colorTable->toString();
1133
            if (-1 != $bgColor) {
1134
                $bgColor = $this->m_img->m_gih->m_colorTable->colorIndex($bgColor);
1135
            }
1136
        } elseif ($this->m_gfh->m_bGlobalClr) {
1137
            $nColors = $this->m_gfh->m_nTableSize;
1138
            $pal     = $this->m_gfh->m_colorTable->toString();
1139
            if (-1 != $bgColor) {
1140
                $bgColor = $this->m_gfh->m_colorTable->colorIndex($bgColor);
1141
            }
1142
        } else {
1143
            $nColors = 0;
1144
            $pal     = '';
1145
            $bgColor = -1;
1146
        }
1147
1148
        // PREPARE BITMAP BITS
1149
        $data = $this->m_img->m_data;
1150
        $nPxl = 0;
1151
        $bmp  = '';
1152
        for ($y = 0; $y < $this->m_gfh->m_nHeight; $y++) {
1153
            $bmp .= "\x00";
1154
            for ($x = 0; $x < $this->m_gfh->m_nWidth; $x++, $nPxl++) {
1155
                if (($x >= $this->m_img->m_gih->m_nLeft)
1156
                    && ($y >= $this->m_img->m_gih->m_nTop)
1157
                    && ($x < ($this->m_img->m_gih->m_nLeft + $this->m_img->m_gih->m_nWidth))
1158
                    && ($y < ($this->m_img->m_gih->m_nTop + $this->m_img->m_gih->m_nHeight))) {
1159
                    // PART OF IMAGE
1160
                    $bmp .= $data{$nPxl};
1161
                } else {
1162
                    // BACKGROUND
1163
                    if (-1 == $bgColor) {
1164
                        $bmp .= chr($this->m_gfh->m_nBgColor);
1165
                    } else {
1166
                        $bmp .= chr($bgColor);
1167
                    }
1168
                }
1169
            }
1170
        }
1171
        $bmp = gzcompress($bmp, 9);
1172
1173
        ///////////////////////////////////////////////////////////////////////
1174
        // SIGNATURE
1175
        $out .= "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
1176
        ///////////////////////////////////////////////////////////////////////
1177
        // HEADER
1178
        $out .= "\x00\x00\x00\x0D";
1179
        $tmp = 'IHDR';
1180
        $tmp .= $this->ndword($this->m_gfh->m_nWidth);
1181
        $tmp .= $this->ndword($this->m_gfh->m_nHeight);
1182
        $tmp .= "\x08\x03\x00\x00\x00";
1183
        $out .= $tmp;
1184
        $out .= $this->ndword(crc32($tmp));
1185
        ///////////////////////////////////////////////////////////////////////
1186
        // PALETTE
1187
        if ($nColors > 0) {
1188
            $out .= $this->ndword($nColors * 3);
1189
            $tmp = 'PLTE';
1190
            $tmp .= $pal;
1191
            $out .= $tmp;
1192
            $out .= $this->ndword(crc32($tmp));
1193
        }
1194
        ///////////////////////////////////////////////////////////////////////
1195
        // TRANSPARENCY
1196
        if (@$this->m_img->m_bTrans && ($nColors > 0)) {
1197
            $out .= $this->ndword($nColors);
1198
            $tmp = 'tRNS';
1199
            for ($i = 0; $i < $nColors; $i++) {
1200
                $tmp .= ($i == $this->m_img->m_nTrans) ? "\x00" : "\xFF";
1201
            }
1202
            $out .= $tmp;
1203
            $out .= $this->ndword(crc32($tmp));
1204
        }
1205
        ///////////////////////////////////////////////////////////////////////
1206
        // DATA BITS
1207
        $out .= $this->ndword(strlen($bmp));
1208
        $tmp = 'IDAT';
1209
        $tmp .= $bmp;
1210
        $out .= $tmp;
1211
        $out .= $this->ndword(crc32($tmp));
1212
        ///////////////////////////////////////////////////////////////////////
1213
        // END OF FILE
1214
        $out .= "\x00\x00\x00\x00IEND\xAE\x42\x60\x82";
1215
1216
        return $out;
1217
    }
1218
1219
    ///////////////////////////////////////////////////////////////////////////
1220
1221
    // Added by James Heinrich <[email protected]> - January 5, 2003
1222
1223
    // Takes raw image data and plots it pixel-by-pixel on a new GD image and returns that
1224
    // It's extremely slow, but the only solution when imagecreatefromstring() fails
1225
    /**
1226
     * @return bool|resource
1227
     */
1228
    public function getGD_PixelPlotterVersion()
1229
    {
1230
        if (!$this->m_bLoaded) {
1231
            return false;
1232
        }
1233
1234
        // PREPARE COLOR TABLE (RGBQUADs)
1235
        if ($this->m_img->m_gih->m_bLocalClr) {
1236
            $pal = $this->m_img->m_gih->m_colorTable->toString();
1237
        } elseif ($this->m_gfh->m_bGlobalClr) {
1238
            $pal = $this->m_gfh->m_colorTable->toString();
1239
        } else {
1240
            die('No color table available in getGD_PixelPlotterVersion()');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1241
        }
1242
1243
        $PlottingIMG    = imagecreate($this->m_gfh->m_nWidth, $this->m_gfh->m_nHeight);
1244
        $NumColorsInPal = floor(strlen($pal) / 3);
1245
        $ThisImageColor = [];
1246
        for ($i = 0; $i < $NumColorsInPal; $i++) {
1247
            $ThisImageColor[$i] = imagecolorallocate($PlottingIMG, ord($pal{($i * 3) + 0}), ord($pal{($i * 3) + 1}), ord($pal{($i * 3) + 2}));
1248
        }
1249
1250
        // PREPARE BITMAP BITS
1251
        $data = $this->m_img->m_data;
1252
        $nPxl = ($this->m_gfh->m_nHeight - 1) * $this->m_gfh->m_nWidth;
1253
        for ($y = 0; $y < $this->m_gfh->m_nHeight; $y++) {
1254
            if (!phpthumb_functions::FunctionIsDisabled('set_time_limit')) {
1255
                set_time_limit(30);
1256
            }
1257
            for ($x = 0; $x < $this->m_gfh->m_nWidth; $x++, $nPxl++) {
1258
                if (($x >= $this->m_img->m_gih->m_nLeft)
1259
                    && ($y >= $this->m_img->m_gih->m_nTop)
1260
                    && ($x < ($this->m_img->m_gih->m_nLeft + $this->m_img->m_gih->m_nWidth))
1261
                    && ($y < ($this->m_img->m_gih->m_nTop + $this->m_img->m_gih->m_nHeight))) {
1262
                    // PART OF IMAGE
1263
                    if (@$this->m_img->m_bTrans && (ord($data{$nPxl}) == $this->m_img->m_nTrans)) {
1264
                        imagesetpixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[$this->m_gfh->m_nBgColor]);
1265
                    } else {
1266
                        imagesetpixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[ord($data{$nPxl})]);
1267
                    }
1268
                } else {
1269
                    // BACKGROUND
1270
                    imagesetpixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[$this->m_gfh->m_nBgColor]);
1271
                }
1272
            }
1273
            $nPxl -= $this->m_gfh->m_nWidth << 1;
1274
        }
1275
1276
        return $PlottingIMG;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $PlottingIMG also could return the type GdImage which is incompatible with the documented return type boolean|resource.
Loading history...
1277
    }
1278
1279
    ///////////////////////////////////////////////////////////////////////////
1280
1281
    /**
1282
     * @param $val
1283
     * @return string
1284
     */
1285
    public function dword($val)
1286
    {
1287
        $val = (int)$val;
1288
1289
        return chr($val & 0xFF) . chr(($val & 0xFF00) >> 8) . chr(($val & 0xFF0000) >> 16) . chr(($val & 0xFF000000) >> 24);
1290
    }
1291
1292
    ///////////////////////////////////////////////////////////////////////////
1293
1294
    /**
1295
     * @param $val
1296
     * @return string
1297
     */
1298
    public function ndword($val)
1299
    {
1300
        $val = (int)$val;
1301
1302
        return chr(($val & 0xFF000000) >> 24) . chr(($val & 0xFF0000) >> 16) . chr(($val & 0xFF00) >> 8) . chr($val & 0xFF);
1303
    }
1304
1305
    ///////////////////////////////////////////////////////////////////////////
1306
1307
    public function width()
1308
    {
1309
        return $this->m_gfh->m_nWidth;
1310
    }
1311
1312
    ///////////////////////////////////////////////////////////////////////////
1313
1314
    public function height()
1315
    {
1316
        return $this->m_gfh->m_nHeight;
1317
    }
1318
1319
    ///////////////////////////////////////////////////////////////////////////
1320
1321
    public function comment()
1322
    {
1323
        return $this->m_img->m_lpComm;
1324
    }
1325
1326
    ///////////////////////////////////////////////////////////////////////////
1327
1328
    /**
1329
     * @return bool
1330
     */
1331
    public function loaded()
1332
    {
1333
        return $this->m_bLoaded;
1334
    }
1335
}
1336