Picture   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 337
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 43
eloc 104
c 5
b 0
f 0
dl 0
loc 337
rs 8.96

22 Methods

Rating   Name   Duplication   Size   Complexity  
A getGererateMethod() 0 6 2
A getHeight() 0 3 1
A setImage() 0 4 1
A addFont() 0 9 2
A create() 0 8 1
A getCreateMethod() 0 6 2
A write() 0 16 5
A __construct() 0 6 1
A downloadPicture() 0 4 1
A getFont() 0 7 2
A addRectangle() 0 10 3
A getStream() 0 6 1
A getMimeType() 0 6 2
A getColor() 0 7 2
A addColor() 0 14 2
A savePicture() 0 7 1
A copyResized() 0 18 5
A showPicture() 0 8 1
A getImage() 0 3 1
A getWidth() 0 3 1
A __destruct() 0 3 1
A scale() 0 18 5

How to fix   Complexity   

Complex Class

Complex classes like Picture 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 Picture, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace VideoGamesRecords\CoreBundle\File;
6
7
use Exception;
8
use GdImage;
9
use VideoGamesRecords\CoreBundle\Contracts\PictureInterface;
10
11
class Picture implements PictureInterface
12
{
13
    protected $image = null;
14
15
    protected array $fonts = [];
16
    protected array $colors = [];
17
18
    protected ?int $activeColor = null;
19
    protected ?string $activeFont = null;
20
21
22
    /**
23
     * Picture constructor.
24
     * @param      $width
25
     * @param      $height
26
     */
27
    public function __construct($width, $height)
28
    {
29
        $width = (int) $width;
30
        $height = (int) $height;
31
32
        $this->image = imagecreatetruecolor($width, $height);
33
    }
34
35
    /**
36
     * @param GdImage $image
37
     * @return Picture
38
     */
39
    public static function create(GdImage $image): Picture
40
    {
41
        $oSelf = new self(imagesx($image), imagesy($image));
42
        $oSrc = new self(imagesx($image), imagesy($image));
43
        $oSrc->setImage($image);
44
        $oSelf->copyResized($oSrc, 0, 0);
45
        unset($oSrc);
46
        return $oSelf;
47
    }
48
49
    /**
50
     *
51
     */
52
    public function __destruct()
53
    {
54
        imagedestroy($this->image);
55
    }
56
57
    /**
58
     * @param $image
59
     * @return $this
60
     */
61
    public function setImage($image): Picture
62
    {
63
        $this->image = $image;
64
        return $this;
65
    }
66
67
    /**
68
     * @return int
69
     */
70
    public function getWidth(): int
71
    {
72
        return imagesx($this->image);
73
    }
74
75
    /**
76
     * @return int
77
     */
78
    public function getHeight(): int
79
    {
80
        return imagesy($this->image);
81
    }
82
83
    /**
84
     * @return GdImage|null
85
     */
86
    public function getImage(): ?GdImage
87
    {
88
        return $this->image;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->image could return the type resource which is incompatible with the type-hinted return GdImage|null. Consider adding an additional type-check to rule them out.
Loading history...
89
    }
90
91
    /**
92
     * @param $name
93
     * @return mixed
94
     * @throws Exception
95
     */
96
    public function getColor($name): mixed
97
    {
98
        if (!isset($this->colors[$name])) {
99
            throw new Exception('Unknown color ' . $name . '.');
100
        }
101
        $this->activeColor = $this->colors[$name];
102
        return $this->colors[$name];
103
    }
104
105
    /**
106
     * @param $name
107
     * @return mixed
108
     * @throws Exception
109
     */
110
    public function getFont($name): mixed
111
    {
112
        if (!isset($this->fonts[$name])) {
113
            throw new Exception('Unknown font ' . $name . '.');
114
        }
115
        $this->activeFont = $this->fonts[$name];
116
        return $this->fonts[$name];
117
    }
118
119
    /**
120
     * @param $name
121
     * @param $filePath
122
     * @return Picture
123
     * @throws Exception
124
     */
125
    public function addFont($name, $filePath): Picture
126
    {
127
        $fontPath = realpath($filePath);
128
        if ($fontPath === false) {
129
            throw new Exception('Unable to load font file. The file does not exists.');
130
        }
131
        $this->fonts[$name] = $fontPath;
132
        $this->activeFont = $fontPath;
133
        return $this;
134
    }
135
136
    /**
137
     * @param      $name
138
     * @param      $red
139
     * @param      $green
140
     * @param      $blue
141
     * @param      $alpha
142
     * @return Picture
143
     */
144
    public function addColor($name, $red, $green, $blue, $alpha = null): Picture
145
    {
146
        $red %= 256;
147
        $green %= 256;
148
        $blue %= 256;
149
        if ($alpha !== null) {
150
            $alpha %= 128;
151
            $color = imagecolorallocatealpha($this->image, $red, $green, $blue, $alpha);
152
        } else {
153
            $color = imagecolorallocate($this->image, $red, $green, $blue);
154
        }
155
        $this->colors[$name] = $color;
156
        $this->activeColor = $color;
157
        return $this;
158
    }
159
160
    /**
161
     * @param Picture $pic
162
     * @param int             $dstX
163
     * @param int             $dstY
164
     * @param int             $srcX
165
     * @param int             $srcY
166
     * @param int|null        $dstW
167
     * @param int|null        $dstH
168
     * @param int|null        $srcW
169
     * @param int|null        $srcH
170
     * @return Picture
171
     */
172
    public function copyResized(
173
        Picture $pic,
174
        int $dstX,
175
        int $dstY,
176
        int $srcX = 0,
177
        int $srcY = 0,
178
        int $dstW = null,
179
        int $dstH = null,
180
        int $srcW = null,
181
        int $srcH = null
182
    ): Picture {
183
        $dstW = is_null($dstW) ? $pic->getWidth() : $dstW;
184
        $dstH = is_null($dstH) ? $pic->getHeight() : $dstH;
185
        $srcW = is_null($srcW) ? $pic->getWidth() : $srcW;
186
        $srcH = is_null($srcH) ? $pic->getHeight() : $srcH;
187
188
        imagecopyresized($this->image, $pic->getImage(), $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
189
        return $this;
190
    }
191
192
    public function scale(int $width, int $height): void
193
    {
194
        $dstRatio = $width / $height;
195
        $srcW = $this->getWidth();
196
        $srcH = $this->getHeight();
197
        $srcRatio = $srcW / $srcH;
198
199
        // Is picture size < dest size do nothing
200
        if (($srcW <= $width) && ($srcH <= $height)) {
201
            return;
202
        }
203
204
        if ($srcRatio === $dstRatio) {
205
            $this->image = imagescale($this->image, $width, $height);
206
        } elseif ($srcRatio < $dstRatio) {
207
            $this->image = imagescale($this->image, (int) ($srcW * ($height / $srcH)), $height);
208
        } else {
209
            $this->image = imagescale($this->image, $width, (int) ($srcH * ($width / $srcW)));
210
        }
211
    }
212
213
    /**
214
     * @param      $xA
215
     * @param      $yA
216
     * @param      $xB
217
     * @param      $yB
218
     * @param null $color
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $color is correct as it would always require null to be passed?
Loading history...
219
     * @return Picture
220
     * @throws Exception
221
     */
222
    public function addRectangle($xA, $yA, $xB, $yB, $color = null): Picture
223
    {
224
        if ($color === null) {
0 ignored issues
show
introduced by
The condition $color === null is always true.
Loading history...
225
            $color = $this->activeColor;
226
            if ($color === null) {
227
                throw new Exception('No active color defined.');
228
            }
229
        }
230
        imagefilledrectangle($this->image, $xA, $yA, $xB, $yB, $color);
231
        return $this;
232
    }
233
234
    /**
235
     * @param      $message
236
     * @param      $size
237
     * @param      $x
238
     * @param      $y
239
     * @param int  $angle
240
     * @param null $color
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $color is correct as it would always require null to be passed?
Loading history...
241
     * @param null $font
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $font is correct as it would always require null to be passed?
Loading history...
242
     * @return Picture
243
     * @throws Exception
244
     */
245
    public function write($message, $size, $x, $y, int $angle = 0, $color = null, $font = null): Picture
246
    {
247
        if ($color === null) {
0 ignored issues
show
introduced by
The condition $color === null is always true.
Loading history...
248
            $color = $this->activeColor;
249
            if ($color === null) {
250
                throw new Exception('No active color defined.');
251
            }
252
        }
253
        if ($font === null) {
0 ignored issues
show
introduced by
The condition $font === null is always true.
Loading history...
254
            $font = $this->activeFont;
255
            if ($font === null) {
256
                throw new Exception('No active font defined.');
257
            }
258
        }
259
        imagettftext($this->image, $size, $angle, $x, $y, $color, $font, (string) $message);
260
        return $this;
261
    }
262
263
264
    /**
265
     * @param        $type
266
     * @param string $filename
267
     * @throws Exception
268
     */
269
    public function downloadPicture($type, string $filename): void
270
    {
271
        header('Content-Disposition: "attachement"; filename="' . $filename . '"');
272
        $this->showPicture($type);
273
    }
274
275
    /**
276
     * @param $type
277
     * @throws Exception
278
     */
279
    public function showPicture($type)
280
    {
281
        $method = self::getGererateMethod($type);
282
        $contentType = self::getMimeType($type);
283
284
        header('Content-Type: ' . $contentType);
285
        $method($this->image);
286
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
287
    }
288
289
290
    public function getStream($type): bool|string
291
    {
292
        $method = $this->getGererateMethod($type);
293
        ob_start();
294
        $method($this->image);
295
        return ob_get_clean();
296
    }
297
298
    /**
299
     * @param $filename
300
     * @return $this
301
     * @throws Exception
302
     */
303
    public function savePicture($filename): static
304
    {
305
        $sExtension = pathinfo($filename, PATHINFO_EXTENSION);
306
        $method = $this->getGererateMethod($sExtension);
307
308
        $method($this->image, $filename);
309
        return $this;
310
    }
311
312
    /**
313
     * @param $type
314
     * @return string
315
     * @throws Exception
316
     */
317
    protected static function getGererateMethod($type): string
318
    {
319
        if (!array_key_exists($type, self::EXTENSIONS)) {
320
            throw new Exception('Unknown picture type.');
321
        }
322
        return self::EXTENSIONS[$type]['generate'];
323
    }
324
325
    /**
326
     * @param $type
327
     * @return string
328
     * @throws Exception
329
     */
330
    public static function getCreateMethod($type): string
331
    {
332
        if (!array_key_exists($type, self::EXTENSIONS)) {
333
            throw new Exception('Unknown picture type.');
334
        }
335
        return self::EXTENSIONS[$type]['create'];
336
    }
337
338
    /**
339
     * @param $extension
340
     * @return string
341
     */
342
    public static function getMimeType($extension): string
343
    {
344
        if (!isset(self::MIME_TYPES[$extension])) {
345
            return 'application/octet-stream';
346
        }
347
        return self::MIME_TYPES[$extension];
348
    }
349
}
350