Passed
Branch next (340ec9)
by compolom
03:46
created

GD::resizeByBlurBackground()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 2
1
<?php declare(strict_types=1);
2
3
namespace Compolomus\Compomage;
4
5
use Compolomus\Compomage\Interfaces\ImageInterface;
6
use Exception;
7
use InvalidArgumentException;
8
use LogicException;
9
use RangeException;
10
use SplFileObject;
11
12
class GD extends AbstractImage// implements ImageInterface
13
{
14
    /**
15
     * GD constructor.
16
     * @param string $image
17
     * @throws Exception
18
     */
19 9
    public function __construct(string $image)
20
    {
21 9
        $this->init($image);
22 7
    }
23
24
    /**
25
     * @param int $width
26
     * @param int $height
27
     * @return ImageInterface
28
     * @throws Exception
29
     */
30
    public function resizeByTransparentBackground(int $width, int $height): ImageInterface
31
    {
32
        $temp = new SplFileObject(tempnam(sys_get_temp_dir(), 'image' . mt_rand()), 'w+');
33
        imagepng($this->newImage($width, $height), $temp->getRealPath(), 9, PNG_ALL_FILTERS);
34
35
        return $this->setBackground($width, $height, new Image($temp->getRealPath(), Image::GD));
36
    }
37
38
    /**
39
     * @param int $width
40
     * @param int $height
41
     * @return ImageInterface
42
     * @throws Exception
43
     */
44
    public function resizeByBlurBackground(int $width, int $height): ImageInterface
45
    {
46
        $background = new Image(base64_encode((string) $this), Image::GD);
47
        $background->blur()->resize($width, $height);
48
49
        return $this->setBackground($width, $height, $background);
50
    }
51
52
    /**
53
     * @param int $level
54
     * @return ImageInterface
55
     */
56 View Code Duplication
    public function brightness(int $level): ImageInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
57
    {
58
        if (!$this->compareRangeValue($level, 255))
59
        {
60
            throw new InvalidArgumentException('Wrong brightness level, range -255 - 255, ' . $level . ' given');
61
        }
62
        imagefilter($this->getImage(), IMG_FILTER_BRIGHTNESS, $level);
63
64
        return $this;
65
    }
66
67
    /**
68
     * @param int $level
69
     * @return ImageInterface
70
     */
71 View Code Duplication
    public function contrast(int $level): ImageInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
72
    {
73
        if (!$this->compareRangeValue($level, 100))
74
        {
75
            throw new InvalidArgumentException('Wrong contrast level, range -100 - 100, ' . $level . ' given');
76
        }
77
78
        imagefilter($this->getImage(), IMG_FILTER_CONTRAST, $level);
79
80
        return $this;
81
    }
82
83
    /**
84
     * @return ImageInterface
85
     */
86
    public function negate(): ImageInterface
87
    {
88
        imagefilter($this->getImage(), IMG_FILTER_NEGATE);
89
90
        return $this;
91
    }
92
93
    /**
94
     * @return ImageInterface
95
     */
96
    public function blur(): ImageInterface
97
    {
98
        for ($i = 0; $i < 30; $i++) {
99
            if ($i % 5 === 0) {
100
                imagefilter($this->getImage(), IMG_FILTER_SMOOTH, -7);
101
            }
102
            imagefilter($this->getImage(), IMG_FILTER_GAUSSIAN_BLUR);
103
        }
104
105
        return $this;
106
    }
107
108
    /**
109
     * @return ImageInterface
110
     */
111
    public function flip(): ImageInterface
112
    {
113
        imageflip($this->getImage(), IMG_FLIP_VERTICAL);
114
115
        return $this;
116
    }
117
118
    /**
119
     * @return ImageInterface
120
     */
121
    public function flop(): ImageInterface
122
    {
123
        imageflip($this->getImage(), IMG_FLIP_HORIZONTAL);
124
125
        return $this;
126
    }
127
128
    /**
129
     * @return ImageInterface
130
     */
131
    public function grayscale(): ImageInterface
132
    {
133
        imagefilter($this->getImage(), IMG_FILTER_GRAYSCALE);
134
135
        return $this;
136
    }
137
138
    /**
139
     * @param string $text
140
     * @param string $font
141
     * @param string $position
142
     * @return $this
143
     * @throws InvalidArgumentException
144
     * @throws Exception
145
     */
146 1
    public function copyright(string $text, string $font, string $position = 'SouthWest'): ImageInterface
147
    {
148 1
        if (!array_key_exists(strtoupper($position), self::POSITIONS)) {
149 1
            throw new InvalidArgumentException('Wrong position');
150
        }
151
152
        imagecopymerge(
153
            $this->getImage(),
154
            $image = $this->prepareImage($text, $font),
155
            (int)((($this->getWidth() - imagesx($image)) / 2) * self::POSITIONS[strtoupper($position)]['x']) + self::POSITIONS[strtoupper($position)]['padX'],
156
            (int)((($this->getHeight() - imagesy($image)) / 2) * self::POSITIONS[strtoupper($position)]['y']) + self::POSITIONS[strtoupper($position)]['padY'],
157
            0,
158
            0,
159
            $this->getWidth(),
160
            $this->getHeight(),
161
            80
162
        );
163
164
        return $this;
165
    }
166
167
    /**
168
     * @param string $text
169
     * @param string $font
170
     * @return resource
171
     * @throws InvalidArgumentException
172
     * @throws Exception
173
     */
174
    private function prepareImage(string $text, string $font)
175
    {
176
        if (!$coordinates = imagettfbbox($fontSize = 15, 0, $font, $text)) {
177
            throw new InvalidArgumentException('Does not support font');
178
        }
179
180
        $minX = min([$coordinates[0], $coordinates[2], $coordinates[4], $coordinates[6]]);
181
        $maxX = max([$coordinates[0], $coordinates[2], $coordinates[4], $coordinates[6]]);
182
        $minY = min([$coordinates[1], $coordinates[3], $coordinates[5], $coordinates[7]]);
183
        $maxY = max([$coordinates[1], $coordinates[3], $coordinates[5], $coordinates[7]]);
184
        $textX = (int)abs($minX) + 1;
185
        $textY = (int)abs($minY) + 1;
186
        $image = $this->newImage($maxX - $minX + 2, $maxY - $minY + 2);
187
        imagecolortransparent($image, $white = imagecolorallocate($image, 0, 0, 0));
188
        imagefilledrectangle($image, 0, 0, $this->getWidth(), 20, $white);
189
        imagettftext($image, $fontSize, 0, $textX, $textY, $white, $font, $text);
190
        imagettftext($image, $fontSize, 0, $textX + 1, $textY + 1, $blue = imagecolorallocate($image, 0, 128, 128),
191
            $font, $text);
192
        imagettftext($image, $fontSize, 0, $textX + 1, $textY + 1, $red = imagecolorallocate($image, 255, 0, 0), $font,
193
            $text);
194
        imagettftext($image, $fontSize, 0, $textX + 2, $textY + 2, $black = imagecolorallocate($image, 255, 255, 255),
195
            $font, $text);
196
        imagettftext($image, $fontSize, 0, $textX + 2, $textY + 2, $gray = imagecolorallocate($image, 128, 128, 128),
197
            $font, $text);
198
199
        return $image;
200
    }
201
202
    /**
203
     * @param int $width
204
     * @param int $height
205
     * @return resource
206
     */
207 3
    protected function newImage(int $width, int $height)
208
    {
209 3
        $newimage = imagecreatetruecolor($width, $height);
210 3
        $transparent = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
211 3
        imagefill($newimage, 0, 0, $transparent);
212 3
        imagealphablending($newimage, true);
213 3
        imagesavealpha($newimage, true);
214
215 3
        return $newimage;
216
    }
217
218
    /**
219
     * @param int $width
220
     * @param int $height
221
     * @return ImageInterface
222
     */
223 2
    public function resize(int $width, int $height): ImageInterface
224
    {
225 2
        $newimage = $this->newImage($width, $height);
226 2
        imagecopyresampled($newimage, $this->getImage(), 0, 0, 0, 0, $width, $height, $this->getWidth(),
227 2
            $this->getHeight());
228 2
        $this->setImage($newimage);
229 2
        $this->setSizes();
230
231 2
        return $this;
232
    }
233
234 8
    protected function setSizes(): void
235
    {
236 8
        $this->setWidth(imagesx($this->getImage()));
237 8
        $this->setHeight(imagesy($this->getImage()));
238 8
        $this->setOrientation();
239 8
    }
240
241
    /**
242
     * @param int $width
243
     * @param int $height
244
     * @param int $x
245
     * @param int $y
246
     * @return ImageInterface
247
     */
248
    public function crop(int $width, int $height, int $x, int $y): ImageInterface
249
    {
250
        $width -= $x;
251
        $height -= $y;
252
        $newimage = $this->newImage($width, $height);
253
        imagecopyresampled($newimage, $this->getImage(), 0, 0, $x, $y, $width, $height, $width, $height);
254
        $this->setImage($newimage);
255
        $this->setSizes();
256
257
        return $this;
258
    }
259
260
    /**
261
     * @param int $angle
262
     * @return ImageInterface
263
     */
264 1
    public function rotate(int $angle = 90): ImageInterface
265
    {
266 1
        $angle *= -1;
267 1
        $transparent = imagecolorallocatealpha($this->image, 0, 0, 0, 127);
268 1
        $rotate = imagerotate($this->getImage(), $angle, $transparent);
269 1
        imagealphablending($rotate, true);
270 1
        imagesavealpha($rotate, true);
271 1
        $this->setImage($rotate);
272 1
        $this->setSizes();
273
274 1
        return $this;
275
    }
276
277
    /**
278
     * @throws LogicException
279
     * @throws RangeException
280
     * @return string
281
     */
282 1
    public function __toString(): string
283
    {
284 1
        $temp = new SplFileObject(tempnam(sys_get_temp_dir(), 'image' . mt_rand()), 'w+');
285 1
        imagepng($this->getImage(), $temp->getRealPath(), 9, PNG_ALL_FILTERS);
286
287 1
        return trim(file_get_contents($temp->getRealPath()));
288
    }
289
290
    /**
291
     * @param string $filename
292
     * @param int $quality
293
     * @return bool
294
     */
295 1
    public function save(string $filename, $quality = 100): bool
296
    {
297 1
        return imagepng($this->getImage(), $filename . '.png', (int)($quality / 11), PNG_ALL_FILTERS);
298
    }
299
300
    /**
301
     * @param int $width
302
     * @param int $height
303
     * @param int $newWidth
304
     * @param int $newHeight
305
     * @return ImageInterface
306
     */
307 1
    protected function prepareThumbnail(
308
        int $width,
309
        int $height,
310
        int $newWidth = 0,
311
        int $newHeight = 0
312
    ): ImageInterface {
313 1
        imagecopyresampled(
314 1
            $newimage = $this->newImage($width, $height),
315 1
            $this->getImage(),
316 1
            0 - (int)(($newWidth - $width) / 2),
317 1
            0 - (int)(($newHeight - $height) / 2),
318 1
            0,
319 1
            0,
320 1
            $newWidth,
321 1
            $newHeight,
322 1
            $this->getWidth(),
323 1
            $this->getHeight()
324
        );
325 1
        $this->setImage($newimage);
326 1
        $this->setSizes();
327
328 1
        return $this;
329
    }
330
331
    /**
332
     * @param string $source
333
     * @return ImageInterface
334
     * @throws InvalidArgumentException
335
     * @throws Exception
336
     */
337 8
    protected function tmp(string $source): ImageInterface
338
    {
339 8
        if (@!is_resource($image = @imagecreatefromstring($source))) {
340 1
            throw new InvalidArgumentException('Image create failed');
341
        }
342 7
        $this->setImage($image);
343 7
        $this->setSizes();
344
        // save transparent
345 7
        imagesavealpha($this->getImage(), true);
346 7
        imagealphablending($this->getImage(), false);
347
348 7
        return $this;
349
    }
350
351
    /**
352
     * @param ImageInterface $watermark
353
     * @param int $x
354
     * @param int $y
355
     * @return ImageInterface
356
     */
357
    protected function prepareWatermark($watermark, int $x, int $y): ImageInterface
358
    {
359
        imagealphablending($this->getImage(), true);
360
        imagesavealpha($this->getImage(), true);
361
        imagecopyresampled(
362
            $this->getImage(),
363
            $watermark->getImage(),
364
            $x,
365
            $y,
366
            0,
367
            0,
368
            $width = (int)$watermark->getWidth(),
369
            $height = (int)$watermark->getHeight(),
370
            $width,
371
            $height
372
        );
373
374
        return $this;
375
    }
376
}
377