Test Setup Failed
Push — master ( f71949...6c6bd7 )
by Julito
55:21
created

GDWrapper::resize()   C

Complexity

Conditions 9
Paths 11

Size

Total Lines 58
Code Lines 49

Duplication

Lines 8
Ratio 13.79 %

Importance

Changes 0
Metric Value
cc 9
eloc 49
nc 11
nop 4
dl 8
loc 58
rs 6.9928
c 0
b 0
f 0

How to fix   Long Method   

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:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 * Image class
6
 * This class provides a layer to manage images
7
 * @author Julio Montoya <[email protected]>
8
 * @package chamilo.include.image
9
 * @todo move in a DB configuration setting
10
 */
11
class Image
12
{
13
    public $image_wrapper = null;
14
15
    /**
16
     * Image constructor.
17
     * @param string $path
18
     */
19
    public function __construct($path)
20
    {
21
        if (IMAGE_PROCESSOR == 'gd') {
22
            $this->image_wrapper = new GDWrapper($path);
23
        } else {
24
            if (class_exists('Imagick')) {
25
                $this->image_wrapper = new ImagickWrapper($path);
26
            } else {
27
                echo Display::return_message('Class Imagick not found', 'warning');
28
                exit;
29
            }
30
        }
31
    }
32
33
    public function resize($max_size_for_picture)
34
    {
35
        $image_size = $this->get_image_size($this->image_wrapper->path);
36
        $width = $image_size['width'];
37
        $height = $image_size['height'];
38
        if ($width >= $height) {
39 View Code Duplication
            if ($width >= $max_size_for_picture) {
40
                // scale height
41
                $new_height = round($height * ($max_size_for_picture / $width));
42
                $this->image_wrapper->resize($max_size_for_picture, $new_height, 0);
43
            }
44 View Code Duplication
        } else { // height > $width
45
            if ($height >= $max_size_for_picture) {
46
                // scale width
47
                $new_width = round($width * ($max_size_for_picture / $height));
48
                 $this->image_wrapper->resize($new_width, $max_size_for_picture, 0);
49
            }
50
        }
51
    }
52
53
    public function crop($cropParameters)
54
    {
55
        $image_size = $this->get_image_size($this->image_wrapper->path);
56
        $src_width = $image_size['width'];
57
        $src_height = $image_size['height'];
58
        $cropParameters = explode(",", $cropParameters);
59
        $x = intval($cropParameters[0]);
60
        $y = intval($cropParameters[1]);
61
        $width = intval($cropParameters[2]);
62
        $height = intval($cropParameters[3]);
63
64
        $image = $this->image_wrapper->crop($x, $y, $width, $height, $src_width, $src_height);
65
        return $image;
66
    }
67
68
    public function send_image(
69
        $file = '',
70
        $compress = -1,
71
        $convert_file_to = null
72
    ) {
73
        return $this->image_wrapper->send_image(
74
            $file,
75
            $compress,
76
            $convert_file_to
77
        );
78
    }
79
80
    public function get_image_size()
81
    {
82
        return $this->image_wrapper->get_image_size();
83
    }
84
85
    public function get_image_info()
86
    {
87
        return $this->image_wrapper->get_image_info();
88
    }
89
90
    public function convert2bw()
91
    {
92
        $this->image_wrapper->convert2bw();
0 ignored issues
show
Bug introduced by
The method convert2bw does only exist in GDWrapper, but not in ImagickWrapper.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
93
    }
94
}
95
96
/**
97
 * Image wrapper class
98
 *
99
 * @package chamilo.include.image
100
 */
101
abstract class ImageWrapper
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

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

Loading history...
102
{
103
    public $debug = true;
104
    public $path;
105
    public $width;
106
    public $height;
107
    public $type;
108
    public $allowed_extensions = array('jpeg', 'jpg', 'png', 'gif');
109
    public $image_validated = false;
110
111
    public function __construct($path)
112
    {
113
        if (empty($path)) {
114
            return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
115
        }
116
        $this->path = $path;
117
        $this->set_image_wrapper(); //Creates image obj
118
    }
119
120
    abstract function set_image_wrapper();
121
    abstract function fill_image_info();
122
    abstract function get_image_size();
123
    abstract function resize($thumbw, $thumbh, $border, $specific_size = false);
124
    abstract function crop($x, $y, $width, $height, $src_width, $src_height);
125
    abstract function send_image($file = '', $compress = -1, $convert_file_to = null);
126
127
    public function get_image_info()
128
    {
129
        return array(
130
            'width' => $this->width,
131
            'height' => $this->height,
132
            'type' => $this->type,
133
        );
134
    }
135
}
136
137
/**
138
 * Imagick Chamilo wrapper
139
 *
140
 * @author jmontoya
141
 *
142
 * @package chamilo.include.image
143
 */
144
class ImagickWrapper extends ImageWrapper
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

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

Loading history...
145
{
146
    public $image;
147
    public $filter = Imagick::FILTER_LANCZOS;
148
149
    /**
150
     * ImagickWrapper constructor.
151
     * @param $path
152
     */
153
    public function __construct($path)
154
    {
155
          parent::__construct($path);
156
    }
157
158
    public function set_image_wrapper()
159
    {
160
        if ($this->debug) error_log('Image::set_image_wrapper loaded');
161
        try {
162
            if (file_exists($this->path)) {
163
                $this->image = new Imagick($this->path);
164
165
                if ($this->image) {
166
                    $this->fill_image_info(); //Fills height, width and type
167
                }
168
            } else {
169
                if ($this->debug) error_log('Image::image does not exist');
170
            }
171
        } catch (ImagickException $e) {
172
            if ($this->debug) error_log($e->getMessage());
173
        }
174
    }
175
176
    public function fill_image_info()
177
    {
178
        $image_info      = $this->image->identifyImage();
179
180
        $this->width     = $image_info['geometry']['width'];
181
        $this->height    = $image_info['geometry']['height'];
182
        $this->type      = strtolower($this->image->getImageFormat());
183
184
        if (in_array($this->type, $this->allowed_extensions)) {
185
            $this->image_validated = true;
186
            if ($this->debug) error_log('image_validated true');
187
        }
188
    }
189
190
    public function get_image_size()
191
    {
192
        $imagesize = array('width'=>0, 'height'=>0);
193
        if ($this->image_validated) {
194
            $imagesize = $this->image->getImageGeometry();
195
        }
196
        return $imagesize;
197
    }
198
199
    //@todo implement border logic case for Imagick
200
    public function resize($thumbw, $thumbh, $border, $specific_size = false)
201
    {
202
        if (!$this->image_validated) return false;
203
204 View Code Duplication
        if ($specific_size) {
205
            $width = $thumbw;
206
            $height = $thumbh;
207
        } else {
208
            $scale  = ($this->width > 0 && $this->height > 0) ? min($thumbw / $this->width, $thumbh / $this->height) : 0;
209
            $width  = (int) ($this->width * $scale);
210
            $height = (int) ($this->height * $scale);
211
        }
212
        $result = $this->image->resizeImage($width, $height, $this->filter, 1);
213
        $this->width  = $thumbw;
214
        $this->height = $thumbh;
215
    }
216
217
    /**
218
     * @author José Loguercio <[email protected]>
219
     * @param int $x coordinate of the cropped region top left corner
220
     * @param int $y coordinate of the cropped region top left corner
221
     * @param int $width the width of the crop
222
     * @param int $height the height of the crop
223
     * @param int $src_width the source width of the original image
224
     * @param int $src_height the source height of the original image
225
     */
226
    public function crop($x, $y, $width, $height, $src_width, $src_height)
227
    {
228
        if (!$this->image_validated) {
229
            return false;
230
        }
231
        $this->image->cropimage($width, $height, $x, $y);
232
        $this->width = $width;
233
        $this->height = $height;
234
    }
235
236
    public function send_image($file = '', $compress = -1, $convert_file_to = null)
237
    {
238
        if (!$this->image_validated) {
239
            return false;
240
        }
241
        $type = $this->type;
242
        if (!empty($convert_file_to) && in_array($convert_file_to, $this->allowed_extensions)) {
243
            $type = $convert_file_to;
244
        }
245
        switch ($type) {
246
            case 'jpeg':
247
            case 'jpg':
248
                if (!$file) {
249
                    header("Content-type: image/jpeg");
250
                }
251
                break;
252
            case 'png':
253
                if (!$file) {
254
                    header("Content-type: image/png");
255
                }
256
                break;
257
            case 'gif':
258
                if (!$file) {
259
                    header("Content-type: image/gif");
260
                }
261
                break;
262
        }
263
        $result = false;
264
        try {
265
            $result = $this->image->writeImage($file);
266
        } catch (ImagickException $e) {
267
            if ($this->debug) {
268
                error_log($e->getMessage());
269
            }
270
        }
271
272
        if (!$file) {
273
            echo $this->image;
274
            $this->image->clear();
275
            $this->image->destroy();
276
        } else {
277
            $this->image->clear();
278
            $this->image->destroy();
279
            return $result;
280
        }
281
    }
282
}
283
284
/**
285
 * php-gd wrapper
286
 * @package chamilo.include.image
287
 */
288
class GDWrapper extends ImageWrapper
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

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

Loading history...
289
{
290
    public $bg;
291
    public function __construct($path)
292
    {
293
        parent::__construct($path);
294
    }
295
296
    public function set_image_wrapper()
297
    {
298
        $handler = null;
299
        $this->fill_image_info();
300
301
        switch ($this->type) {
302
            case 0:
303
                $handler = false;
304
                break;
305
            case 1:
306
                $handler = @imagecreatefromgif($this->path);
307
                $this->type = 'gif';
308
                break;
309
            case 2:
310
                $handler = @imagecreatefromjpeg($this->path);
311
                $this->type = 'jpg';
312
                break;
313
            case 3:
314
                $handler = @imagecreatefrompng($this->path);
315
                $this->type = 'png';
316
                break;
317
        }
318
        if ($handler) {
319
            $this->image_validated = true;
320
            $this->bg = $handler;
321
            @imagealphablending($this->bg, false);
322
            @imagesavealpha($this->bg, true);
323
        }
324
    }
325
326
    public function get_image_size()
327
    {
328
        $return_array = array('width'=>0, 'height'=>0);
329
        if ($this->image_validated) {
330
            $return_array = array('width'=>$this->width, 'height'=>$this->height);
331
        }
332
        return $return_array;
333
    }
334
335
    public function fill_image_info()
336
    {
337
        if (file_exists($this->path)) {
338
            $image_info = getimagesize($this->path);
339
            $this->width = $image_info[0];
340
            $this->height = $image_info[1];
341
            $this->type = $image_info[2];
342
        } else {
343
            $this->width = 0;
344
            $this->height = 0;
345
            $this->type = 0;
346
        }
347
    }
348
349
    public function resize($thumbw, $thumbh, $border, $specific_size = false)
350
    {
351
        if (!$this->image_validated) {
352
            return false;
353
        }
354
        if ($border == 1) {
355
            if ($specific_size) {
356
                $width = $thumbw;
357
                $height = $thumbh;
358
            } else {
359
                $scale = min($thumbw / $this->width, $thumbh / $this->height);
360
                $width = (int) ($this->width * $scale);
361
                $height = (int) ($this->height * $scale);
362
            }
363
            $deltaw = (int) (($thumbw - $width) / 2);
364
            $deltah = (int) (($thumbh - $height) / 2);
365
            $dst_img = @ImageCreateTrueColor($thumbw, $thumbh);
366
            @imagealphablending($dst_img, false);
367
            @imagesavealpha($dst_img, true);
368
369
            if (!empty($this->color)) {
370
                @imagefill($dst_img, 0, 0, $this->color);
371
            }
372
            $this->width = $thumbw;
373
            $this->height = $thumbh;
374
        } elseif ($border == 0) {
375 View Code Duplication
            if ($specific_size) {
376
                $width = $thumbw;
377
                $height = $thumbh;
378
            } else {
379
                $scale = ($this->width > 0 && $this->height > 0) ? min($thumbw / $this->width, $thumbh / $this->height) : 0;
380
                $width  = (int) ($this->width * $scale);
381
                $height = (int) ($this->height * $scale);
382
            }
383
            $deltaw = 0;
384
            $deltah = 0;
385
            $dst_img = @ImageCreateTrueColor($width, $height);
386
            @imagealphablending($dst_img, false);
387
            @imagesavealpha($dst_img, true);
388
            $this->width = $width;
389
            $this->height = $height;
390
        }
391
        $src_img = $this->bg;
392
        @ImageCopyResampled(
393
            $dst_img,
394
            $src_img,
395
            $deltaw,
396
            $deltah,
397
            0,
398
            0,
399
            $width,
400
            $height,
401
            ImageSX($src_img),
402
            ImageSY($src_img)
403
        );
404
        $this->bg = $dst_img;
405
        @imagedestroy($src_img);
406
    }
407
408
    /**
409
     * @author José Loguercio <[email protected]>
410
     * @param int $x coordinate of the cropped region top left corner
411
     * @param int $y coordinate of the cropped region top left corner
412
     * @param int $width the width of the crop
413
     * @param int $height the height of the crop
414
     * @param int $src_width the source width of the original image
415
     * @param int $src_height the source height of the original image
416
     */
417
    public function crop($x, $y, $width, $height, $src_width, $src_height)
418
    {
419
        if (!$this->image_validated) {
420
            return false;
421
        }
422
        $this->width = $width;
423
        $this->height = $height;
424
        $src = null;
425
        $dest = @imagecreatetruecolor($width, $height);
426
        $type = $this->type;
427
        switch ($type) {
428
            case 'jpeg':
429 View Code Duplication
            case 'jpg':
430
                $src = @imagecreatefromjpeg($this->path);
431
                @imagecopy($dest, $src, 0, 0, $x, $y, $src_width, $src_height);
432
                @imagejpeg($dest, $this->path);
433
                break;
434 View Code Duplication
            case 'png':
435
                $src = @imagecreatefrompng($this->path);
436
                @imagecopy($dest, $src, 0, 0, $x, $y, $src_width, $src_height);
437
                @imagepng($dest, $this->path);
438
                break;
439 View Code Duplication
            case 'gif':
440
                $src = @imagecreatefromgif($this->path);
441
                @imagecopy($dest, $src, 0, 0, $x, $y, $src_width, $src_height);
442
                @imagegif($dest, $this->path);
443
                break;
444
            default:
445
                return 0;
446
        }
447
        @imagedestroy($dest);
448
        @imagedestroy($src);
449
    }
450
451
    public function send_image($file = '', $compress = -1, $convert_file_to = null)
452
    {
453
        if (!$this->image_validated) {
454
            return false;
455
        }
456
        $compress = (int) $compress;
457
        $type = $this->type;
458
        if (!empty($convert_file_to) && in_array($convert_file_to, $this->allowed_extensions)) {
459
            $type = $convert_file_to;
460
        }
461
        switch ($type) {
462
            case 'jpeg':
463
            case 'jpg':
464
                if (!$file) {
465
                    header("Content-type: image/jpeg");
466
                }
467
                if ($compress == -1) {
468
                    $compress = 100;
469
                }
470
471
                return imagejpeg($this->bg, $file, $compress);
472
                break;
473 View Code Duplication
            case 'png':
474
                if (!$file) {
475
                    header("Content-type: image/png");
476
                }
477
                if ($compress != -1) {
478
                    @imagetruecolortopalette($this->bg, true, $compress);
479
                }
480
481
                return imagepng($this->bg, $file, $compress);
482
                break;
483 View Code Duplication
            case 'gif':
484
                if (!$file) {
485
                    header("Content-type: image/gif");
486
                }
487
                if ($compress != -1) {
488
                    @imagetruecolortopalette($this->bg, true, $compress);
489
                }
490
491
                return imagegif($this->bg, $file, $compress);
492
                break;
493
            default:
494
                return 0;
495
        }
496
        // TODO: Occupied memory is not released, because the following fragment of code is actually dead.
497
        @imagedestroy($this->bg);
498
    }
499
500
    /**
501
     * Convert image to black & white
502
     */
503
    function convert2bw()
504
    {
505
        if (!$this->image_validated) {
506
            return false;
507
        }
508
509
        $dest_img = imagecreatetruecolor(imagesx($this->bg), imagesy($this->bg));
510
        /* copy ignore the transparent color
511
         * so that we can use black (0,0,0) as transparent, which is what
512
         * the image is filled with when created.
513
         */
514
        $transparent = imagecolorallocate($dest_img, 0, 0, 0);
515
        imagealphablending($dest_img, false);
516
        imagesavealpha($dest_img, true);
517
        imagecolortransparent($dest_img, $transparent);
518
        imagecopy($dest_img, $this->bg, 0, 0, 0, 0, imagesx($this->bg), imagesx($this->bg));
519
        imagefilter($dest_img, IMG_FILTER_GRAYSCALE);
520
        $this->bg = $dest_img;
521
522
        return true;
523
    }
524
}
525