Passed
Pull Request — develop (#93)
by BENARD
05:59
created

Picture::downloadPicture()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 2
1
<?php
2
3
namespace VideoGamesRecords\CoreBundle\File;
4
5
use Exception;
6
use GdImage;
7
use VideoGamesRecords\CoreBundle\Contracts\PictureInterface;
8
9
class Picture implements PictureInterface
10
{
11
    protected $image = null;
12
13
    protected array $fonts = [];
14
    protected array $colors = [];
15
16
    protected ?int $activeColor = null;
17
    protected ?string $activeFont = null;
18
19
20
    /**
21
     * Picture constructor.
22
     * @param      $width
23
     * @param      $height
24
     */
25
    public function __construct($width, $height)
26
    {
27
        $width = (int) $width;
28
        $height = (int) $height;
29
30
        $this->image = imagecreatetruecolor($width, $height);
31
    }
32
33
    /**
34
     * @param GdImage $image
35
     * @return Picture
36
     */
37
    public static function create(GdImage $image): Picture
38
    {
39
        $oSelf = new self(imagesx($image), imagesy($image));
40
        $oSrc = new self(imagesx($image), imagesy($image));
41
        $oSrc->setImage($image);
42
        $oSelf->copyResized($oSrc, 0, 0);
43
        unset($oSrc);
44
        return $oSelf;
45
    }
46
47
    /**
48
     *
49
     */
50
    public function __destruct()
51
    {
52
        imagedestroy($this->image);
53
    }
54
55
    /**
56
     * @param $image
57
     * @return $this
58
     */
59
    public function setImage($image): Picture
60
    {
61
        $this->image = $image;
62
        return $this;
63
    }
64
65
    /**
66
     * @return int
67
     */
68
    public function getWidth():int
69
    {
70
        return imagesx($this->image);
71
    }
72
73
    /**
74
     * @return int
75
     */
76
    public function getHeight(): int
77
    {
78
        return imagesy($this->image);
79
    }
80
81
    /**
82
     * @return GdImage|null
83
     */
84
    public function getImage(): ?GdImage
85
    {
86
        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...
87
    }
88
89
    /**
90
     * @param $name
91
     * @return mixed
92
     * @throws Exception
93
     */
94
    public function getColor($name): mixed
95
    {
96
        if (!isset($this->colors[$name])) {
97
            throw new Exception('Unknown color ' . $name . '.');
98
        }
99
        $this->activeColor = $this->colors[$name];
100
        return $this->colors[$name];
101
    }
102
103
    /**
104
     * @param $name
105
     * @return mixed
106
     * @throws Exception
107
     */
108
    public function getFont($name): mixed
109
    {
110
        if (!isset($this->fonts[$name])) {
111
            throw new Exception('Unknown font ' . $name . '.');
112
        }
113
        $this->activeFont = $this->fonts[$name];
114
        return $this->fonts[$name];
115
    }
116
117
    /**
118
     * @param $name
119
     * @param $filePath
120
     * @return Picture
121
     * @throws Exception
122
     */
123
    public function addFont($name, $filePath): Picture
124
    {
125
        $fontPath = realpath($filePath);
126
        if ($fontPath === false) {
127
            throw new Exception('Unable to load font file. The file does not exists.');
128
        }
129
        $this->fonts[$name] = $fontPath;
130
        $this->activeFont = $fontPath;
131
        return $this;
132
    }
133
134
    /**
135
     * @param      $name
136
     * @param      $red
137
     * @param      $green
138
     * @param      $blue
139
     * @param      $alpha
140
     * @return Picture
141
     */
142
    public function addColor($name, $red, $green, $blue, $alpha = null): Picture
143
    {
144
        $red %= 256;
145
        $green %= 256;
146
        $blue %= 256;
147
        if ($alpha !== null) {
148
            $alpha %= 128;
149
            $color = imagecolorallocatealpha($this->image, $red, $green, $blue, $alpha);
150
        } else {
151
            $color = imagecolorallocate($this->image, $red, $green, $blue);
152
        }
153
        $this->colors[$name] = $color;
154
        $this->activeColor = $color;
155
        return $this;
156
    }
157
158
    /**
159
     * @param Picture $pic
160
     * @param int             $dstX
161
     * @param int             $dstY
162
     * @param int             $srcX
163
     * @param int             $srcY
164
     * @param int|null        $dstW
165
     * @param int|null        $dstH
166
     * @param int|null        $srcW
167
     * @param int|null        $srcH
168
     * @return Picture
169
     */
170
    public function copyResized(
171
        Picture $pic,
172
        int $dstX,
173
        int $dstY,
174
        int $srcX = 0,
175
        int $srcY = 0,
176
        int $dstW = null,
177
        int $dstH = null,
178
        int $srcW = null,
179
        int $srcH = null
180
    ): Picture {
181
        $dstW = is_null($dstW) ? $pic->getWidth() : $dstW;
182
        $dstH = is_null($dstH) ? $pic->getHeight() : $dstH;
183
        $srcW = is_null($srcW) ? $pic->getWidth() : $srcW;
184
        $srcH = is_null($srcH) ? $pic->getHeight() : $srcH;
185
186
        imagecopyresized($this->image, $pic->getImage(), $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
187
        return $this;
188
    }
189
190
    public function scale(int $width, int $height): void
191
    {
192
        $dstRatio = $width / $height;
193
        $srcW = $this->getWidth();
194
        $srcH = $this->getHeight();
195
        $srcRatio = $srcW / $srcH;
196
197
        // Is picture size < dest size do nothing
198
        if (($srcW <= $width) && ($srcH <= $height)) {
199
            return;
200
        }
201
202
        if ($srcRatio === $dstRatio) {
203
            $this->image = imagescale($this->image, $width, $height);
204
        } elseif ($srcRatio < $dstRatio) {
205
            $this->image = imagescale($this->image, $srcW * ($height / $srcH), $height);
206
        } else {
207
            $this->image = imagescale($this->image, $width, $srcH * ($width / $srcW),);
208
        }
209
    }
210
211
    /**
212
     * @param      $xA
213
     * @param      $yA
214
     * @param      $xB
215
     * @param      $yB
216
     * @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...
217
     * @return Picture
218
     * @throws Exception
219
     */
220
    public function addRectangle($xA, $yA, $xB, $yB, $color = null): Picture
221
    {
222
        if ($color === null) {
0 ignored issues
show
introduced by
The condition $color === null is always true.
Loading history...
223
            $color = $this->activeColor;
224
            if ($color === null) {
225
                throw new Exception('No active color defined.');
226
            }
227
        }
228
        imagefilledrectangle($this->image, $xA, $yA, $xB, $yB, $color);
229
        return $this;
230
    }
231
232
    /**
233
     * @param      $message
234
     * @param      $size
235
     * @param      $x
236
     * @param      $y
237
     * @param int  $angle
238
     * @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...
239
     * @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...
240
     * @return Picture
241
     * @throws Exception
242
     */
243
    public function write($message, $size, $x, $y, int $angle = 0, $color = null, $font = null): Picture
244
    {
245
        if ($color === null) {
0 ignored issues
show
introduced by
The condition $color === null is always true.
Loading history...
246
            $color = $this->activeColor;
247
            if ($color === null) {
248
                throw new Exception('No active color defined.');
249
            }
250
        }
251
        if ($font === null) {
0 ignored issues
show
introduced by
The condition $font === null is always true.
Loading history...
252
            $font = $this->activeFont;
253
            if ($font === null) {
254
                throw new Exception('No active font defined.');
255
            }
256
        }
257
        imagettftext($this->image, $size, $angle, $x, $y, $color, $font, $message);
258
        return $this;
259
    }
260
261
262
    /**
263
     * @param        $type
264
     * @param string $filename
265
     * @throws Exception
266
     */
267
    public function downloadPicture($type, string $filename): void
268
    {
269
        header('Content-Disposition: "attachement"; filename="' . $filename . '"');
270
        $this->showPicture($type);
271
    }
272
273
    /**
274
     * @param $type
275
     * @throws Exception
276
     */
277
    public function showPicture($type)
278
    {
279
        $method = self::getGererateMethod($type);
280
        $contentType = self::getMimeType($type);
281
282
        header('Content-Type: ' . $contentType);
283
        $method($this->image);
284
        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...
285
    }
286
287
288
    public function getStream($type): bool|string
289
    {
290
        $method = $this->getGererateMethod($type);
291
        ob_start();
292
        $method($this->image);
293
        return ob_get_clean();
294
    }
295
296
    /**
297
     * @param $filename
298
     * @return $this
299
     * @throws Exception
300
     */
301
    public function savePicture($filename): static
302
    {
303
        $sExtension = pathinfo($filename, PATHINFO_EXTENSION);
304
        $method = $this->getGererateMethod($sExtension);
305
306
        $method($this->image, $filename);
307
        return $this;
308
    }
309
310
    /**
311
     * @param $type
312
     * @return string
313
     * @throws Exception
314
     */
315
    protected static function getGererateMethod($type): string
316
    {
317
        if (!array_key_exists($type, self::EXTENSIONS)) {
318
            throw new Exception('Unknown picture type.');
319
        }
320
        return self::EXTENSIONS[$type]['generate'];
321
    }
322
323
    /**
324
     * @param $type
325
     * @return string
326
     * @throws Exception
327
     */
328
    public static function getCreateMethod($type): string
329
    {
330
        if (!array_key_exists($type, self::EXTENSIONS)) {
331
            throw new Exception('Unknown picture type.');
332
        }
333
        return self::EXTENSIONS[$type]['create'];
334
    }
335
336
    /**
337
     * @param $extension
338
     * @return string
339
     */
340
    public static function getMimeType($extension): string
341
    {
342
        if (!isset(self::MIME_TYPES[$extension])) {
343
            return 'application/octet-stream';
344
        }
345
        return self::MIME_TYPES[$extension];
346
    }
347
}
348