phpthumb_filters::WatermarkText()   F
last analyzed

Complexity

Conditions 68
Paths 4024

Size

Total Lines 301
Code Lines 226

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 68
eloc 226
nc 4024
nop 13
dl 0
loc 301
rs 0
c 5
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
//////////////////////////////////////////////////////////////
3
//   phpThumb() by James Heinrich <[email protected]>   //
4
//        available at http://phpthumb.sourceforge.net      //
5
//         and/or https://github.com/JamesHeinrich/phpThumb //
6
//////////////////////////////////////////////////////////////
7
///                                                         //
8
// phpthumb.filters.php - image processing filter functions //
9
//                                                         ///
10
//////////////////////////////////////////////////////////////
11
12
class phpthumb_filters
13
{
14
    /**
15
     * @var phpthumb
16
     */
17
18
    public $phpThumbObject = null;
19
20
    public function DebugMessage($message, $file = '', $line = '')
21
    {
22
        if (is_object($this->phpThumbObject)) {
23
            return $this->phpThumbObject->DebugMessage($message, $file, $line);
24
        }
25
        return false;
26
    }
27
28
    public function ApplyMask(&$gdimg_mask, &$gdimg_image)
29
    {
30
        if (phpthumb_functions::gd_version() < 2) {
31
            $this->DebugMessage('Skipping ApplyMask() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
32
            return false;
33
        }
34
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.2', '>=')) {
35
            $this->DebugMessage('Using alpha ApplyMask() technique', __FILE__, __LINE__);
36
            if ($gdimg_mask_resized = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_image), imagesy($gdimg_image))) {
37
                imagecopyresampled($gdimg_mask_resized, $gdimg_mask, 0, 0, 0, 0, imagesx($gdimg_image), imagesy($gdimg_image), imagesx($gdimg_mask), imagesy($gdimg_mask));
38
                if ($gdimg_mask_blendtemp = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_image), imagesy($gdimg_image))) {
39
                    $color_background = imagecolorallocate($gdimg_mask_blendtemp, 0, 0, 0);
40
                    imagefilledrectangle($gdimg_mask_blendtemp, 0, 0, imagesx($gdimg_mask_blendtemp), imagesy($gdimg_mask_blendtemp), $color_background);
41
                    imagealphablending($gdimg_mask_blendtemp, false);
42
                    imagesavealpha($gdimg_mask_blendtemp, true);
43
                    for ($x = 0, $xMax = imagesx($gdimg_image); $x < $xMax; $x++) {
44
                        for ($y = 0, $yMax = imagesy($gdimg_image); $y < $yMax; $y++) {
45
                            //$RealPixel = phpthumb_functions::GetPixelColor($gdimg_mask_blendtemp, $x, $y);
46
                            $RealPixel = phpthumb_functions::GetPixelColor($gdimg_image, $x, $y);
47
                            $MaskPixel = phpthumb_functions::GrayscalePixel(phpthumb_functions::GetPixelColor($gdimg_mask_resized, $x, $y));
48
                            $MaskAlpha = 127 - (floor($MaskPixel['red'] / 2) * (1 - ($RealPixel['alpha'] / 127)));
49
                            $newcolor  = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_mask_blendtemp, $RealPixel['red'], $RealPixel['green'], $RealPixel['blue'], $MaskAlpha);
50
                            imagesetpixel($gdimg_mask_blendtemp, $x, $y, $newcolor);
51
                        }
52
                    }
53
                    imagealphablending($gdimg_image, false);
54
                    imagesavealpha($gdimg_image, true);
55
                    imagecopy($gdimg_image, $gdimg_mask_blendtemp, 0, 0, 0, 0, imagesx($gdimg_mask_blendtemp), imagesy($gdimg_mask_blendtemp));
56
                    imagedestroy($gdimg_mask_blendtemp);
57
                } else {
58
                    $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__);
59
                }
60
                imagedestroy($gdimg_mask_resized);
61
            } else {
62
                $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__);
63
            }
64
        } else {
65
            // alpha merging requires PHP v4.3.2+
66
            $this->DebugMessage('Skipping ApplyMask() technique because PHP is v"' . PHP_VERSION . '"', __FILE__, __LINE__);
67
        }
68
        return true;
69
    }
70
71
    public function Bevel(&$gdimg, $width, $hexcolor1, $hexcolor2)
72
    {
73
        $width     = ($width ? $width : 5);
74
        $hexcolor1 = ($hexcolor1 ? $hexcolor1 : 'FFFFFF');
75
        $hexcolor2 = ($hexcolor2 ? $hexcolor2 : '000000');
76
77
        imagealphablending($gdimg, true);
78
        for ($i = 0; $i < $width; $i++) {
79
            $alpha  = round(($i / $width) * 127);
80
            $color1 = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor1, false, $alpha);
81
            $color2 = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor2, false, $alpha);
82
83
            imageline($gdimg, $i, $i + 1, $i, imagesy($gdimg) - $i - 1, $color1); // left
84
            imageline($gdimg, $i, $i, imagesx($gdimg) - $i, $i, $color1); // top
85
            imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i - 1, imagesx($gdimg) - $i, $i + 1, $color2); // right
86
            imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i, $i, imagesy($gdimg) - $i, $color2); // bottom
87
        }
88
        return true;
89
    }
90
91
    public function Blur(&$gdimg, $radius = 0.5)
92
    {
93
        // Taken from Torstein Hønsi's phpUnsharpMask (see phpthumb.unsharp.php)
94
95
        $radius = round(max(0, min($radius, 50)) * 2);
96
        if (!$radius) {
97
            return false;
98
        }
99
100
        $w = imagesx($gdimg);
101
        $h = imagesy($gdimg);
102
        if ($imgBlur = imagecreatetruecolor($w, $h)) {
103
            // Gaussian blur matrix:
104
            //	1	2	1
105
            //	2	4	2
106
            //	1	2	1
107
108
            // Move copies of the image around one pixel at the time and merge them with weight
109
            // according to the matrix. The same matrix is simply repeated for higher radii.
110
            for ($i = 0; $i < $radius; $i++) {
111
                imagecopy($imgBlur, $gdimg, 0, 0, 1, 1, $w - 1, $h - 1);            // up left
112
                imagecopymerge($imgBlur, $gdimg, 1, 1, 0, 0, $w, $h, 50.00000);  // down right
113
                imagecopymerge($imgBlur, $gdimg, 0, 1, 1, 0, $w - 1, $h, 33.33333);  // down left
0 ignored issues
show
Bug introduced by
33.33333 of type double is incompatible with the type integer expected by parameter $pct of imagecopymerge(). ( Ignorable by Annotation )

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

113
                imagecopymerge($imgBlur, $gdimg, 0, 1, 1, 0, $w - 1, $h, /** @scrutinizer ignore-type */ 33.33333);  // down left
Loading history...
114
                imagecopymerge($imgBlur, $gdimg, 1, 0, 0, 1, $w, $h - 1, 25.00000);  // up right
115
                imagecopymerge($imgBlur, $gdimg, 0, 0, 1, 0, $w - 1, $h, 33.33333);  // left
116
                imagecopymerge($imgBlur, $gdimg, 1, 0, 0, 0, $w, $h, 25.00000);  // right
117
                imagecopymerge($imgBlur, $gdimg, 0, 0, 0, 1, $w, $h - 1, 20.00000);  // up
118
                imagecopymerge($imgBlur, $gdimg, 0, 1, 0, 0, $w, $h, 16.666667); // down
119
                imagecopymerge($imgBlur, $gdimg, 0, 0, 0, 0, $w, $h, 50.000000); // center
120
                imagecopy($gdimg, $imgBlur, 0, 0, 0, 0, $w, $h);
121
            }
122
            return true;
123
        }
124
        return false;
125
    }
126
127
    public function BlurGaussian(&$gdimg)
128
    {
129
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
130
            if (imagefilter($gdimg, IMG_FILTER_GAUSSIAN_BLUR)) {
131
                return true;
132
            }
133
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_GAUSSIAN_BLUR)', __FILE__, __LINE__);
134
            // fall through and try it the hard way
135
        }
136
        $this->DebugMessage('FAILED: phpthumb_filters::BlurGaussian($gdimg) [using phpthumb_filters::Blur() instead]', __FILE__, __LINE__);
137
        return $this->Blur($gdimg, 0.5);
138
    }
139
140
    public function BlurSelective(&$gdimg)
141
    {
142
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
143
            if (imagefilter($gdimg, IMG_FILTER_SELECTIVE_BLUR)) {
144
                return true;
145
            }
146
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_SELECTIVE_BLUR)', __FILE__, __LINE__);
147
            // fall through and try it the hard way
148
        }
149
        // currently not implemented "the hard way"
150
        $this->DebugMessage('FAILED: phpthumb_filters::BlurSelective($gdimg) [function not implemented]', __FILE__, __LINE__);
151
        return false;
152
    }
153
154
    public function Brightness(&$gdimg, $amount = 0)
155
    {
156
        if ($amount == 0) {
157
            return true;
158
        }
159
        $amount = max(-255, min(255, $amount));
160
161
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
162
            if (imagefilter($gdimg, IMG_FILTER_BRIGHTNESS, $amount)) {
163
                return true;
164
            }
165
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_BRIGHTNESS, ' . $amount . ')', __FILE__, __LINE__);
166
            // fall through and try it the hard way
167
        }
168
169
        $scaling    = (255 - abs($amount)) / 255;
170
        $baseamount = (($amount > 0) ? $amount : 0);
171
        for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) {
172
            for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) {
173
                $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
174
                $NewPixel      = [];
175
                foreach ($OriginalPixel as $key => $value) {
176
                    $NewPixel[$key] = round($baseamount + ($OriginalPixel[$key] * $scaling));
177
                }
178
                $newColor = imagecolorallocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']);
179
                imagesetpixel($gdimg, $x, $y, $newColor);
180
            }
181
        }
182
        return true;
183
    }
184
185
    public function Contrast(&$gdimg, $amount = 0)
186
    {
187
        if ($amount == 0) {
188
            return true;
189
        }
190
        $amount = max(-255, min(255, $amount));
191
192
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
193
            // imagefilter(IMG_FILTER_CONTRAST) has range +100 to -100 (positive numbers make it darker!)
194
            $amount = ($amount / 255) * -100;
195
            if (imagefilter($gdimg, IMG_FILTER_CONTRAST, $amount)) {
196
                return true;
197
            }
198
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_CONTRAST, ' . $amount . ')', __FILE__, __LINE__);
199
            // fall through and try it the hard way
200
        }
201
202
        if ($amount > 0) {
203
            $scaling = 1 + ($amount / 255);
204
        } else {
205
            $scaling = (255 - abs($amount)) / 255;
206
        }
207
        for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) {
208
            for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) {
209
                $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
210
                $NewPixel      = [];
211
                foreach ($OriginalPixel as $key => $value) {
212
                    $NewPixel[$key] = min(255, max(0, round($OriginalPixel[$key] * $scaling)));
213
                }
214
                $newColor = imagecolorallocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']);
215
                imagesetpixel($gdimg, $x, $y, $newColor);
216
            }
217
        }
218
        return true;
219
    }
220
221
    public function Colorize(&$gdimg, $amount, $targetColor)
222
    {
223
        $amount      = (is_numeric($amount) ? $amount : 25);
224
        $amountPct   = $amount / 100;
225
        $targetColor = (phpthumb_functions::IsHexColor($targetColor) ? $targetColor : 'gray');
226
227
        if ($amount == 0) {
228
            return true;
229
        }
230
231
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
232
            if ($targetColor == 'gray') {
233
                $targetColor = '808080';
234
            }
235
            $r = round($amountPct * hexdec(substr($targetColor, 0, 2)));
236
            $g = round($amountPct * hexdec(substr($targetColor, 2, 2)));
237
            $b = round($amountPct * hexdec(substr($targetColor, 4, 2)));
238
            if (imagefilter($gdimg, IMG_FILTER_COLORIZE, $r, $g, $b)) {
0 ignored issues
show
Bug introduced by
$r of type double is incompatible with the type integer expected by parameter $arg1 of imagefilter(). ( Ignorable by Annotation )

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

238
            if (imagefilter($gdimg, IMG_FILTER_COLORIZE, /** @scrutinizer ignore-type */ $r, $g, $b)) {
Loading history...
Bug introduced by
$g of type double is incompatible with the type integer expected by parameter $arg2 of imagefilter(). ( Ignorable by Annotation )

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

238
            if (imagefilter($gdimg, IMG_FILTER_COLORIZE, $r, /** @scrutinizer ignore-type */ $g, $b)) {
Loading history...
Bug introduced by
$b of type double is incompatible with the type integer expected by parameter $arg3 of imagefilter(). ( Ignorable by Annotation )

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

238
            if (imagefilter($gdimg, IMG_FILTER_COLORIZE, $r, $g, /** @scrutinizer ignore-type */ $b)) {
Loading history...
239
                return true;
240
            }
241
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_COLORIZE)', __FILE__, __LINE__);
242
            // fall through and try it the hard way
243
        }
244
245
        // overridden below for grayscale
246
        $TargetPixel = [];
247
        if ($targetColor != 'gray') {
248
            $TargetPixel['red']   = hexdec(substr($targetColor, 0, 2));
249
            $TargetPixel['green'] = hexdec(substr($targetColor, 2, 2));
250
            $TargetPixel['blue']  = hexdec(substr($targetColor, 4, 2));
251
        }
252
253
        for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) {
254
            for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) {
255
                $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
256
                if ($targetColor == 'gray') {
257
                    $TargetPixel = phpthumb_functions::GrayscalePixel($OriginalPixel);
258
                }
259
                $NewPixel = [];
260
                foreach ($TargetPixel as $key => $value) {
261
                    $NewPixel[$key] = round(max(0, min(255, ($OriginalPixel[$key] * ((100 - $amount) / 100)) + ($TargetPixel[$key] * $amountPct))));
262
                }
263
                //$newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue'], $OriginalPixel['alpha']);
264
                $newColor = imagecolorallocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']);
265
                imagesetpixel($gdimg, $x, $y, $newColor);
266
            }
267
        }
268
        return true;
269
    }
270
271
    public function Crop(&$gdimg, $left = 0, $right = 0, $top = 0, $bottom = 0)
272
    {
273
        if (!$left && !$right && !$top && !$bottom) {
274
            return true;
275
        }
276
        $oldW = imagesx($gdimg);
277
        $oldH = imagesy($gdimg);
278
        if (($left > 0) && ($left < 1)) {
279
            $left = round($left * $oldW);
280
        }
281
        if (($right > 0) && ($right < 1)) {
282
            $right = round($right * $oldW);
283
        }
284
        if (($top > 0) && ($top < 1)) {
285
            $top = round($top * $oldH);
286
        }
287
        if (($bottom > 0) && ($bottom < 1)) {
288
            $bottom = round($bottom * $oldH);
289
        }
290
        $right  = min($oldW - $left - 1, $right);
291
        $bottom = min($oldH - $top - 1, $bottom);
292
        $newW   = $oldW - $left - $right;
293
        $newH   = $oldH - $top - $bottom;
294
295
        if ($imgCropped = imagecreatetruecolor($newW, $newH)) {
296
            imagecopy($imgCropped, $gdimg, 0, 0, $left, $top, $newW, $newH);
297
            if ($gdimg = imagecreatetruecolor($newW, $newH)) {
298
                imagecopy($gdimg, $imgCropped, 0, 0, 0, 0, $newW, $newH);
299
                imagedestroy($imgCropped);
300
                return true;
301
            }
302
            imagedestroy($imgCropped);
303
        }
304
        return false;
305
    }
306
307
    public function Desaturate(&$gdimg, $amount, $color = '')
308
    {
309
        if ($amount == 0) {
310
            return true;
311
        }
312
        return $this->Colorize($gdimg, $amount, (phpthumb_functions::IsHexColor($color) ? $color : 'gray'));
313
    }
314
315
    public function DropShadow(&$gdimg, $distance, $width, $hexcolor, $angle, $alpha)
316
    {
317
        if (phpthumb_functions::gd_version() < 2) {
318
            return false;
319
        }
320
        $distance = ($distance ? $distance : 10);
321
        $width    = ($width ? $width : 10);
322
        $hexcolor = ($hexcolor ? $hexcolor : '000000');
323
        $angle    = ($angle ? $angle : 225) % 360;
324
        $alpha    = max(0, min(100, ($alpha ? $alpha : 100)));
325
326
        if ($alpha <= 0) {
327
            // invisible shadow, nothing to do
328
            return true;
329
        }
330
        if ($distance <= 0) {
331
            // shadow completely obscured by source image, nothing to do
332
            return true;
333
        }
334
335
        //$width_shadow  = cos(deg2rad($angle)) * ($distance + $width);
336
        //$height_shadow = sin(deg2rad($angle)) * ($distance + $width);
337
        //$scaling = min(imagesx($gdimg) / (imagesx($gdimg) + abs($width_shadow)), imagesy($gdimg) / (imagesy($gdimg) + abs($height_shadow)));
338
339
        $Offset = [];
340
        for ($i = 0; $i < $width; $i++) {
341
            $WidthAlpha[$i] = (abs(($width / 2) - $i) / $width);
342
            $Offset['x']    = cos(deg2rad($angle)) * ($distance + $i);
343
            $Offset['y']    = sin(deg2rad($angle)) * ($distance + $i);
344
        }
345
346
        $tempImageWidth  = imagesx($gdimg) + abs($Offset['x']);
347
        $tempImageHeight = imagesy($gdimg) + abs($Offset['y']);
348
349
        if ($gdimg_dropshadow_temp = phpthumb_functions::ImageCreateFunction($tempImageWidth, $tempImageHeight)) {
350
            imagealphablending($gdimg_dropshadow_temp, false);
351
            imagesavealpha($gdimg_dropshadow_temp, true);
352
            $transparent1 = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_dropshadow_temp, 0, 0, 0, 127);
353
            imagefill($gdimg_dropshadow_temp, 0, 0, $transparent1);
354
355
            $PixelMap = [];
356
            for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) {
357
                for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) {
358
                    $PixelMap[$x][$y] = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
359
                }
360
            }
361
            for ($x = 0; $x < $tempImageWidth; $x++) {
362
                for ($y = 0; $y < $tempImageHeight; $y++) {
363
                    //for ($i = 0; $i < $width; $i++) {
364
                    for ($i = 0; $i < 1; $i++) {
365
                        if (!isset($PixelMap[$x][$y]['alpha']) || ($PixelMap[$x][$y]['alpha'] > 0)) {
366
                            if (isset($PixelMap[$x + $Offset['x']][$y + $Offset['y']]['alpha']) && ($PixelMap[$x + $Offset['x']][$y + $Offset['y']]['alpha'] < 127)) {
367
                                $thisColor = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor, false, $PixelMap[$x + $Offset['x']][$y + $Offset['y']]['alpha']);
368
                                imagesetpixel($gdimg_dropshadow_temp, $x, $y, $thisColor);
369
                            }
370
                        }
371
                    }
372
                }
373
            }
374
375
            imagealphablending($gdimg_dropshadow_temp, true);
376
            for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) {
377
                for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) {
378
                    if ($PixelMap[$x][$y]['alpha'] < 127) {
379
                        $thisColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_dropshadow_temp, $PixelMap[$x][$y]['red'], $PixelMap[$x][$y]['green'], $PixelMap[$x][$y]['blue'], $PixelMap[$x][$y]['alpha']);
380
                        imagesetpixel($gdimg_dropshadow_temp, $x, $y, $thisColor);
381
                    }
382
                }
383
            }
384
385
            imagesavealpha($gdimg, true);
386
            imagealphablending($gdimg, false);
387
            //$this->is_alpha = true;
388
            $transparent2 = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 0, 0, 0, 127);
389
            imagefilledrectangle($gdimg, 0, 0, imagesx($gdimg), imagesy($gdimg), $transparent2);
390
            imagecopyresampled($gdimg, $gdimg_dropshadow_temp, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg), imagesx($gdimg_dropshadow_temp), imagesy($gdimg_dropshadow_temp));
391
392
            imagedestroy($gdimg_dropshadow_temp);
393
        }
394
        return true;
395
    }
396
397
    public function EdgeDetect(&$gdimg)
398
    {
399
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
400
            if (imagefilter($gdimg, IMG_FILTER_EDGEDETECT)) {
401
                return true;
402
            }
403
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_EDGEDETECT)', __FILE__, __LINE__);
404
            // fall through and try it the hard way
405
        }
406
        // currently not implemented "the hard way"
407
        $this->DebugMessage('FAILED: phpthumb_filters::EdgeDetect($gdimg) [function not implemented]', __FILE__, __LINE__);
408
        return false;
409
    }
410
411
    public function Ellipse($gdimg)
412
    {
413
        if (phpthumb_functions::gd_version() < 2) {
414
            return false;
415
        }
416
        // generate mask at twice desired resolution and downsample afterwards for easy antialiasing
417
        if ($gdimg_ellipsemask_double = phpthumb_functions::ImageCreateFunction(imagesx($gdimg) * 2, imagesy($gdimg) * 2)) {
418
            if ($gdimg_ellipsemask = phpthumb_functions::ImageCreateFunction(imagesx($gdimg), imagesy($gdimg))) {
419
                $color_transparent = imagecolorallocate($gdimg_ellipsemask_double, 255, 255, 255);
420
                imagefilledellipse($gdimg_ellipsemask_double, imagesx($gdimg), imagesy($gdimg), (imagesx($gdimg) - 1) * 2, (imagesy($gdimg) - 1) * 2, $color_transparent);
421
                imagecopyresampled($gdimg_ellipsemask, $gdimg_ellipsemask_double, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg), imagesx($gdimg) * 2, imagesy($gdimg) * 2);
422
423
                $this->ApplyMask($gdimg_ellipsemask, $gdimg);
424
                imagedestroy($gdimg_ellipsemask);
425
                return true;
426
            } else {
427
                $this->DebugMessage('$gdimg_ellipsemask = phpthumb_functions::ImageCreateFunction() failed', __FILE__, __LINE__);
428
            }
429
            imagedestroy($gdimg_ellipsemask_double);
430
        } else {
431
            $this->DebugMessage('$gdimg_ellipsemask_double = phpthumb_functions::ImageCreateFunction() failed', __FILE__, __LINE__);
432
        }
433
        return false;
434
    }
435
436
    public function Emboss(&$gdimg)
437
    {
438
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
439
            if (imagefilter($gdimg, IMG_FILTER_EMBOSS)) {
440
                return true;
441
            }
442
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_EMBOSS)', __FILE__, __LINE__);
443
            // fall through and try it the hard way
444
        }
445
        // currently not implemented "the hard way"
446
        $this->DebugMessage('FAILED: phpthumb_filters::Emboss($gdimg) [function not implemented]', __FILE__, __LINE__);
447
        return false;
448
    }
449
450
    public function Flip(&$gdimg, $x = false, $y = false)
451
    {
452
        if (!$x && !$y) {
453
            return false;
454
        }
455
        if ($tempImage = phpthumb_functions::ImageCreateFunction(imagesx($gdimg), imagesy($gdimg))) {
456
            if ($x) {
457
                imagecopy($tempImage, $gdimg, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg));
458
                for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) {
459
                    imagecopy($gdimg, $tempImage, imagesx($gdimg) - 1 - $x, 0, $x, 0, 1, imagesy($gdimg));
460
                }
461
            }
462
            if ($y) {
463
                imagecopy($tempImage, $gdimg, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg));
464
                for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) {
465
                    imagecopy($gdimg, $tempImage, 0, imagesy($gdimg) - 1 - $y, 0, $y, imagesx($gdimg), 1);
466
                }
467
            }
468
            imagedestroy($tempImage);
469
        }
470
        return true;
471
    }
472
473
    public function Frame(&$gdimg, $frame_width, $edge_width, $hexcolor_frame, $hexcolor1, $hexcolor2)
474
    {
475
        $frame_width    = ($frame_width ? $frame_width : 5);
476
        $edge_width     = ($edge_width ? $edge_width : 1);
477
        $hexcolor_frame = ($hexcolor_frame ? $hexcolor_frame : 'CCCCCC');
478
        $hexcolor1      = ($hexcolor1 ? $hexcolor1 : 'FFFFFF');
479
        $hexcolor2      = ($hexcolor2 ? $hexcolor2 : '000000');
480
481
        $color_frame = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor_frame);
482
        $color1      = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor1);
483
        $color2      = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor2);
484
        for ($i = 0; $i < $edge_width; $i++) {
485
            // outer bevel
486
            imageline($gdimg, $i, $i, $i, imagesy($gdimg) - $i, $color1); // left
487
            imageline($gdimg, $i, $i, imagesx($gdimg) - $i, $i, $color1); // top
488
            imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i, imagesx($gdimg) - $i, $i, $color2); // right
489
            imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i, $i, imagesy($gdimg) - $i, $color2); // bottom
490
        }
491
        for ($i = 0; $i < $frame_width; $i++) {
492
            // actual frame
493
            imagerectangle($gdimg, $edge_width + $i, $edge_width + $i, imagesx($gdimg) - $edge_width - $i, imagesy($gdimg) - $edge_width - $i, $color_frame);
494
        }
495
        for ($i = 0; $i < $edge_width; $i++) {
496
            // inner bevel
497
            imageline($gdimg, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, imagesy($gdimg) - $frame_width - $edge_width - $i, $color2); // left
498
            imageline($gdimg, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, imagesx($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, $color2); // top
499
            imageline($gdimg, imagesx($gdimg) - $frame_width - $edge_width - $i, imagesy($gdimg) - $frame_width - $edge_width - $i, imagesx($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, $color1); // right
500
            imageline($gdimg, imagesx($gdimg) - $frame_width - $edge_width - $i, imagesy($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, imagesy($gdimg) - $frame_width - $edge_width - $i, $color1); // bottom
501
        }
502
        return true;
503
    }
504
505
    public function Gamma(&$gdimg, $amount)
506
    {
507
        if (number_format($amount, 4) == '1.0000') {
508
            return true;
509
        }
510
        return imagegammacorrect($gdimg, 1.0, $amount);
511
    }
512
513
    public function Grayscale(&$gdimg)
514
    {
515
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
516
            if (imagefilter($gdimg, IMG_FILTER_GRAYSCALE)) {
517
                return true;
518
            }
519
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_GRAYSCALE)', __FILE__, __LINE__);
520
            // fall through and try it the hard way
521
        }
522
        return $this->Colorize($gdimg, 100, 'gray');
523
    }
524
525
    public function HistogramAnalysis(&$gdimg, $calculateGray = false)
526
    {
527
        $ImageSX  = imagesx($gdimg);
528
        $ImageSY  = imagesy($gdimg);
529
        $Analysis = [];
530
        for ($x = 0; $x < $ImageSX; $x++) {
531
            for ($y = 0; $y < $ImageSY; $y++) {
532
                $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
533
                @$Analysis['red'][$OriginalPixel['red']]++;
534
                @$Analysis['green'][$OriginalPixel['green']]++;
535
                @$Analysis['blue'][$OriginalPixel['blue']]++;
536
                @$Analysis['alpha'][$OriginalPixel['alpha']]++;
537
                if ($calculateGray) {
538
                    $GrayPixel = phpthumb_functions::GrayscalePixel($OriginalPixel);
539
                    @$Analysis['gray'][$GrayPixel['red']]++;
540
                }
541
            }
542
        }
543
        $keys = ['red', 'green', 'blue', 'alpha'];
544
        if ($calculateGray) {
545
            $keys[] = 'gray';
546
        }
547
        foreach ($keys as $dummy => $key) {
548
            ksort($Analysis[$key]);
549
        }
550
        return $Analysis;
551
    }
552
553
    public function HistogramStretch(&$gdimg, $band = '*', $method = 0, $threshold = 0.1)
554
    {
555
        // equivalent of "Auto Contrast" in Adobe Photoshop
556
        // method 0 stretches according to RGB colors. Gives a more conservative stretch.
557
        // method 1 band stretches according to grayscale which is color-biased (59% green, 30% red, 11% blue). May give a punchier / more aggressive stretch, possibly appearing over-saturated
558
        $Analysis = $this->HistogramAnalysis($gdimg, true);
559
        $keys     = ['r' => 'red', 'g' => 'green', 'b' => 'blue', 'a' => 'alpha', '*' => ($method == 0) ? 'all' : 'gray'];
560
        $band     = $band[0];
561
        if (!isset($keys[$band])) {
562
            return false;
563
        }
564
        $key = $keys[$band];
565
566
        // If the absolute brightest and darkest pixels are used then one random
567
        // pixel in the image could throw off the whole system. Instead, count up/down
568
        // from the limit and allow <threshold> (default = 0.1%) of brightest/darkest
569
        // pixels to be clipped to min/max
570
        $threshold      = (float)$threshold / 100;
571
        $clip_threshold = imagesx($gdimg) * imagesx($gdimg) * $threshold;
572
573
        $countsum  = 0;
574
        $range_min = 0;
575
        for ($i = 0; $i <= 255; $i++) {
576
            if ($method == 0) {
577
                $countsum = max(@$Analysis['red'][$i], @$Analysis['green'][$i], @$Analysis['blue'][$i]);
578
            } else {
579
                $countsum += @$Analysis[$key][$i];
580
            }
581
            if ($countsum >= $clip_threshold) {
582
                $range_min = $i - 1;
583
                break;
584
            }
585
        }
586
        $range_min = max($range_min, 0);
587
588
        $countsum  = 0;
589
        $range_max = 255;
590
        for ($i = 255; $i >= 0; $i--) {
591
            if ($method == 0) {
592
                $countsum = max(@$Analysis['red'][$i], @$Analysis['green'][$i], @$Analysis['blue'][$i]);
593
            } else {
594
                $countsum += @$Analysis[$key][$i];
595
            }
596
            if ($countsum >= $clip_threshold) {
597
                $range_max = $i + 1;
598
                break;
599
            }
600
        }
601
        $range_max = min($range_max, 255);
602
603
        $range_scale = (($range_max == $range_min) ? 1 : (255 / ($range_max - $range_min)));
604
        if (($range_min == 0) && ($range_max == 255)) {
605
            // no adjustment necessary - don't waste CPU time!
606
            return true;
607
        }
608
609
        $ImageSX = imagesx($gdimg);
610
        $ImageSY = imagesy($gdimg);
611
        for ($x = 0; $x < $ImageSX; $x++) {
612
            for ($y = 0; $y < $ImageSY; $y++) {
613
                $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
614
                if ($band == '*') {
615
                    $new['red']   = min(255, max(0, ($OriginalPixel['red'] - $range_min) * $range_scale));
616
                    $new['green'] = min(255, max(0, ($OriginalPixel['green'] - $range_min) * $range_scale));
617
                    $new['blue']  = min(255, max(0, ($OriginalPixel['blue'] - $range_min) * $range_scale));
618
                    $new['alpha'] = min(255, max(0, ($OriginalPixel['alpha'] - $range_min) * $range_scale));
619
                } else {
620
                    $new       = $OriginalPixel;
621
                    $new[$key] = min(255, max(0, ($OriginalPixel[$key] - $range_min) * $range_scale));
622
                }
623
                $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $new['red'], $new['green'], $new['blue'], $new['alpha']);
624
                imagesetpixel($gdimg, $x, $y, $newColor);
625
            }
626
        }
627
628
        return true;
629
    }
630
631
    public function HistogramOverlay(&$gdimg, $bands = '*', $colors = '', $width = 0.25, $height = 0.25, $alignment = 'BR', $opacity = 50, $margin_x = 5, $margin_y = null)
0 ignored issues
show
Unused Code introduced by
The parameter $height is not used and could be removed. ( Ignorable by Annotation )

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

631
    public function HistogramOverlay(&$gdimg, $bands = '*', $colors = '', $width = 0.25, /** @scrutinizer ignore-unused */ $height = 0.25, $alignment = 'BR', $opacity = 50, $margin_x = 5, $margin_y = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
632
    {
633
        $margin_y = (null === $margin_y ? $margin_x : $margin_y);
634
635
        $Analysis = $this->HistogramAnalysis($gdimg, true);
636
        $histW    = round(($width > 1) ? min($width, imagesx($gdimg)) : imagesx($gdimg) * $width);
637
        $histH    = round(($width > 1) ? min($width, imagesx($gdimg)) : imagesx($gdimg) * $width);
638
        if ($gdHist = imagecreatetruecolor($histW, $histH)) {
0 ignored issues
show
Bug introduced by
$histH of type double is incompatible with the type integer expected by parameter $height of imagecreatetruecolor(). ( Ignorable by Annotation )

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

638
        if ($gdHist = imagecreatetruecolor($histW, /** @scrutinizer ignore-type */ $histH)) {
Loading history...
Bug introduced by
$histW of type double is incompatible with the type integer expected by parameter $width of imagecreatetruecolor(). ( Ignorable by Annotation )

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

638
        if ($gdHist = imagecreatetruecolor(/** @scrutinizer ignore-type */ $histW, $histH)) {
Loading history...
639
            $color_back = phpthumb_functions::ImageColorAllocateAlphaSafe($gdHist, 0, 0, 0, 127);
640
            imagefilledrectangle($gdHist, 0, 0, $histW, $histH, $color_back);
0 ignored issues
show
Bug introduced by
$histW of type double is incompatible with the type integer expected by parameter $x2 of imagefilledrectangle(). ( Ignorable by Annotation )

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

640
            imagefilledrectangle($gdHist, 0, 0, /** @scrutinizer ignore-type */ $histW, $histH, $color_back);
Loading history...
Bug introduced by
$histH of type double is incompatible with the type integer expected by parameter $y2 of imagefilledrectangle(). ( Ignorable by Annotation )

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

640
            imagefilledrectangle($gdHist, 0, 0, $histW, /** @scrutinizer ignore-type */ $histH, $color_back);
Loading history...
641
            imagealphablending($gdHist, false);
642
            imagesavealpha($gdHist, true);
643
644
            $HistogramTempWidth  = 256;
645
            $HistogramTempHeight = 100;
646
            if ($gdHistTemp = imagecreatetruecolor($HistogramTempWidth, $HistogramTempHeight)) {
647
                $color_back_temp = phpthumb_functions::ImageColorAllocateAlphaSafe($gdHistTemp, 255, 0, 255, 127);
648
                imagealphablending($gdHistTemp, false);
649
                imagesavealpha($gdHistTemp, true);
650
                imagefilledrectangle($gdHistTemp, 0, 0, imagesx($gdHistTemp), imagesy($gdHistTemp), $color_back_temp);
651
652
                $DefaultColors = ['r' => 'FF0000', 'g' => '00FF00', 'b' => '0000FF', 'a' => '999999', '*' => 'FFFFFF'];
653
                $Colors        = explode(';', $colors);
654
                $BandsToGraph  = array_unique(preg_split('##', $bands));
655
                $keys          = ['r' => 'red', 'g' => 'green', 'b' => 'blue', 'a' => 'alpha', '*' => 'gray'];
656
                foreach ($BandsToGraph as $key => $band) {
657
                    if (!isset($keys[$band])) {
658
                        continue;
659
                    }
660
                    $PeakValue = max($Analysis[$keys[$band]]);
661
                    $thisColor = phpthumb_functions::ImageHexColorAllocate($gdHistTemp, phpthumb_functions::IsHexColor(@$Colors[$key]) ? $Colors[$key] : $DefaultColors[$band]);
662
                    for ($x = 0; $x < $HistogramTempWidth; $x++) {
663
                        imageline($gdHistTemp, $x, $HistogramTempHeight - 1, $x, $HistogramTempHeight - 1 - round(@$Analysis[$keys[$band]][$x] / $PeakValue * $HistogramTempHeight), $thisColor);
664
                    }
665
                    imageline($gdHistTemp, 0, $HistogramTempHeight - 1, $HistogramTempWidth - 1, $HistogramTempHeight - 1, $thisColor);
666
                    imageline($gdHistTemp, 0, $HistogramTempHeight - 2, $HistogramTempWidth - 1, $HistogramTempHeight - 2, $thisColor);
667
                }
668
                imagecopyresampled($gdHist, $gdHistTemp, 0, 0, 0, 0, imagesx($gdHist), imagesy($gdHist), imagesx($gdHistTemp), imagesy($gdHistTemp));
669
                imagedestroy($gdHistTemp);
670
            } else {
671
                return false;
672
            }
673
674
            $this->WatermarkOverlay($gdimg, $gdHist, $alignment, $opacity, $margin_x, $margin_y);
675
            imagedestroy($gdHist);
676
            return true;
677
        }
678
        return false;
679
    }
680
681
    public function ImageBorder(&$gdimg, $border_width, $radius_x, $radius_y, $hexcolor_border)
682
    {
683
        $border_width = ($border_width ? $border_width : 1);
684
        $radius_x     = ($radius_x ? $radius_x : 0);
685
        $radius_y     = ($radius_y ? $radius_y : 0);
686
687
        $output_width  = imagesx($gdimg);
688
        $output_height = imagesy($gdimg);
689
690
        [$new_width, $new_height] = phpthumb_functions::ProportionalResize($output_width, $output_height, $output_width - max($border_width * 2, $radius_x), $output_height - max($border_width * 2, $radius_y));
691
        $offset_x = ($radius_x ? $output_width - $new_width - $radius_x : 0);
692
693
        if ($gd_border_canvas = phpthumb_functions::ImageCreateFunction($output_width, $output_height)) {
694
            imagesavealpha($gd_border_canvas, true);
695
            imagealphablending($gd_border_canvas, false);
696
            $color_background = phpthumb_functions::ImageColorAllocateAlphaSafe($gd_border_canvas, 255, 255, 255, 127);
697
            imagefilledrectangle($gd_border_canvas, 0, 0, $output_width, $output_height, $color_background);
698
699
            $color_border = phpthumb_functions::ImageHexColorAllocate($gd_border_canvas, (phpthumb_functions::IsHexColor($hexcolor_border) ? $hexcolor_border : '000000'));
700
701
            for ($i = 0; $i < $border_width; $i++) {
702
                imageline($gd_border_canvas, floor($offset_x / 2) + $radius_x, $i, $output_width - $radius_x - ceil($offset_x / 2), $i, $color_border); // top
703
                imageline($gd_border_canvas, floor($offset_x / 2) + $radius_x, $output_height - 1 - $i, $output_width - $radius_x - ceil($offset_x / 2), $output_height - 1 - $i, $color_border); // bottom
704
                imageline($gd_border_canvas, floor($offset_x / 2) + $i, $radius_y, floor($offset_x / 2) + $i, $output_height - $radius_y, $color_border); // left
705
                imageline($gd_border_canvas, $output_width - 1 - $i - ceil($offset_x / 2), $radius_y, $output_width - 1 - $i - ceil($offset_x / 2), $output_height - $radius_y, $color_border); // right
706
            }
707
708
            if ($radius_x && $radius_y) {
709
                // PHP bug: imagearc() with thicknesses > 1 give bad/undesirable/unpredicatable results
710
                // Solution: Draw multiple 1px arcs side-by-side.
711
712
                // Problem: parallel arcs give strange/ugly antialiasing problems
713
                // Solution: draw non-parallel arcs, from one side of the line thickness at the start angle
714
                //   to the opposite edge of the line thickness at the terminating angle
715
                for ($thickness_offset = 0; $thickness_offset < $border_width; $thickness_offset++) {
716
                    imagearc($gd_border_canvas, floor($offset_x / 2) + 1 + $radius_x, $thickness_offset - 1 + $radius_y, $radius_x * 2, $radius_y * 2, 180, 270, $color_border); // top-left
717
                    imagearc($gd_border_canvas, $output_width - $radius_x - 1 - ceil($offset_x / 2), $thickness_offset - 1 + $radius_y, $radius_x * 2, $radius_y * 2, 270, 360, $color_border); // top-right
718
                    imagearc($gd_border_canvas, $output_width - $radius_x - 1 - ceil($offset_x / 2), $output_height - $thickness_offset - $radius_y, $radius_x * 2, $radius_y * 2, 0, 90, $color_border); // bottom-right
719
                    imagearc($gd_border_canvas, floor($offset_x / 2) + 1 + $radius_x, $output_height - $thickness_offset - $radius_y, $radius_x * 2, $radius_y * 2, 90, 180, $color_border); // bottom-left
720
                }
721
                if ($border_width > 1) {
722
                    for ($thickness_offset = 0; $thickness_offset < $border_width; $thickness_offset++) {
723
                        imagearc($gd_border_canvas, floor($offset_x / 2) + $thickness_offset + $radius_x, $radius_y, $radius_x * 2, $radius_y * 2, 180, 270, $color_border); // top-left
724
                        imagearc($gd_border_canvas, $output_width - $thickness_offset - $radius_x - 1 - ceil($offset_x / 2), $radius_y, $radius_x * 2, $radius_y * 2, 270, 360, $color_border); // top-right
725
                        imagearc($gd_border_canvas, $output_width - $thickness_offset - $radius_x - 1 - ceil($offset_x / 2), $output_height - $radius_y, $radius_x * 2, $radius_y * 2, 0, 90, $color_border); // bottom-right
726
                        imagearc($gd_border_canvas, floor($offset_x / 2) + $thickness_offset + $radius_x, $output_height - $radius_y, $radius_x * 2, $radius_y * 2, 90, 180, $color_border); // bottom-left
727
                    }
728
                }
729
            }
730
            $this->phpThumbObject->ImageResizeFunction($gd_border_canvas, $gdimg, floor(($output_width - $new_width) / 2), round(($output_height - $new_height) / 2), 0, 0, $new_width, $new_height, $output_width, $output_height);
731
732
            imagedestroy($gdimg);
733
            $gdimg = phpthumb_functions::ImageCreateFunction($output_width, $output_height);
734
            imagesavealpha($gdimg, true);
735
            imagealphablending($gdimg, false);
736
            $gdimg_color_background = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 255, 255, 255, 127);
737
            imagefilledrectangle($gdimg, 0, 0, $output_width, $output_height, $gdimg_color_background);
738
739
            imagecopy($gdimg, $gd_border_canvas, 0, 0, 0, 0, $output_width, $output_height);
740
            imagedestroy($gd_border_canvas);
741
            return true;
742
        } else {
743
            $this->DebugMessage('FAILED: $gd_border_canvas = phpthumb_functions::ImageCreateFunction(' . $output_width . ', ' . $output_height . ')', __FILE__, __LINE__);
744
        }
745
        return false;
746
    }
747
748
    public static function ImprovedImageRotate(&$gdimg_source, $rotate_angle = 0, $config_background_hexcolor = 'FFFFFF', $bg = null, &$phpThumbObject)
749
    {
750
        while ($rotate_angle < 0) {
751
            $rotate_angle += 360;
752
        }
753
        $rotate_angle %= 360;
754
        if ($rotate_angle != 0) {
755
            $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_source, $config_background_hexcolor);
756
757
            if ((phpthumb_functions::gd_version() >= 2) && !$bg && ($rotate_angle % 90)) {
758
                //$this->DebugMessage('Using alpha rotate', __FILE__, __LINE__);
759
                if ($gdimg_rotate_mask = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_source), imagesy($gdimg_source))) {
760
                    $color_mask = [];
761
                    for ($i = 0; $i <= 255; $i++) {
762
                        $color_mask[$i] = imagecolorallocate($gdimg_rotate_mask, $i, $i, $i);
763
                    }
764
                    imagefilledrectangle($gdimg_rotate_mask, 0, 0, imagesx($gdimg_rotate_mask), imagesy($gdimg_rotate_mask), $color_mask[255]);
765
                    $imageX = imagesx($gdimg_source);
766
                    $imageY = imagesy($gdimg_source);
767
                    for ($x = 0; $x < $imageX; $x++) {
768
                        for ($y = 0; $y < $imageY; $y++) {
769
                            $pixelcolor = phpthumb_functions::GetPixelColor($gdimg_source, $x, $y);
770
                            imagesetpixel($gdimg_rotate_mask, $x, $y, $color_mask[255 - round($pixelcolor['alpha'] * 255 / 127)]);
771
                        }
772
                    }
773
                    $gdimg_rotate_mask = imagerotate($gdimg_rotate_mask, $rotate_angle, $color_mask[0]);
774
                    $gdimg_source      = imagerotate($gdimg_source, $rotate_angle, $background_color);
775
776
                    imagealphablending($gdimg_source, false);
777
                    imagesavealpha($gdimg_source, true);
778
                    //$this->is_alpha = true;
779
                    $phpThumbFilters = new self();
780
                    //$phpThumbFilters->phpThumbObject = $this;
781
                    $phpThumbFilters->phpThumbObject = $phpThumbObject;
782
                    $phpThumbFilters->ApplyMask($gdimg_rotate_mask, $gdimg_source);
783
784
                    imagedestroy($gdimg_rotate_mask);
785
                } else {
786
                    //$this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__);
787
                }
788
            } else {
789
                if (phpthumb_functions::gd_version() < 2) {
790
                    //$this->DebugMessage('Using non-alpha rotate because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
791
                } elseif ($bg) {
792
                    //$this->DebugMessage('Using non-alpha rotate because $this->bg is "'.$bg.'"', __FILE__, __LINE__);
793
                } elseif ($rotate_angle % 90) {
794
                    //$this->DebugMessage('Using non-alpha rotate because ($rotate_angle % 90) = "'.($rotate_angle % 90).'"', __FILE__, __LINE__);
795
                } else {
796
                    //$this->DebugMessage('Using non-alpha rotate because $this->thumbnailFormat is "'.$this->thumbnailFormat.'"', __FILE__, __LINE__);
797
                }
798
799
                if (imagecolortransparent($gdimg_source) >= 0) {
800
                    // imagerotate() forgets all about an image's transparency and sets the transparent color to black
801
                    // To compensate, flood-fill the transparent color of the source image with the specified background color first
802
                    // then rotate and the colors should match
803
804
                    if (!function_exists('imageistruecolor') || !imageistruecolor($gdimg_source)) {
805
                        // convert paletted image to true-color before rotating to prevent nasty aliasing artifacts
806
807
                        //$this->source_width  = imagesx($gdimg_source);
808
                        //$this->source_height = imagesy($gdimg_source);
809
                        $gdimg_newsrc     = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_source), imagesy($gdimg_source));
810
                        $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_newsrc, $config_background_hexcolor);
811
                        imagefilledrectangle($gdimg_newsrc, 0, 0, imagesx($gdimg_source), imagesy($gdimg_source), phpthumb_functions::ImageHexColorAllocate($gdimg_newsrc, $config_background_hexcolor));
812
                        imagecopy($gdimg_newsrc, $gdimg_source, 0, 0, 0, 0, imagesx($gdimg_source), imagesy($gdimg_source));
813
                        imagedestroy($gdimg_source);
814
                        unset($gdimg_source);
815
                        $gdimg_source = $gdimg_newsrc;
816
                        unset($gdimg_newsrc);
817
                    } else {
818
                        imagecolorset(
819
                            $gdimg_source,
820
                            imagecolortransparent($gdimg_source),
821
                            hexdec(substr($config_background_hexcolor, 0, 2)),
822
                            hexdec(substr($config_background_hexcolor, 2, 2)),
823
                            hexdec(substr($config_background_hexcolor, 4, 2))
824
                        );
825
826
                        imagecolortransparent($gdimg_source, -1);
827
                    }
828
                }
829
830
                $gdimg_source = imagerotate($gdimg_source, $rotate_angle, $background_color);
831
            }
832
        }
833
        return true;
834
    }
835
836
    public function MeanRemoval(&$gdimg)
837
    {
838
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
839
            if (imagefilter($gdimg, IMG_FILTER_MEAN_REMOVAL)) {
840
                return true;
841
            }
842
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_MEAN_REMOVAL)', __FILE__, __LINE__);
843
            // fall through and try it the hard way
844
        }
845
        // currently not implemented "the hard way"
846
        $this->DebugMessage('FAILED: phpthumb_filters::MeanRemoval($gdimg) [function not implemented]', __FILE__, __LINE__);
847
        return false;
848
    }
849
850
    public function Negative(&$gdimg)
851
    {
852
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
853
            if (imagefilter($gdimg, IMG_FILTER_NEGATE)) {
854
                return true;
855
            }
856
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_NEGATE)', __FILE__, __LINE__);
857
            // fall through and try it the hard way
858
        }
859
        $ImageSX = imagesx($gdimg);
860
        $ImageSY = imagesy($gdimg);
861
        for ($x = 0; $x < $ImageSX; $x++) {
862
            for ($y = 0; $y < $ImageSY; $y++) {
863
                $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
864
                $newColor     = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, ~$currentPixel['red'] & 0xFF, ~$currentPixel['green'] & 0xFF, ~$currentPixel['blue'] & 0xFF, $currentPixel['alpha']);
865
                imagesetpixel($gdimg, $x, $y, $newColor);
866
            }
867
        }
868
        return true;
869
    }
870
871
    public function RoundedImageCorners(&$gdimg, $radius_x, $radius_y)
872
    {
873
        // generate mask at twice desired resolution and downsample afterwards for easy antialiasing
874
        // mask is generated as a white double-size ellipse on a triple-size black background and copy-paste-resampled
875
        // onto a correct-size mask image as 4 corners due to errors when the entire mask is resampled at once (gray edges)
876
        if ($gdimg_cornermask_triple = phpthumb_functions::ImageCreateFunction($radius_x * 6, $radius_y * 6)) {
877
            if ($gdimg_cornermask = phpthumb_functions::ImageCreateFunction(imagesx($gdimg), imagesy($gdimg))) {
878
                $color_transparent = imagecolorallocate($gdimg_cornermask_triple, 255, 255, 255);
879
                imagefilledellipse($gdimg_cornermask_triple, $radius_x * 3, $radius_y * 3, $radius_x * 4, $radius_y * 4, $color_transparent);
880
881
                imagefilledrectangle($gdimg_cornermask, 0, 0, imagesx($gdimg), imagesy($gdimg), $color_transparent);
882
883
                imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, 0, 0, $radius_x, $radius_y, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2);
884
                imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, 0, imagesy($gdimg) - $radius_y, $radius_x, $radius_y * 3, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2);
885
                imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, imagesx($gdimg) - $radius_x, imagesy($gdimg) - $radius_y, $radius_x * 3, $radius_y * 3, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2);
886
                imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, imagesx($gdimg) - $radius_x, 0, $radius_x * 3, $radius_y, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2);
887
888
                $this->ApplyMask($gdimg_cornermask, $gdimg);
889
                imagedestroy($gdimg_cornermask);
890
                $this->DebugMessage('RoundedImageCorners(' . $radius_x . ', ' . $radius_y . ') succeeded', __FILE__, __LINE__);
891
                return true;
892
            } else {
893
                $this->DebugMessage('FAILED: $gdimg_cornermask = phpthumb_functions::ImageCreateFunction(' . imagesx($gdimg) . ', ' . imagesy($gdimg) . ')', __FILE__, __LINE__);
894
            }
895
            imagedestroy($gdimg_cornermask_triple);
896
        } else {
897
            $this->DebugMessage('FAILED: $gdimg_cornermask_triple = phpthumb_functions::ImageCreateFunction(' . ($radius_x * 6) . ', ' . ($radius_y * 6) . ')', __FILE__, __LINE__);
898
        }
899
        return false;
900
    }
901
902
    public function Saturation(&$gdimg, $amount, $color = '')
903
    {
904
        if ($amount == 0) {
905
            return true;
906
        } elseif ($amount > 0) {
907
            $amount = 0 - $amount;
908
        } else {
909
            $amount = abs($amount);
910
        }
911
        return $this->Desaturate($gdimg, $amount, $color);
912
    }
913
914
    public function Sepia(&$gdimg, $amount, $targetColor)
915
    {
916
        $amount      = (is_numeric($amount) ? max(0, min(100, $amount)) : 50);
917
        $amountPct   = $amount / 100;
918
        $targetColor = (phpthumb_functions::IsHexColor($targetColor) ? $targetColor : 'A28065');
919
920
        if ($amount == 0) {
921
            return true;
922
        }
923
924
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
925
            if (imagefilter($gdimg, IMG_FILTER_GRAYSCALE)) {
926
                $r = round($amountPct * hexdec(substr($targetColor, 0, 2)));
927
                $g = round($amountPct * hexdec(substr($targetColor, 2, 2)));
928
                $b = round($amountPct * hexdec(substr($targetColor, 4, 2)));
929
                if (imagefilter($gdimg, IMG_FILTER_COLORIZE, $r, $g, $b)) {
0 ignored issues
show
Bug introduced by
$b of type double is incompatible with the type integer expected by parameter $arg3 of imagefilter(). ( Ignorable by Annotation )

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

929
                if (imagefilter($gdimg, IMG_FILTER_COLORIZE, $r, $g, /** @scrutinizer ignore-type */ $b)) {
Loading history...
Bug introduced by
$r of type double is incompatible with the type integer expected by parameter $arg1 of imagefilter(). ( Ignorable by Annotation )

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

929
                if (imagefilter($gdimg, IMG_FILTER_COLORIZE, /** @scrutinizer ignore-type */ $r, $g, $b)) {
Loading history...
Bug introduced by
$g of type double is incompatible with the type integer expected by parameter $arg2 of imagefilter(). ( Ignorable by Annotation )

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

929
                if (imagefilter($gdimg, IMG_FILTER_COLORIZE, $r, /** @scrutinizer ignore-type */ $g, $b)) {
Loading history...
930
                    return true;
931
                }
932
                $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_COLORIZE)', __FILE__, __LINE__);
933
                // fall through and try it the hard way
934
935
            } else {
936
                $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_GRAYSCALE)', __FILE__, __LINE__);
937
                // fall through and try it the hard way
938
939
            }
940
        }
941
942
        $TargetPixel['red']   = hexdec(substr($targetColor, 0, 2));
0 ignored issues
show
Comprehensibility Best Practice introduced by
$TargetPixel was never initialized. Although not strictly required by PHP, it is generally a good practice to add $TargetPixel = array(); before regardless.
Loading history...
943
        $TargetPixel['green'] = hexdec(substr($targetColor, 2, 2));
944
        $TargetPixel['blue']  = hexdec(substr($targetColor, 4, 2));
945
946
        $ImageSX = imagesx($gdimg);
947
        $ImageSY = imagesy($gdimg);
948
        for ($x = 0; $x < $ImageSX; $x++) {
949
            for ($y = 0; $y < $ImageSY; $y++) {
950
                $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
951
                $GrayPixel     = phpthumb_functions::GrayscalePixel($OriginalPixel);
952
953
                // http://www.gimpguru.org/Tutorials/SepiaToning/
954
                // "In the traditional sepia toning process, the tinting occurs most in
955
                // the mid-tones: the lighter and darker areas appear to be closer to B&W."
956
                $SepiaAmount = ((128 - abs($GrayPixel['red'] - 128)) / 128) * $amountPct;
957
958
                $NewPixel = [];
959
                foreach ($TargetPixel as $key => $value) {
960
                    $NewPixel[$key] = round(max(0, min(255, $GrayPixel[$key] * (1 - $SepiaAmount) + ($TargetPixel[$key] * $SepiaAmount))));
961
                }
962
                $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue'], $OriginalPixel['alpha']);
963
                imagesetpixel($gdimg, $x, $y, $newColor);
964
            }
965
        }
966
        return true;
967
    }
968
969
    public function Smooth(&$gdimg, $amount = 6)
970
    {
971
        $amount = min(25, max(0, $amount));
972
        if ($amount == 0) {
973
            return true;
974
        }
975
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
976
            if (imagefilter($gdimg, IMG_FILTER_SMOOTH, $amount)) {
977
                return true;
978
            }
979
            $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_SMOOTH, ' . $amount . ')', __FILE__, __LINE__);
980
            // fall through and try it the hard way
981
        }
982
        // currently not implemented "the hard way"
983
        $this->DebugMessage('FAILED: phpthumb_filters::Smooth($gdimg, ' . $amount . ') [function not implemented]', __FILE__, __LINE__);
984
        return false;
985
    }
986
987
    public function SourceTransparentColorMask(&$gdimg, $hexcolor, $min_limit = 5, $max_limit = 10)
988
    {
989
        $width  = imagesx($gdimg);
990
        $height = imagesy($gdimg);
991
        if ($gdimg_mask = imagecreatetruecolor($width, $height)) {
992
            $R           = hexdec(substr($hexcolor, 0, 2));
993
            $G           = hexdec(substr($hexcolor, 2, 2));
994
            $B           = hexdec(substr($hexcolor, 4, 2));
995
            $targetPixel = ['red' => $R, 'green' => $G, 'blue' => $B];
996
            $cutoffRange = $max_limit - $min_limit;
997
            for ($x = 0; $x < $width; $x++) {
998
                for ($y = 0; $y < $height; $y++) {
999
                    $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
1000
                    $colorDiff    = phpthumb_functions::PixelColorDifferencePercent($currentPixel, $targetPixel);
1001
                    $grayLevel    = min($cutoffRange, max(0, -$min_limit + $colorDiff)) * (255 / max(1, $cutoffRange));
1002
                    $newColor     = imagecolorallocate($gdimg_mask, $grayLevel, $grayLevel, $grayLevel);
1003
                    imagesetpixel($gdimg_mask, $x, $y, $newColor);
1004
                }
1005
            }
1006
            return $gdimg_mask;
1007
        }
1008
        return false;
1009
    }
1010
1011
    public function Threshold(&$gdimg, $cutoff)
1012
    {
1013
        $width  = imagesx($gdimg);
1014
        $height = imagesy($gdimg);
1015
        $cutoff = min(255, max(0, ($cutoff ? $cutoff : 128)));
1016
        for ($x = 0; $x < $width; $x++) {
1017
            for ($y = 0; $y < $height; $y++) {
1018
                $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
1019
                $grayPixel    = phpthumb_functions::GrayscalePixel($currentPixel);
1020
                if ($grayPixel['red'] < $cutoff) {
1021
                    $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 0x00, 0x00, 0x00, $currentPixel['alpha']);
1022
                } else {
1023
                    $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 0xFF, 0xFF, 0xFF, $currentPixel['alpha']);
1024
                }
1025
                imagesetpixel($gdimg, $x, $y, $newColor);
1026
            }
1027
        }
1028
        return true;
1029
    }
1030
1031
    public function ImageTrueColorToPalette2(&$image, $dither, $ncolors)
1032
    {
1033
        // http://www.php.net/manual/en/function.imagetruecolortopalette.php
1034
        // zmorris at zsculpt dot com (17-Aug-2004 06:58)
1035
        $width      = imagesx($image);
1036
        $height     = imagesy($image);
1037
        $image_copy = imagecreatetruecolor($width, $height);
1038
        //imagecopymerge($image_copy, $image, 0, 0, 0, 0, $width, $height, 100);
1039
        imagecopy($image_copy, $image, 0, 0, 0, 0, $width, $height);
1040
        imagetruecolortopalette($image, $dither, $ncolors);
1041
        imagecolormatch($image_copy, $image);
1042
        imagedestroy($image_copy);
1043
        return true;
1044
    }
1045
1046
    public function ReduceColorDepth(&$gdimg, $colors = 256, $dither = true)
1047
    {
1048
        $colors = max(min($colors, 256), 2);
1049
        // imagetruecolortopalette usually makes ugly colors, the replacement is a bit better
1050
        //imagetruecolortopalette($gdimg, $dither, $colors);
1051
        $this->ImageTrueColorToPalette2($gdimg, $dither, $colors);
1052
        return true;
1053
    }
1054
1055
    public function WhiteBalance(&$gdimg, $targetColor = '')
1056
    {
1057
        if (phpthumb_functions::IsHexColor($targetColor)) {
1058
            $targetPixel = [
1059
                'red'   => hexdec(substr($targetColor, 0, 2)),
1060
                'green' => hexdec(substr($targetColor, 2, 2)),
1061
                'blue'  => hexdec(substr($targetColor, 4, 2)),
1062
            ];
1063
        } else {
1064
            $Analysis    = $this->HistogramAnalysis($gdimg, false);
1065
            $targetPixel = [
1066
                'red'   => max(array_keys($Analysis['red'])),
1067
                'green' => max(array_keys($Analysis['green'])),
1068
                'blue'  => max(array_keys($Analysis['blue'])),
1069
            ];
1070
        }
1071
        $grayValue = phpthumb_functions::GrayscaleValue($targetPixel['red'], $targetPixel['green'], $targetPixel['blue']);
1072
        $scaleR    = $grayValue / $targetPixel['red'];
1073
        $scaleG    = $grayValue / $targetPixel['green'];
1074
        $scaleB    = $grayValue / $targetPixel['blue'];
1075
1076
        for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) {
1077
            for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) {
1078
                $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
1079
                $newColor     = phpthumb_functions::ImageColorAllocateAlphaSafe(
1080
                    $gdimg,
1081
                    max(0, min(255, round($currentPixel['red'] * $scaleR))),
1082
                    max(0, min(255, round($currentPixel['green'] * $scaleG))),
1083
                    max(0, min(255, round($currentPixel['blue'] * $scaleB))),
1084
                    $currentPixel['alpha']
1085
                );
1086
                imagesetpixel($gdimg, $x, $y, $newColor);
1087
            }
1088
        }
1089
        return true;
1090
    }
1091
1092
    public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color = '000000', $ttffont = '', $opacity = 100, $margin = 5, $angle = 0, $bg_color = false, $bg_opacity = 0, $fillextend = '', $lineheight = 1.0)
1093
    {
1094
        // text watermark requested
1095
        if (!$text) {
1096
            return false;
1097
        }
1098
        imagealphablending($gdimg, true);
1099
1100
        if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)(@[LCR])?$#i', $alignment, $matches)) {
1101
            $originOffsetX = (int)$matches[1];
1102
            $originOffsetY = (int)$matches[2];
1103
            $alignment     = (@$matches[4] ? $matches[4] : 'L');
1104
            $margin        = 0;
1105
        } else {
1106
            $originOffsetX = 0;
1107
            $originOffsetY = 0;
1108
        }
1109
        $lineheight = min(100.0, max(0.01, (float)$lineheight));
1110
1111
        $metaTextArray = [
1112
            '^Fb' => $this->phpThumbObject->getimagesizeinfo['filesize'],
1113
            '^Fk' => round($this->phpThumbObject->getimagesizeinfo['filesize'] / 1024),
1114
            '^Fm' => round($this->phpThumbObject->getimagesizeinfo['filesize'] / 1048576),
1115
            '^X'  => $this->phpThumbObject->getimagesizeinfo[0],
1116
            '^Y'  => $this->phpThumbObject->getimagesizeinfo[1],
1117
            '^x'  => imagesx($gdimg),
1118
            '^y'  => imagesy($gdimg),
1119
            '^^'  => '^',
1120
        ];
1121
        $text          = strtr($text, $metaTextArray);
1122
1123
        $text      = str_replace([
1124
                                     "\r\n",
1125
                                     "\r",
1126
                                 ], "\n", $text);
1127
        $textlines = explode("\n", $text);
1128
        $this->DebugMessage('Processing ' . count($textlines) . ' lines of text', __FILE__, __LINE__);
1129
1130
        if (@is_readable($ttffont) && is_file($ttffont)) {
1131
            $opacity           = 100 - (int)max(min($opacity, 100), 0);
1132
            $letter_color_text = phpthumb_functions::ImageHexColorAllocate($gdimg, $hex_color, false, $opacity * 1.27);
1133
1134
            $this->DebugMessage('Using TTF font "' . $ttffont . '"', __FILE__, __LINE__);
1135
1136
            $TTFbox = imagettfbbox($size, $angle, $ttffont, $text);
1137
1138
            $min_x = min($TTFbox[0], $TTFbox[2], $TTFbox[4], $TTFbox[6]);
1139
            $max_x = max($TTFbox[0], $TTFbox[2], $TTFbox[4], $TTFbox[6]);
1140
            //$text_width = round($max_x - $min_x + ($size * 0.5));
1141
            $text_width = round($max_x - $min_x);
1142
1143
            $min_y = min($TTFbox[1], $TTFbox[3], $TTFbox[5], $TTFbox[7]);
1144
            $max_y = max($TTFbox[1], $TTFbox[3], $TTFbox[5], $TTFbox[7]);
1145
            //$text_height = round($max_y - $min_y + ($size * 0.5));
1146
            $text_height = round($max_y - $min_y);
1147
1148
            $TTFboxChar  = imagettfbbox($size, $angle, $ttffont, 'jH');
1149
            $char_min_y  = min($TTFboxChar[1], $TTFboxChar[3], $TTFboxChar[5], $TTFboxChar[7]);
1150
            $char_max_y  = max($TTFboxChar[1], $TTFboxChar[3], $TTFboxChar[5], $TTFboxChar[7]);
1151
            $char_height = round($char_max_y - $char_min_y);
1152
1153
            if ($alignment == '*') {
1154
                $text_origin_y = $char_height + $margin;
1155
                while (($text_origin_y - $text_height) < imagesy($gdimg)) {
1156
                    $text_origin_x = $margin;
1157
                    while ($text_origin_x < imagesx($gdimg)) {
1158
                        imagettftext($gdimg, $size, $angle, $text_origin_x, $text_origin_y, $letter_color_text, $ttffont, $text);
1159
                        $text_origin_x += ($text_width + $margin);
1160
                    }
1161
                    $text_origin_y += ($text_height + $margin) * $lineheight;
1162
                }
1163
            } else {
1164
                // this block for background color only
1165
1166
                $text_origin_x = 0;
1167
                $text_origin_y = 0;
1168
                switch ($alignment) {
1169
                    case '*':
1170
                        // handled separately
1171
                        break;
1172
1173
                    case 'T':
1174
                        $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((imagesx($gdimg) - $text_width) / 2));
1175
                        $text_origin_y = $char_height + $margin + $originOffsetY;
1176
                        break;
1177
1178
                    case 'B':
1179
                        $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((imagesx($gdimg) - $text_width) / 2));
1180
                        $text_origin_y = imagesy($gdimg) + $TTFbox[1] - $margin + $originOffsetY;
1181
                        break;
1182
1183
                    case 'L':
1184
                        $text_origin_x = $margin + $originOffsetX;
1185
                        $text_origin_y = ($originOffsetY ? $originOffsetY : round((imagesy($gdimg) - $text_height) / 2) + $char_height);
1186
                        break;
1187
1188
                    case 'R':
1189
                        $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : imagesx($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin);
1190
                        $text_origin_y = ($originOffsetY ? $originOffsetY : round((imagesy($gdimg) - $text_height) / 2) + $char_height);
1191
                        break;
1192
1193
                    case 'C':
1194
                        $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((imagesx($gdimg) - $text_width) / 2));
1195
                        $text_origin_y = ($originOffsetY ? $originOffsetY : round((imagesy($gdimg) - $text_height) / 2) + $char_height);
1196
                        break;
1197
1198
                    case 'TL':
1199
                        $text_origin_x = $margin + $originOffsetX;
1200
                        $text_origin_y = $char_height + $margin + $originOffsetY;
1201
                        break;
1202
1203
                    case 'TR':
1204
                        $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : imagesx($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin);
1205
                        $text_origin_y = $char_height + $margin + $originOffsetY;
1206
                        break;
1207
1208
                    case 'BL':
1209
                        $text_origin_x = $margin + $originOffsetX;
1210
                        $text_origin_y = imagesy($gdimg) + $TTFbox[1] - $margin + $originOffsetY;
1211
                        break;
1212
1213
                    case 'BR':
1214
                    default:
1215
                        $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : imagesx($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin);
1216
                        $text_origin_y = imagesy($gdimg) + $TTFbox[1] - $margin + $originOffsetY;
1217
                        break;
1218
                }
1219
1220
                if (phpthumb_functions::IsHexColor($bg_color)) {
1221
                    $text_background_alpha = round(127 * ((100 - min(max(0, $bg_opacity), 100)) / 100));
1222
                    $text_color_background = phpthumb_functions::ImageHexColorAllocate($gdimg, $bg_color, false, $text_background_alpha);
1223
                } else {
1224
                    $text_color_background = phpthumb_functions::ImageHexColorAllocate($gdimg, 'FFFFFF', false, 127);
1225
                }
1226
                $x1   = $text_origin_x + $min_x;
1227
                $y1   = $text_origin_y + $TTFbox[1];
1228
                $x2   = $text_origin_x + $min_x + $text_width;
1229
                $y2   = $text_origin_y + $TTFbox[1] - $text_height;
1230
                $x_TL = false !== stripos($fillextend, 'x') ? 0 : min($x1, $x2);
1231
                $y_TL = false !== stripos($fillextend, 'y') ? 0 : min($y1, $y2);
1232
                $x_BR = false !== stripos($fillextend, 'x') ? imagesx($gdimg) : max($x1, $x2);
1233
                $y_BR = false !== stripos($fillextend, 'y') ? imagesy($gdimg) : max($y1, $y2);
1234
                $this->DebugMessage('WatermarkText() calling imagefilledrectangle($gdimg, ' . $x_TL . ', ' . $y_TL . ', ' . $x_BR . ', ' . $y_BR . ', $text_color_background)', __FILE__, __LINE__);
1235
                imagefilledrectangle($gdimg, $x_TL, $y_TL, $x_BR, $y_BR, $text_color_background);
1236
1237
                // end block for background color only
1238
1239
                $y_offset = 0;
1240
                foreach ($textlines as $dummy => $line) {
1241
                    $TTFboxLine      = imagettfbbox($size, $angle, $ttffont, $line);
1242
                    $min_x_line      = min($TTFboxLine[0], $TTFboxLine[2], $TTFboxLine[4], $TTFboxLine[6]);
1243
                    $max_x_line      = max($TTFboxLine[0], $TTFboxLine[2], $TTFboxLine[4], $TTFboxLine[6]);
1244
                    $text_width_line = round($max_x_line - $min_x_line);
1245
1246
                    switch ($alignment) {
1247
                        // $text_origin_y set above, just re-set $text_origin_x here as needed
1248
1249
                        case 'L':
1250
                        case 'TL':
1251
                        case 'BL':
1252
                            // no change necessary
1253
                            break;
1254
1255
                        case 'C':
1256
                        case 'T':
1257
                        case 'B':
1258
                            $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width_line / 2) : round((imagesx($gdimg) - $text_width_line) / 2));
1259
                            break;
1260
1261
                        case 'R':
1262
                        case 'TR':
1263
                        case 'BR':
1264
                            $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width_line : imagesx($gdimg) - $text_width_line + $TTFbox[0] - $min_x + round($size * 0.25) - $margin);
1265
                            break;
1266
                    }
1267
1268
                    //imagettftext($gdimg, $size, $angle, $text_origin_x, $text_origin_y, $letter_color_text, $ttffont, $text);
1269
                    $this->DebugMessage('WatermarkText() calling imagettftext($gdimg, ' . $size . ', ' . $angle . ', ' . $text_origin_x . ', ' . ($text_origin_y + $y_offset) . ', $letter_color_text, ' . $ttffont . ', ' . $line . ')', __FILE__, __LINE__);
1270
                    imagettftext($gdimg, $size, $angle, $text_origin_x, $text_origin_y + $y_offset, $letter_color_text, $ttffont, $line);
1271
1272
                    $y_offset += $char_height * $lineheight;
1273
                }
1274
            }
1275
            return true;
1276
        } else {
1277
            $size = min(5, max(1, $size));
1278
            $this->DebugMessage('Using built-in font (size=' . $size . ') for text watermark' . ($ttffont ? ' because $ttffont !is_readable(' . $ttffont . ')' : ''), __FILE__, __LINE__);
1279
1280
            $text_width  = 0;
1281
            $text_height = 0;
1282
            foreach ($textlines as $dummy => $line) {
1283
                $text_width  = max($text_width, imagefontwidth($size) * strlen($line));
1284
                $text_height += imagefontheight($size);
1285
            }
1286
            if ($img_watermark = phpthumb_functions::ImageCreateFunction($text_width, $text_height)) {
1287
                imagealphablending($img_watermark, false);
1288
                if (phpthumb_functions::IsHexColor($bg_color)) {
1289
                    $text_background_alpha = round(127 * ((100 - min(max(0, $bg_opacity), 100)) / 100));
1290
                    $text_color_background = phpthumb_functions::ImageHexColorAllocate($img_watermark, $bg_color, false, $text_background_alpha);
1291
                } else {
1292
                    $text_color_background = phpthumb_functions::ImageHexColorAllocate($img_watermark, 'FFFFFF', false, 127);
1293
                }
1294
                $this->DebugMessage('WatermarkText() calling imagefilledrectangle($img_watermark, 0, 0, ' . imagesx($img_watermark) . ', ' . imagesy($img_watermark) . ', $text_color_background)', __FILE__, __LINE__);
1295
                imagefilledrectangle($img_watermark, 0, 0, imagesx($img_watermark), imagesy($img_watermark), $text_color_background);
1296
1297
                $img_watermark_mask    = false;
1298
                $mask_color_background = false;
1299
                $mask_color_watermark  = false;
1300
                if ($angle && function_exists('imagerotate')) {
1301
                    // using $img_watermark_mask is pointless if imagerotate function isn't available
1302
                    if ($img_watermark_mask = phpthumb_functions::ImageCreateFunction($text_width, $text_height)) {
1303
                        $mask_color_background = imagecolorallocate($img_watermark_mask, 0, 0, 0);
1304
                        imagealphablending($img_watermark_mask, false);
1305
                        imagefilledrectangle($img_watermark_mask, 0, 0, imagesx($img_watermark_mask), imagesy($img_watermark_mask), $mask_color_background);
1306
                        $mask_color_watermark = imagecolorallocate($img_watermark_mask, 255, 255, 255);
1307
                    }
1308
                }
1309
1310
                $text_color_watermark = phpthumb_functions::ImageHexColorAllocate($img_watermark, $hex_color);
1311
                $x_offset             = 0;
1312
                foreach ($textlines as $key => $line) {
1313
                    switch ($alignment) {
1314
                        case 'C':
1315
                            $x_offset      = round(($text_width - (imagefontwidth($size) * strlen($line))) / 2);
1316
                            $originOffsetX = (imagesx($gdimg) - imagesx($img_watermark)) / 2;
1317
                            $originOffsetY = (imagesy($gdimg) - imagesy($img_watermark)) / 2;
1318
                            break;
1319
1320
                        case 'T':
1321
                            $x_offset      = round(($text_width - (imagefontwidth($size) * strlen($line))) / 2);
1322
                            $originOffsetX = (imagesx($gdimg) - imagesx($img_watermark)) / 2;
1323
                            $originOffsetY = $margin;
1324
                            break;
1325
1326
                        case 'B':
1327
                            $x_offset      = round(($text_width - (imagefontwidth($size) * strlen($line))) / 2);
1328
                            $originOffsetX = (imagesx($gdimg) - imagesx($img_watermark)) / 2;
1329
                            $originOffsetY = imagesy($gdimg) - imagesy($img_watermark) - $margin;
1330
                            break;
1331
1332
                        case 'L':
1333
                            $x_offset      = 0;
1334
                            $originOffsetX = $margin;
1335
                            $originOffsetY = (imagesy($gdimg) - imagesy($img_watermark)) / 2;
1336
                            break;
1337
1338
                        case 'TL':
1339
                            $x_offset      = 0;
1340
                            $originOffsetX = $margin;
1341
                            $originOffsetY = $margin;
1342
                            break;
1343
1344
                        case 'BL':
1345
                            $x_offset      = 0;
1346
                            $originOffsetX = $margin;
1347
                            $originOffsetY = imagesy($gdimg) - imagesy($img_watermark) - $margin;
1348
                            break;
1349
1350
                        case 'R':
1351
                            $x_offset      = $text_width - (imagefontwidth($size) * strlen($line));
1352
                            $originOffsetX = imagesx($gdimg) - imagesx($img_watermark) - $margin;
1353
                            $originOffsetY = (imagesy($gdimg) - imagesy($img_watermark)) / 2;
1354
                            break;
1355
1356
                        case 'TR':
1357
                            $x_offset      = $text_width - (imagefontwidth($size) * strlen($line));
1358
                            $originOffsetX = imagesx($gdimg) - imagesx($img_watermark) - $margin;
1359
                            $originOffsetY = $margin;
1360
                            break;
1361
1362
                        case 'BR':
1363
                        default:
1364
                            if (!empty($originOffsetX) || !empty($originOffsetY)) {
1365
                                // absolute pixel positioning
1366
                            } else {
1367
                                $x_offset      = $text_width - (imagefontwidth($size) * strlen($line));
1368
                                $originOffsetX = imagesx($gdimg) - imagesx($img_watermark) - $margin;
1369
                                $originOffsetY = imagesy($gdimg) - imagesy($img_watermark) - $margin;
1370
                            }
1371
                            break;
1372
                    }
1373
                    $this->DebugMessage('WatermarkText() calling imagestring($img_watermark, ' . $size . ', ' . $x_offset . ', ' . ($key * imagefontheight($size)) . ', ' . $line . ', $text_color_watermark)', __FILE__, __LINE__);
1374
                    imagestring($img_watermark, $size, $x_offset, $key * imagefontheight($size), $line, $text_color_watermark);
1375
                    if ($angle && $img_watermark_mask) {
1376
                        $this->DebugMessage('WatermarkText() calling imagestring($img_watermark_mask, ' . $size . ', ' . $x_offset . ', ' . ($key * imagefontheight($size) * $lineheight) . ', ' . $text . ', $mask_color_watermark)', __FILE__, __LINE__);
1377
                        imagestring($img_watermark_mask, $size, $x_offset, $key * imagefontheight($size) * $lineheight, $text, $mask_color_watermark);
1378
                    }
1379
                }
1380
                if ($angle && $img_watermark_mask) {
1381
                    $img_watermark      = imagerotate($img_watermark, $angle, $text_color_background);
1382
                    $img_watermark_mask = imagerotate($img_watermark_mask, $angle, $mask_color_background);
1383
                    $this->ApplyMask($img_watermark_mask, $img_watermark);
1384
                }
1385
                //phpthumb_filters::WatermarkOverlay($gdimg, $img_watermark, $alignment, $opacity, $margin);
1386
                $this->DebugMessage('WatermarkText() calling phpthumb_filters::WatermarkOverlay($gdimg, $img_watermark, ' . ($originOffsetX . 'x' . $originOffsetY) . ', ' . $opacity . ', 0)', __FILE__, __LINE__);
1387
                $this->WatermarkOverlay($gdimg, $img_watermark, $originOffsetX . 'x' . $originOffsetY, $opacity, 0);
1388
                imagedestroy($img_watermark);
1389
                return true;
1390
            }
1391
        }
1392
        return false;
1393
    }
1394
1395
    public function WatermarkOverlay(&$gdimg_dest, &$img_watermark, $alignment = '*', $opacity = 50, $margin_x = 5, $margin_y = null)
1396
    {
1397
        if ((is_resource($gdimg_dest) || (is_object($gdimg_dest) && $gdimg_dest instanceof \GdImage)) && (is_resource($img_watermark) || (is_object($img_watermark) && $img_watermark instanceof \GdImage))) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (is_resource($gdimg_dest...mark instanceof GdImage, Probably Intended Meaning: is_resource($gdimg_dest)...ark instanceof GdImage)
Loading history...
1398
            $img_source_width          = imagesx($gdimg_dest);
1399
            $img_source_height         = imagesy($gdimg_dest);
1400
            $watermark_source_width    = imagesx($img_watermark);
1401
            $watermark_source_height   = imagesy($img_watermark);
1402
            $watermark_opacity_percent = max(0, min(100, $opacity));
1403
            $margin_y                  = (null === $margin_y ? $margin_x : $margin_y);
1404
            $watermark_margin_x        = ((($margin_x > 0) && ($margin_x < 1)) ? round((1 - $margin_x) * $img_source_width) : $margin_x);
1405
            $watermark_margin_y        = ((($margin_y > 0) && ($margin_y < 1)) ? round((1 - $margin_y) * $img_source_height) : $margin_y);
1406
            $watermark_destination_x   = 0;
1407
            $watermark_destination_y   = 0;
1408
            if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
1409
                $watermark_destination_x = (int)$matches[1];
1410
                $watermark_destination_y = (int)$matches[2];
1411
            } else {
1412
                switch ($alignment) {
1413
                    case '*':
1414
                        if ($gdimg_tiledwatermark = phpthumb_functions::ImageCreateFunction($img_source_width, $img_source_height)) {
1415
                            imagealphablending($gdimg_tiledwatermark, false);
1416
                            imagesavealpha($gdimg_tiledwatermark, true);
1417
                            $text_color_transparent = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_tiledwatermark, 255, 0, 255, 127);
1418
                            imagefill($gdimg_tiledwatermark, 0, 0, $text_color_transparent);
1419
1420
                            // set the tiled image transparent color to whatever the untiled image transparency index is
1421
                            //						imagecolortransparent($gdimg_tiledwatermark, imagecolortransparent($img_watermark));
1422
1423
                            // a "cleaner" way of doing it, but can't handle the margin feature :(
1424
                            //						imagesettile($gdimg_tiledwatermark, $img_watermark);
1425
                            //						imagefill($gdimg_tiledwatermark, 0, 0, IMG_COLOR_TILED);
1426
                            //						break;
1427
1428
                            //						imagefill($gdimg_tiledwatermark, 0, 0, imagecolortransparent($gdimg_tiledwatermark));
1429
                            // tile the image as many times as can fit
1430
                            for ($x = $watermark_margin_x; $x < ($img_source_width + $watermark_source_width); $x += ($watermark_source_width + $watermark_margin_x)) {
1431
                                for ($y = $watermark_margin_y; $y < ($img_source_height + $watermark_source_height); $y += ($watermark_source_height + $watermark_margin_y)) {
1432
                                    imagecopy(
1433
                                        $gdimg_tiledwatermark,
1434
                                        $img_watermark,
1435
                                        $x,
0 ignored issues
show
Bug introduced by
It seems like $x can also be of type double; however, parameter $dst_x of imagecopy() 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

1435
                                        /** @scrutinizer ignore-type */ $x,
Loading history...
1436
                                        $y,
0 ignored issues
show
Bug introduced by
It seems like $y can also be of type double; however, parameter $dst_y of imagecopy() 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

1436
                                        /** @scrutinizer ignore-type */ $y,
Loading history...
1437
                                        0,
1438
                                        0,
1439
                                        min($watermark_source_width, $img_source_width - $x - $watermark_margin_x),
1440
                                        min($watermark_source_height, $img_source_height - $y - $watermark_margin_y)
1441
                                    );
1442
                                }
1443
                            }
1444
1445
                            $watermark_source_width  = imagesx($gdimg_tiledwatermark);
1446
                            $watermark_source_height = imagesy($gdimg_tiledwatermark);
1447
                            $watermark_destination_x = 0;
1448
                            $watermark_destination_y = 0;
1449
1450
                            imagedestroy($img_watermark);
1451
                            $img_watermark = $gdimg_tiledwatermark;
1452
                        }
1453
                        break;
1454
1455
                    case 'T':
1456
                        $watermark_destination_x = round((($img_source_width / 2) - ($watermark_source_width / 2)) + $watermark_margin_x);
1457
                        $watermark_destination_y = $watermark_margin_y;
1458
                        break;
1459
1460
                    case 'B':
1461
                        $watermark_destination_x = round((($img_source_width / 2) - ($watermark_source_width / 2)) + $watermark_margin_x);
1462
                        $watermark_destination_y = $img_source_height - $watermark_source_height - $watermark_margin_y;
1463
                        break;
1464
1465
                    case 'L':
1466
                        $watermark_destination_x = $watermark_margin_x;
1467
                        $watermark_destination_y = round((($img_source_height / 2) - ($watermark_source_height / 2)) + $watermark_margin_y);
1468
                        break;
1469
1470
                    case 'R':
1471
                        $watermark_destination_x = $img_source_width - $watermark_source_width - $watermark_margin_x;
1472
                        $watermark_destination_y = round((($img_source_height / 2) - ($watermark_source_height / 2)) + $watermark_margin_y);
1473
                        break;
1474
1475
                    case 'C':
1476
                        $watermark_destination_x = round(($img_source_width / 2) - ($watermark_source_width / 2));
1477
                        $watermark_destination_y = round(($img_source_height / 2) - ($watermark_source_height / 2));
1478
                        break;
1479
1480
                    case 'TL':
1481
                        $watermark_destination_x = $watermark_margin_x;
1482
                        $watermark_destination_y = $watermark_margin_y;
1483
                        break;
1484
1485
                    case 'TR':
1486
                        $watermark_destination_x = $img_source_width - $watermark_source_width - $watermark_margin_x;
1487
                        $watermark_destination_y = $watermark_margin_y;
1488
                        break;
1489
1490
                    case 'BL':
1491
                        $watermark_destination_x = $watermark_margin_x;
1492
                        $watermark_destination_y = $img_source_height - $watermark_source_height - $watermark_margin_y;
1493
                        break;
1494
1495
                    case 'BR':
1496
                    default:
1497
                        $watermark_destination_x = $img_source_width - $watermark_source_width - $watermark_margin_x;
1498
                        $watermark_destination_y = $img_source_height - $watermark_source_height - $watermark_margin_y;
1499
                        break;
1500
                }
1501
            }
1502
            imagealphablending($gdimg_dest, false);
1503
            imagesavealpha($gdimg_dest, true);
1504
            imagesavealpha($img_watermark, true);
1505
            phpthumb_functions::ImageCopyRespectAlpha($gdimg_dest, $img_watermark, $watermark_destination_x, $watermark_destination_y, 0, 0, $watermark_source_width, $watermark_source_height, $watermark_opacity_percent);
1506
1507
            return true;
1508
        }
1509
        return false;
1510
    }
1511
}
1512