image_gd   F
last analyzed

Complexity

Total Complexity 115

Size/Duplication

Total Lines 348
Duplicated Lines 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 196
c 1
b 1
f 0
dl 0
loc 348
rs 2
wmc 115

18 Methods

Rating   Name   Duplication   Size   Complexity  
C resizeFit() 0 38 15
A output() 0 7 2
F watermark() 0 29 19
A imageFilledRectangle() 0 7 2
A output_jpeg() 0 8 5
A flipVertical() 0 9 2
A flipHorizontal() 0 9 2
A imageCopyResampled() 0 32 6
B resize() 0 9 7
B checkImage() 0 9 8
A output_png() 0 9 6
A output_gif() 0 7 4
B getImage() 0 20 11
A getBlankImage() 0 6 1
B gdColor() 0 34 10
C resizeCrop() 0 54 12
A available() 0 3 1
A rotate() 0 11 2

How to fix   Complexity   

Complex Class

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

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

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

1
<?php
2
3
/** This file is part of KCFinder project
4
 *
5
 * @desc      GD image driver class
6
 * @package   KCFinder
7
 * @version   3.12
8
 * @author    Pavel Tzonkov <[email protected]>
9
 * @copyright 2010-2014 KCFinder Project
10
 * @license   http://opensource.org/licenses/GPL-3.0 GPLv3
11
 * @license   http://opensource.org/licenses/LGPL-3.0 LGPLv3
12
 * @link      http://kcfinder.sunhater.com
13
 */
14
15
namespace kcfinder;
16
17
class image_gd extends image
18
{
19
20
    // ABSTRACT PUBLIC METHODS
21
22
    public function resize($width, $height)
23
    {
24
        if (!$width) {
25
            $width = 1;
26
        }
27
        if (!$height) {
28
            $height = 1;
29
        }
30
        return ((false !== ($img = new image_gd([$width, $height]))) && $img->imageCopyResampled($this) && (false !== ($this->image = $img->image)) && (false !== ($this->width = $img->width)) && (false !== ($this->height = $img->height)));
31
    }
32
33
    public function resizeFit($width, $height, $background = false)
34
    {
35
        if ((!$width && !$height) || (($width == $this->width) && ($height == $this->height))) {
36
            return true;
37
        }
38
        if (!$width || (($height / $width) < ($this->height / $this->width))) {
39
            $h = $height;
40
            $w = round(($this->width * $h) / $this->height);
41
        } elseif (!$height || (($width / $height) < ($this->width / $this->height))) {
42
            $w = $width;
43
            $h = round(($this->height * $w) / $this->width);
44
        } else {
45
            $w = $width;
46
            $h = $height;
47
        }
48
        if (!$w) {
49
            $w = 1;
50
        }
51
        if (!$h) {
52
            $h = 1;
53
        }
54
55
        if (false === $background) {
56
            return $this->resize($w, $h);
57
        } else {
58
            $img = new image_gd([$width, $height]);
59
            $x   = round(($width - $w) / 2);
60
            $y   = round(($height - $h) / 2);
61
62
            if ((false === $this->resize($w, $h)) || (false === $img->imageFilledRectangle(0, 0, $width, $height, $background)) || (false === $img->imageCopyResampled($this->image, $x, $y, 0, 0, $w, $h))) {
63
                return false;
64
            }
65
66
            $this->image  = $img->image;
67
            $this->width  = $width;
68
            $this->height = $height;
69
70
            return true;
71
        }
72
    }
73
74
    public function resizeCrop($width, $height, $offset = false)
75
    {
76
        if (($this->width / $this->height) > ($width / $height)) {
77
            $h = $height;
78
            $w = ($this->width * $h) / $this->height;
79
            $y = 0;
80
            if (false !== $offset) {
81
                if ($offset > 0) {
82
                    $offset = -$offset;
83
                }
84
                if (($w + $offset) <= $width) {
85
                    $offset = $width - $w;
86
                }
87
                $x = $offset;
88
            } else {
89
                $x = ($width - $w) / 2;
90
            }
91
        } else {
92
            $w = $width;
93
            $h = ($this->height * $w) / $this->width;
94
            $x = 0;
95
            if (false !== $offset) {
96
                if ($offset > 0) {
97
                    $offset = -$offset;
98
                }
99
                if (($h + $offset) <= $height) {
100
                    $offset = $height - $h;
101
                }
102
                $y = $offset;
103
            } else {
104
                $y = ($height - $h) / 2;
105
            }
106
        }
107
108
        $x = round($x);
109
        $y = round($y);
110
        $w = round($w);
111
        $h = round($h);
112
        if (!$w) {
113
            $w = 1;
114
        }
115
        if (!$h) {
116
            $h = 1;
117
        }
118
119
        $return = ((false !== ($img = new image_gd([$width, $height])))) && (false !== ($img->imageCopyResampled($this->image, $x, $y, 0, 0, $w, $h)));
120
121
        if ($return) {
122
            $this->image  = $img->image;
123
            $this->width  = $w;
124
            $this->height = $h;
125
        }
126
127
        return $return;
128
    }
129
130
    public function rotate($angle, $background = '#000000')
131
    {
132
        $angle = -$angle;
133
        $img   = @imagerotate($this->image, $angle, $this->gdColor($background));
0 ignored issues
show
Bug introduced by
It seems like $this->gdColor($background) can also be of type false; however, parameter $bgd_color of imagerotate() 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

133
        $img   = @imagerotate($this->image, $angle, /** @scrutinizer ignore-type */ $this->gdColor($background));
Loading history...
134
        if (false === $img) {
135
            return false;
136
        }
137
        $this->width  = imagesx($img);
138
        $this->height = imagesy($img);
139
        $this->image  = $img;
140
        return true;
141
    }
142
143
    public function flipHorizontal()
144
    {
145
        $img = imagecreatetruecolor($this->width, $this->height);
146
        if (imagecopyresampled($img, $this->image, 0, 0, ($this->width - 1), 0, $this->width, $this->height, -$this->width, $this->height)) {
147
            $this->image = $img;
148
        } else {
149
            return false;
150
        }
151
        return true;
152
    }
153
154
    public function flipVertical()
155
    {
156
        $img = imagecreatetruecolor($this->width, $this->height);
157
        if (imagecopyresampled($img, $this->image, 0, 0, 0, ($this->height - 1), $this->width, $this->height, $this->width, -$this->height)) {
158
            $this->image = $img;
159
        } else {
160
            return false;
161
        }
162
        return true;
163
    }
164
165
    public function watermark($file, $left = false, $top = false)
166
    {
167
        $info = getimagesize($file);
168
        list($w, $h, $t) = $info;
169
        if (!in_array($t, [IMAGETYPE_PNG, IMAGETYPE_GIF])) {
170
            return false;
171
        }
172
        $imagecreate = (IMAGETYPE_PNG == $t) ? 'imagecreatefrompng' : 'imagecreatefromgif';
173
174
        if (!@imagealphablending($this->image, true) || (false === ($wm = @$imagecreate($file)))) {
175
            return false;
176
        }
177
178
        $w = imagesx($wm);
179
        $h = imagesy($wm);
180
        $x = (true === $left) ? 0 : ((null === $left) ? round(($this->width - $w) / 2) : (((false === $left) || !preg_match('/^\d+$/', $left)) ? ($this->width - $w) : $left));
181
        $y = (true === $top) ? 0 : ((null === $top) ? round(($this->height - $h) / 2) : (((false === $top) || !preg_match('/^\d+$/', $top)) ? ($this->height - $h) : $top));
182
183
        if ((($x + $w) > $this->width) || (($y + $h) > $this->height) || ($x < 0) || ($y < 0)) {
184
            return false;
185
        }
186
187
        if ((false === $wm) || !@imagecopy($this->image, $wm, $x, $y, 0, 0, $w, $h)) {
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

187
        if ((false === $wm) || !@imagecopy($this->image, $wm, $x, /** @scrutinizer ignore-type */ $y, 0, 0, $w, $h)) {
Loading history...
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

187
        if ((false === $wm) || !@imagecopy($this->image, $wm, /** @scrutinizer ignore-type */ $x, $y, 0, 0, $w, $h)) {
Loading history...
188
            return false;
189
        }
190
191
        @imagealphablending($this->image, false);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for imagealphablending(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

191
        /** @scrutinizer ignore-unhandled */ @imagealphablending($this->image, false);

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

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

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

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

192
        /** @scrutinizer ignore-unhandled */ @imagesavealpha($this->image, true);

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
193
        return true;
194
    }
195
196
    public function output($type = 'jpeg', array $options = [])
197
    {
198
        $method = "output_$type";
199
        if (!method_exists($this, $method)) {
200
            return false;
201
        }
202
        return $this->$method($options);
203
    }
204
205
    // ABSTRACT PROTECTED METHODS
206
207
    protected function getBlankImage($width, $height)
208
    {
209
        $image = imagecreatetruecolor($width, $height);
210
        imagealphablending($image, false);
211
        imagesavealpha($image, true);
212
        return $image;
213
    }
214
215
    protected function getImage($image, &$width, &$height)
216
    {
217
        if (is_resource($image) && ('gd' == get_resource_type($image))) {
218
            $width  = @imagesx($image);
219
            $height = @imagesy($image);
220
            imagealphablending($image, false);
221
            imagesavealpha($image, true);
222
            return $image;
223
        } elseif (is_string($image) && (false !== (list($width, $height, $t) = @getimagesize($image)))) {
224
            $image = (IMAGETYPE_GIF == $t) ? @imagecreatefromgif($image) : ((IMAGETYPE_WBMP == $t) ? @imagecreatefromwbmp($image) : ((IMAGETYPE_JPEG == $t) ? @imagecreatefromjpeg($image) : ((IMAGETYPE_PNG == $t) ? @imagecreatefrompng($image) : ((IMAGETYPE_XBM == $t) ? @imagecreatefromxbm(
225
                $image
226
            ) : false))));
227
228
            if (IMAGETYPE_PNG == $t) {
229
                imagealphablending($image, false);
0 ignored issues
show
Bug introduced by
It seems like $image can also be of type false; however, parameter $image of imagealphablending() does only seem to accept GdImage|resource, 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

229
                imagealphablending(/** @scrutinizer ignore-type */ $image, false);
Loading history...
230
                imagesavealpha($image, true);
0 ignored issues
show
Bug introduced by
It seems like $image can also be of type false; however, parameter $image of imagesavealpha() does only seem to accept GdImage|resource, 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

230
                imagesavealpha(/** @scrutinizer ignore-type */ $image, true);
Loading history...
231
            }
232
            return $image;
233
        } else {
234
            return false;
235
        }
236
    }
237
238
    // PSEUDO-ABSTRACT STATIC METHODS
239
240
    public static function available()
241
    {
242
        return function_exists('imagecreatefromjpeg');
243
    }
244
245
    public static function checkImage($file)
246
    {
247
        if (!is_string($file) || ((false === (list($width, $height, $t) = @getimagesize($file))))) {
248
            return false;
249
        }
250
251
        $img = (IMAGETYPE_GIF == $t) ? @imagecreatefromgif($file) : ((IMAGETYPE_WBMP == $t) ? @imagecreatefromwbmp($file) : ((IMAGETYPE_JPEG == $t) ? @imagecreatefromjpeg($file) : ((IMAGETYPE_PNG == $t) ? @imagecreatefrompng($file) : ((IMAGETYPE_XBM == $t) ? @imagecreatefromxbm($file) : false))));
252
253
        return (false !== $img);
254
    }
255
256
    // OWN METHODS
257
258
    protected function output_png(array $options = [])
259
    {
260
        $file    = isset($options['file']) ? $options['file'] : null;
261
        $quality = isset($options['quality']) ? $options['quality'] : null;
262
        $filters = isset($options['filters']) ? $options['filters'] : null;
263
        if ((null === $file) && !headers_sent()) {
264
            header('Content-Type: image/png');
265
        }
266
        return imagepng($this->image, $file, $quality, $filters);
267
    }
268
269
    protected function output_jpeg(array $options = [])
270
    {
271
        $file    = isset($options['file']) ? $options['file'] : null;
272
        $quality = isset($options['quality']) ? $options['quality'] : self::DEFAULT_JPEG_QUALITY;
273
        if ((null === $file) && !headers_sent()) {
274
            header('Content-Type: image/jpeg');
275
        }
276
        return imagejpeg($this->image, $file, $quality);
277
    }
278
279
    protected function output_gif(array $options = [])
280
    {
281
        $file = isset($options['file']) ? $options['file'] : null;
282
        if (isset($options['file']) && !headers_sent()) {
283
            header('Content-Type: image/gif');
284
        }
285
        return imagegif($this->image, $file);
286
    }
287
288
    protected function gdColor()
289
    {
290
        $args = func_get_args();
291
292
        $exprRGB  = '/^rgb\(\s*(\d{1,3})\s*\,\s*(\d{1,3})\s*\,\s*(\d{1,3})\s*\)$/i';
293
        $exprHex1 = '/^\#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i';
294
        $exprHex2 = '/^\#?([0-9a-f])([0-9a-f])([0-9a-f])$/i';
295
        $exprByte = '/^([01]?\d?\d|2[0-4]\d|25[0-5])$/';
296
297
        if (!isset($args[0])) {
298
            return false;
299
        }
300
301
        if (3 == count($args[0])) {
302
            list($r, $g, $b) = $args[0];
303
        } elseif (preg_match($exprRGB, $args[0], $match)) {
304
            list($tmp, $r, $g, $b) = $match;
305
        } elseif (preg_match($exprHex1, $args[0], $match)) {
306
            list($tmp, $r, $g, $b) = $match;
307
            $r = hexdec($r);
308
            $g = hexdec($g);
309
            $b = hexdec($b);
310
        } elseif (preg_match($exprHex2, $args[0], $match)) {
311
            list($tmp, $r, $g, $b) = $match;
312
            $r = hexdec("$r$r");
313
            $g = hexdec("$g$g");
314
            $b = hexdec("$b$b");
315
        } elseif ((3 == count($args)) && preg_match($exprByte, $args[0]) && preg_match($exprByte, $args[1]) && preg_match($exprByte, $args[2])) {
316
            list($r, $g, $b) = $args;
317
        } else {
318
            return false;
319
        }
320
321
        return imagecolorallocate($this->image, $r, $g, $b);
322
    }
323
324
    protected function imageFilledRectangle($x1, $y1, $x2, $y2, $color)
325
    {
326
        $color = $this->gdColor($color);
327
        if (false === $color) {
328
            return false;
329
        }
330
        return imageFilledRectangle($this->image, $x1, $y1, $x2, $y2, $color);
331
    }
332
333
    protected function imageCopyResampled(
334
        $src,
335
        $dstX = 0,
336
        $dstY = 0,
337
        $srcX = 0,
338
        $srcY = 0,
339
        $dstW = null,
340
        $dstH = null,
341
        $srcW = null,
342
        $srcH = null
343
    ) {
344
        $imageDetails = $this->buildImage($src);
345
346
        if (false === $imageDetails) {
0 ignored issues
show
introduced by
The condition false === $imageDetails is always false.
Loading history...
347
            return false;
348
        }
349
350
        list($src, $srcWidth, $srcHeight) = $imageDetails;
351
352
        if (is_null($dstW)) {
353
            $dstW = $this->width - $dstW;
354
        }
355
        if (is_null($dstH)) {
356
            $dstH = $this->height - $dstY;
357
        }
358
        if (is_null($srcW)) {
359
            $srcW = $srcWidth - $srcX;
360
        }
361
        if (is_null($srcH)) {
362
            $srcH = $srcHeight - $srcY;
363
        }
364
        return imageCopyResampled($this->image, $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
365
    }
366
}
367